]> git.imager.perl.org - imager.git/blob - img16.c
- in some cases it's possible for giflib/libungif to return color
[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 "imager.h"
24 #include "imageri.h"
25
26 static int i_ppix_d16(i_img *im, int x, int y, const 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, const i_color *vals);
30 static int i_ppixf_d16(i_img *im, int x, int y, const 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, const 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_low(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, line_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   /* basic assumption: we can always allocate a buffer representing a
164      line from the image, otherwise we're going to have trouble
165      working with the image */
166   line_bytes = sizeof(i_fcolor) * x;
167   if (line_bytes / x != sizeof(i_fcolor)) {
168     i_push_error(0, "integer overflow calculating scanline allocation");
169     return NULL;
170   }
171
172   *im = IIM_base_16bit_direct;
173   i_tags_new(&im->tags);
174   im->xsize = x;
175   im->ysize = y;
176   im->channels = ch;
177   im->bytes = bytes;
178   im->ext_data = NULL;
179   im->idata = mymalloc(im->bytes);
180   if (im->idata) {
181     memset(im->idata, 0, im->bytes);
182   }
183   else {
184     i_tags_destroy(&im->tags);
185     im = NULL;
186   }
187   
188   return im;
189 }
190
191 /*
192 =item i_img_16_new(x, y, ch)
193
194 =category Image creation
195
196 Create a new 16-bit/sample image.
197
198 Returns the image on success, or NULL on failure.
199
200 =cut
201 */
202
203 i_img *i_img_16_new(int x, int y, int ch) {
204   i_img *im;
205   
206   i_clear_error();
207
208   im = mymalloc(sizeof(i_img));
209   if (im) {
210     if (!i_img_16_new_low(im, x, y, ch)) {
211       myfree(im);
212       im = NULL;
213     }
214   }
215   
216   mm_log((1, "(%p) <- i_img_16_new\n", im));
217   
218   return im;
219 }
220
221 /*
222 =item i_img_to_rgb16(im)
223
224 =category Image creation
225
226 Returns a 16-bit/sample version of the supplied image.
227
228 Returns the image on success, or NULL on failure.
229
230 =cut
231 */
232
233 i_img *
234 i_img_to_rgb16(i_img *im) {
235   i_img *targ;
236   i_fcolor *line;
237   int y;
238
239   targ = i_img_16_new(im->xsize, im->ysize, im->channels);
240   if (!targ)
241     return NULL;
242   line = mymalloc(sizeof(i_fcolor) * im->xsize);
243   for (y = 0; y < im->ysize; ++y) {
244     i_glinf(im, 0, im->xsize, y, line);
245     i_plinf(targ, 0, im->xsize, y, line);
246   }
247
248   myfree(line);
249
250   return targ;
251 }
252
253 static int i_ppix_d16(i_img *im, int x, int y, const i_color *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   if (I_ALL_CHANNELS_WRITABLE(im)) {
261     for (ch = 0; ch < im->channels; ++ch)
262       STORE8as16(im->idata, off+ch, val->channel[ch]);
263   }
264   else {
265     for (ch = 0; ch < im->channels; ++ch)
266       if (im->ch_mask & (1 << ch))
267         STORE8as16(im->idata, off+ch, val->channel[ch]);
268   }
269
270   return 0;
271 }
272
273 static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
274   int off, ch;
275
276   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
277     return -1;
278
279   off = (x + y * im->xsize) * im->channels;
280   for (ch = 0; ch < im->channels; ++ch)
281     val->channel[ch] = GET16as8(im->idata, off+ch);
282
283   return 0;
284 }
285
286 static int i_ppixf_d16(i_img *im, int x, int y, const i_fcolor *val) {
287   int off, ch;
288
289   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
290     return -1;
291
292   off = (x + y * im->xsize) * im->channels;
293   if (I_ALL_CHANNELS_WRITABLE(im)) {
294     for (ch = 0; ch < im->channels; ++ch)
295       STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
296   }
297   else {
298     for (ch = 0; ch < im->channels; ++ch)
299       if (im->ch_mask & (1 << ch))
300         STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
301   }
302
303   return 0;
304 }
305
306 static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
307   int off, ch;
308
309   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
310     return -1;
311
312   off = (x + y * im->xsize) * im->channels;
313   for (ch = 0; ch < im->channels; ++ch)
314     val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
315
316   return 0;
317 }
318
319 static int i_glin_d16(i_img *im, int l, int r, int y, i_color *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] = GET16as8(im->idata, off);
330         ++off;
331       }
332     }
333     return count;
334   }
335   else {
336     return 0;
337   }
338 }
339
340 static int i_plin_d16(i_img *im, int l, int r, int y, const i_color *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           STORE8as16(im->idata, off, 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             STORE8as16(im->idata, off, 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_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
373   int ch, count, i;
374   int off;
375   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
376     if (r > im->xsize)
377       r = im->xsize;
378     off = (l+y*im->xsize) * im->channels;
379     count = r - l;
380     for (i = 0; i < count; ++i) {
381       for (ch = 0; ch < im->channels; ++ch) {
382         vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
383         ++off;
384       }
385     }
386     return count;
387   }
388   else {
389     return 0;
390   }
391 }
392
393 static int i_plinf_d16(i_img *im, int l, int r, int y, const i_fcolor *vals) {
394   int ch, count, i;
395   int off;
396   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
397     if (r > im->xsize)
398       r = im->xsize;
399     off = (l+y*im->xsize) * im->channels;
400     count = r - l;
401     if (I_ALL_CHANNELS_WRITABLE(im)) {
402       for (i = 0; i < count; ++i) {
403         for (ch = 0; ch < im->channels; ++ch) {
404           STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
405           ++off;
406         }
407       }
408     }
409     else {
410       for (i = 0; i < count; ++i) {
411         for (ch = 0; ch < im->channels; ++ch) {
412           if (im->ch_mask & (1 << ch))
413             STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
414           ++off;
415         }
416       }
417     }
418     return count;
419   }
420   else {
421     return 0;
422   }
423 }
424
425 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
426                        int const *chans, int chan_count) {
427   int ch, count, i, w;
428   int off;
429
430   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
431     if (r > im->xsize)
432       r = im->xsize;
433     off = (l+y*im->xsize) * im->channels;
434     w = r - l;
435     count = 0;
436
437     if (chans) {
438       /* make sure we have good channel numbers */
439       for (ch = 0; ch < chan_count; ++ch) {
440         if (chans[ch] < 0 || chans[ch] >= im->channels) {
441           i_push_errorf(0, "No channel %d in this image", chans[ch]);
442           return 0;
443         }
444       }
445       for (i = 0; i < w; ++i) {
446         for (ch = 0; ch < chan_count; ++ch) {
447           *samps++ = GET16as8(im->idata, off+chans[ch]);
448           ++count;
449         }
450         off += im->channels;
451       }
452     }
453     else {
454       for (i = 0; i < w; ++i) {
455         for (ch = 0; ch < chan_count; ++ch) {
456           *samps++ = GET16as8(im->idata, off+ch);
457           ++count;
458         }
459         off += im->channels;
460       }
461     }
462
463     return count;
464   }
465   else {
466     return 0;
467   }
468 }
469
470 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
471                         int const *chans, int chan_count) {
472   int ch, count, i, w;
473   int off;
474
475   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
476     if (r > im->xsize)
477       r = im->xsize;
478     off = (l+y*im->xsize) * im->channels;
479     w = r - l;
480     count = 0;
481
482     if (chans) {
483       /* make sure we have good channel numbers */
484       for (ch = 0; ch < chan_count; ++ch) {
485         if (chans[ch] < 0 || chans[ch] >= im->channels) {
486           i_push_errorf(0, "No channel %d in this image", chans[ch]);
487           return 0;
488         }
489       }
490       for (i = 0; i < w; ++i) {
491         for (ch = 0; ch < chan_count; ++ch) {
492           *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
493           ++count;
494         }
495         off += im->channels;
496       }
497     }
498     else {
499       for (i = 0; i < w; ++i) {
500         for (ch = 0; ch < chan_count; ++ch) {
501           *samps++ = Sample16ToF(GET16(im->idata, off+ch));
502           ++count;
503         }
504         off += im->channels;
505       }
506     }
507
508     return count;
509   }
510   else {
511     return 0;
512   }
513 }
514
515 /*
516 =back
517
518 =head1 AUTHOR
519
520 Tony Cook <tony@develop-help.com>
521
522 =head1 SEE ALSO
523
524 Imager(3)
525
526 =cut
527 */