]> git.imager.perl.org - imager.git/blob - img16.c
- improved missing argument handling a little for the string() method
[imager.git] / img16.c
1 /*
2 =head1 NAME
3
4 img16.c - implements 16-bit images
5
6 =head1 SYNOPSIS
7
8   i_img *im = i_img_16_new(int x, int y, int channels);
9   # use like a normal image
10
11 =head1 DESCRIPTION
12
13 Implements 16-bit/sample images.
14
15 This basic implementation is required so that we have some larger 
16 sample image type to work with.
17
18 =over
19
20 =cut
21 */
22
23 #include "image.h"
24 #include "imagei.h"
25
26 static int i_ppix_d16(i_img *im, int x, int y, i_color *val);
27 static int i_gpix_d16(i_img *im, int x, int y, i_color *val);
28 static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals);
29 static int i_plin_d16(i_img *im, int l, int r, int y, i_color *vals);
30 static int i_ppixf_d16(i_img *im, int x, int y, i_fcolor *val);
31 static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val);
32 static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals);
33 static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals);
34 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
35                        int const *chans, int chan_count);
36 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
37                         int const *chans, int chan_count);
38
39 /*
40 =item IIM_base_16bit_direct
41
42 Base structure used to initialize a 16-bit/sample image.
43
44 Internal.
45
46 =cut
47 */
48 static i_img IIM_base_16bit_direct =
49 {
50   0, /* channels set */
51   0, 0, 0, /* xsize, ysize, bytes */
52   ~0U, /* ch_mask */
53   i_16_bits, /* bits */
54   i_direct_type, /* type */
55   0, /* virtual */
56   NULL, /* idata */
57   { 0, 0, NULL }, /* tags */
58   NULL, /* ext_data */
59
60   i_ppix_d16, /* i_f_ppix */
61   i_ppixf_d16, /* i_f_ppixf */
62   i_plin_d16, /* i_f_plin */
63   i_plinf_d16, /* i_f_plinf */
64   i_gpix_d16, /* i_f_gpix */
65   i_gpixf_d16, /* i_f_gpixf */
66   i_glin_d16, /* i_f_glin */
67   i_glinf_d16, /* i_f_glinf */
68   i_gsamp_d16, /* i_f_gsamp */
69   i_gsampf_d16, /* i_f_gsampf */
70
71   NULL, /* i_f_gpal */
72   NULL, /* i_f_ppal */
73   NULL, /* i_f_addcolor */
74   NULL, /* i_f_getcolor */
75   NULL, /* i_f_colorcount */
76   NULL, /* i_f_findcolor */
77
78   NULL, /* i_f_destroy */
79 };
80
81 /* it's possible some platforms won't have a 16-bit integer type,
82    so we check for one otherwise we work by bytes directly
83
84    We do assume 8-bit char
85
86    "Compaq C V6.4-009 on Compaq Tru64 UNIX V5.1A (Rev. 1885)" says it
87    supports C99, but doesn't supply stdint.h, which is required for
88    both hosted and freestanding implementations.  So guard against it.
89 */
90 #if __STDC_VERSION__ >= 199901L && !defined(OS_dec_osf)
91 /* C99 should define something useful */
92 #include <stdint.h>
93 #ifdef UINT16_MAX
94 typedef uint16_t i_sample16_t;
95 #define GOT16
96 #endif
97 #endif
98
99 /* check out unsigned short */
100 #ifndef GOT16
101 #include <limits.h>
102 #if USHRT_MAX == 65535
103 typedef unsigned short i_sample16_t;
104 #define GOT16
105 #endif
106 #endif
107
108 #ifdef GOT16
109
110 /* we have a real 16-bit unsigned integer */
111 #define STORE16(bytes, offset, word) \
112    (((i_sample16_t *)(bytes))[offset] = (word))
113 #define STORE8as16(bytes, offset, byte) \
114    (((i_sample16_t *)(bytes))[offset] = (byte) * 256)
115 #define GET16(bytes, offset) \
116      (((i_sample16_t *)(bytes))[offset])
117 #define GET16as8(bytes, offset) \
118      (((i_sample16_t *)(bytes))[offset] / 256)
119
120 #else
121
122 /* we have to do this the hard way */
123 #define STORE16(bytes, offset, word) \
124    ((((unsigned char *)(bytes))[(offset)*2] = (word) >> 8), \
125     (((unsigned char *)(bytes))[(offset)*2+1] = (word) & 0xFF))
126 #define STORE8as16(bytes, offset, byte) \
127    ((((unsigned char *)(bytes))[(offset)*2] = (byte)), \
128     (((unsigned char *)(bytes))[(offset)*2+1] = 0))
129    
130 #define GET16(bytes, offset) \
131    (((unsigned char *)(bytes))[(offset)*2] * 256 \
132     + ((unsigned char *)(bytes))[(offset)*2+1])
133 #define GET16as8(bytes, offset) \
134    (((unsigned char *)(bytes))[(offset)*2] << 8)
135
136 #endif
137
138 /*
139 =item i_img_16_new(int x, int y, int ch)
140
141 Creates a new 16-bit per sample image.
142
143 =cut
144 */
145 i_img *i_img_16_new_low(i_img *im, int x, int y, int ch) {
146   int bytes;
147   mm_log((1,"i_img_16_new(x %d, y %d, ch %d)\n", x, y, ch));
148
149   if (x < 1 || y < 1) {
150     i_push_error(0, "Image sizes must be positive");
151     return NULL;
152   }
153   if (ch < 1 || ch > MAXCHANNELS) {
154     i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
155     return NULL;
156   }
157   bytes =  x * y * ch * 2;
158   if (bytes / y / ch / 2 != x) {
159     i_push_errorf(0, "integer overflow calculating image allocation");
160     return NULL;
161   }
162   
163   *im = IIM_base_16bit_direct;
164   i_tags_new(&im->tags);
165   im->xsize = x;
166   im->ysize = y;
167   im->channels = ch;
168   im->bytes = bytes;
169   im->ext_data = NULL;
170   im->idata = mymalloc(im->bytes);
171   if (im->idata) {
172     memset(im->idata, 0, im->bytes);
173   }
174   else {
175     i_tags_destroy(&im->tags);
176     im = NULL;
177   }
178   
179   return im;
180 }
181
182 i_img *i_img_16_new(int x, int y, int ch) {
183   i_img *im;
184   
185   i_clear_error();
186
187   im = mymalloc(sizeof(i_img));
188   if (im) {
189     if (!i_img_16_new_low(im, x, y, ch)) {
190       myfree(im);
191       im = NULL;
192     }
193   }
194   
195   mm_log((1, "(%p) <- i_img_16_new\n", im));
196   
197   return im;
198 }
199
200 static int i_ppix_d16(i_img *im, int x, int y, i_color *val) {
201   int off, ch;
202
203   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
204     return -1;
205
206   off = (x + y * im->xsize) * im->channels;
207   if (I_ALL_CHANNELS_WRITABLE(im)) {
208     for (ch = 0; ch < im->channels; ++ch)
209       STORE8as16(im->idata, off+ch, val->channel[ch]);
210   }
211   else {
212     for (ch = 0; ch < im->channels; ++ch)
213       if (im->ch_mask & (1 << ch))
214         STORE8as16(im->idata, off+ch, val->channel[ch]);
215   }
216
217   return 0;
218 }
219
220 static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
221   int off, ch;
222
223   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
224     return -1;
225
226   off = (x + y * im->xsize) * im->channels;
227   for (ch = 0; ch < im->channels; ++ch)
228     val->channel[ch] = GET16as8(im->idata, off+ch);
229
230   return 0;
231 }
232
233 static int i_ppixf_d16(i_img *im, int x, int y, i_fcolor *val) {
234   int off, ch;
235
236   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
237     return -1;
238
239   off = (x + y * im->xsize) * im->channels;
240   if (I_ALL_CHANNELS_WRITABLE(im)) {
241     for (ch = 0; ch < im->channels; ++ch)
242       STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
243   }
244   else {
245     for (ch = 0; ch < im->channels; ++ch)
246       if (im->ch_mask & (1 << ch))
247         STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
248   }
249
250   return 0;
251 }
252
253 static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
254   int off, ch;
255
256   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
257     return -1;
258
259   off = (x + y * im->xsize) * im->channels;
260   for (ch = 0; ch < im->channels; ++ch)
261     val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
262
263   return 0;
264 }
265
266 static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals) {
267   int ch, count, i;
268   int off;
269   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
270     if (r > im->xsize)
271       r = im->xsize;
272     off = (l+y*im->xsize) * im->channels;
273     count = r - l;
274     for (i = 0; i < count; ++i) {
275       for (ch = 0; ch < im->channels; ++ch) {
276         vals[i].channel[ch] = GET16as8(im->idata, off);
277         ++off;
278       }
279     }
280     return count;
281   }
282   else {
283     return 0;
284   }
285 }
286
287 static int i_plin_d16(i_img *im, int l, int r, int y, i_color *vals) {
288   int ch, count, i;
289   int off;
290   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
291     if (r > im->xsize)
292       r = im->xsize;
293     off = (l+y*im->xsize) * im->channels;
294     count = r - l;
295     if (I_ALL_CHANNELS_WRITABLE(im)) {
296       for (i = 0; i < count; ++i) {
297         for (ch = 0; ch < im->channels; ++ch) {
298           STORE8as16(im->idata, off, vals[i].channel[ch]);
299           ++off;
300         }
301       }
302     }
303     else {
304       for (i = 0; i < count; ++i) {
305         for (ch = 0; ch < im->channels; ++ch) {
306           if (im->ch_mask & (1 << ch))
307             STORE8as16(im->idata, off, vals[i].channel[ch]);
308           ++off;
309         }
310       }
311     }
312     return count;
313   }
314   else {
315     return 0;
316   }
317 }
318
319 static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
320   int ch, count, i;
321   int off;
322   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
323     if (r > im->xsize)
324       r = im->xsize;
325     off = (l+y*im->xsize) * im->channels;
326     count = r - l;
327     for (i = 0; i < count; ++i) {
328       for (ch = 0; ch < im->channels; ++ch) {
329         vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
330         ++off;
331       }
332     }
333     return count;
334   }
335   else {
336     return 0;
337   }
338 }
339
340 static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
341   int ch, count, i;
342   int off;
343   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
344     if (r > im->xsize)
345       r = im->xsize;
346     off = (l+y*im->xsize) * im->channels;
347     count = r - l;
348     if (I_ALL_CHANNELS_WRITABLE(im)) {
349       for (i = 0; i < count; ++i) {
350         for (ch = 0; ch < im->channels; ++ch) {
351           STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
352           ++off;
353         }
354       }
355     }
356     else {
357       for (i = 0; i < count; ++i) {
358         for (ch = 0; ch < im->channels; ++ch) {
359           if (im->ch_mask & (1 << ch))
360             STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
361           ++off;
362         }
363       }
364     }
365     return count;
366   }
367   else {
368     return 0;
369   }
370 }
371
372 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
373                        int const *chans, int chan_count) {
374   int ch, count, i, w;
375   int off;
376
377   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
378     if (r > im->xsize)
379       r = im->xsize;
380     off = (l+y*im->xsize) * im->channels;
381     w = r - l;
382     count = 0;
383
384     if (chans) {
385       /* make sure we have good channel numbers */
386       for (ch = 0; ch < chan_count; ++ch) {
387         if (chans[ch] < 0 || chans[ch] >= im->channels) {
388           i_push_errorf(0, "No channel %d in this image", chans[ch]);
389           return 0;
390         }
391       }
392       for (i = 0; i < w; ++i) {
393         for (ch = 0; ch < chan_count; ++ch) {
394           *samps++ = GET16as8(im->idata, off+chans[ch]);
395           ++count;
396         }
397         off += im->channels;
398       }
399     }
400     else {
401       for (i = 0; i < w; ++i) {
402         for (ch = 0; ch < chan_count; ++ch) {
403           *samps++ = GET16as8(im->idata, off+ch);
404           ++count;
405         }
406         off += im->channels;
407       }
408     }
409
410     return count;
411   }
412   else {
413     return 0;
414   }
415 }
416
417 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
418                         int const *chans, int chan_count) {
419   int ch, count, i, w;
420   int off;
421
422   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
423     if (r > im->xsize)
424       r = im->xsize;
425     off = (l+y*im->xsize) * im->channels;
426     w = r - l;
427     count = 0;
428
429     if (chans) {
430       /* make sure we have good channel numbers */
431       for (ch = 0; ch < chan_count; ++ch) {
432         if (chans[ch] < 0 || chans[ch] >= im->channels) {
433           i_push_errorf(0, "No channel %d in this image", chans[ch]);
434           return 0;
435         }
436       }
437       for (i = 0; i < w; ++i) {
438         for (ch = 0; ch < chan_count; ++ch) {
439           *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
440           ++count;
441         }
442         off += im->channels;
443       }
444     }
445     else {
446       for (i = 0; i < w; ++i) {
447         for (ch = 0; ch < chan_count; ++ch) {
448           *samps++ = Sample16ToF(GET16(im->idata, off+ch));
449           ++count;
450         }
451         off += im->channels;
452       }
453     }
454
455     return count;
456   }
457   else {
458     return 0;
459   }
460 }
461
462 /*
463 =back
464
465 =head1 AUTHOR
466
467 Tony Cook <tony@develop-help.com>
468
469 =head1 SEE ALSO
470
471 Imager(3)
472
473 =cut
474 */