]> git.imager.perl.org - imager.git/blob - img16.c
added sample: gifscale.pl - scale an animated gif
[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/destruction
195 =synopsis i_img *img = i_img_16_new(width, height, channels);
196
197 Create a new 16-bit/sample image.
198
199 Returns the image on success, or NULL on failure.
200
201 =cut
202 */
203
204 i_img *i_img_16_new(int x, int y, int ch) {
205   i_img *im;
206   
207   i_clear_error();
208
209   im = mymalloc(sizeof(i_img));
210   if (im) {
211     if (!i_img_16_new_low(im, x, y, ch)) {
212       myfree(im);
213       im = NULL;
214     }
215   }
216   
217   mm_log((1, "(%p) <- i_img_16_new\n", im));
218   
219   return im;
220 }
221
222 /*
223 =item i_img_to_rgb16(im)
224
225 =category Image creation
226
227 Returns a 16-bit/sample version of the supplied image.
228
229 Returns the image on success, or NULL on failure.
230
231 =cut
232 */
233
234 i_img *
235 i_img_to_rgb16(i_img *im) {
236   i_img *targ;
237   i_fcolor *line;
238   int y;
239
240   targ = i_img_16_new(im->xsize, im->ysize, im->channels);
241   if (!targ)
242     return NULL;
243   line = mymalloc(sizeof(i_fcolor) * im->xsize);
244   for (y = 0; y < im->ysize; ++y) {
245     i_glinf(im, 0, im->xsize, y, line);
246     i_plinf(targ, 0, im->xsize, y, line);
247   }
248
249   myfree(line);
250
251   return targ;
252 }
253
254 static int i_ppix_d16(i_img *im, int x, int y, const i_color *val) {
255   int off, ch;
256
257   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
258     return -1;
259
260   off = (x + y * im->xsize) * im->channels;
261   if (I_ALL_CHANNELS_WRITABLE(im)) {
262     for (ch = 0; ch < im->channels; ++ch)
263       STORE8as16(im->idata, off+ch, val->channel[ch]);
264   }
265   else {
266     for (ch = 0; ch < im->channels; ++ch)
267       if (im->ch_mask & (1 << ch))
268         STORE8as16(im->idata, off+ch, val->channel[ch]);
269   }
270
271   return 0;
272 }
273
274 static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
275   int off, ch;
276
277   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
278     return -1;
279
280   off = (x + y * im->xsize) * im->channels;
281   for (ch = 0; ch < im->channels; ++ch)
282     val->channel[ch] = GET16as8(im->idata, off+ch);
283
284   return 0;
285 }
286
287 static int i_ppixf_d16(i_img *im, int x, int y, const i_fcolor *val) {
288   int off, ch;
289
290   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
291     return -1;
292
293   off = (x + y * im->xsize) * im->channels;
294   if (I_ALL_CHANNELS_WRITABLE(im)) {
295     for (ch = 0; ch < im->channels; ++ch)
296       STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
297   }
298   else {
299     for (ch = 0; ch < im->channels; ++ch)
300       if (im->ch_mask & (1 << ch))
301         STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
302   }
303
304   return 0;
305 }
306
307 static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
308   int off, ch;
309
310   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
311     return -1;
312
313   off = (x + y * im->xsize) * im->channels;
314   for (ch = 0; ch < im->channels; ++ch)
315     val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
316
317   return 0;
318 }
319
320 static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals) {
321   int ch, count, i;
322   int off;
323   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
324     if (r > im->xsize)
325       r = im->xsize;
326     off = (l+y*im->xsize) * im->channels;
327     count = r - l;
328     for (i = 0; i < count; ++i) {
329       for (ch = 0; ch < im->channels; ++ch) {
330         vals[i].channel[ch] = GET16as8(im->idata, off);
331         ++off;
332       }
333     }
334     return count;
335   }
336   else {
337     return 0;
338   }
339 }
340
341 static int i_plin_d16(i_img *im, int l, int r, int y, const i_color *vals) {
342   int ch, count, i;
343   int off;
344   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
345     if (r > im->xsize)
346       r = im->xsize;
347     off = (l+y*im->xsize) * im->channels;
348     count = r - l;
349     if (I_ALL_CHANNELS_WRITABLE(im)) {
350       for (i = 0; i < count; ++i) {
351         for (ch = 0; ch < im->channels; ++ch) {
352           STORE8as16(im->idata, off, vals[i].channel[ch]);
353           ++off;
354         }
355       }
356     }
357     else {
358       for (i = 0; i < count; ++i) {
359         for (ch = 0; ch < im->channels; ++ch) {
360           if (im->ch_mask & (1 << ch))
361             STORE8as16(im->idata, off, vals[i].channel[ch]);
362           ++off;
363         }
364       }
365     }
366     return count;
367   }
368   else {
369     return 0;
370   }
371 }
372
373 static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
374   int ch, count, i;
375   int off;
376   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
377     if (r > im->xsize)
378       r = im->xsize;
379     off = (l+y*im->xsize) * im->channels;
380     count = r - l;
381     for (i = 0; i < count; ++i) {
382       for (ch = 0; ch < im->channels; ++ch) {
383         vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
384         ++off;
385       }
386     }
387     return count;
388   }
389   else {
390     return 0;
391   }
392 }
393
394 static int i_plinf_d16(i_img *im, int l, int r, int y, const i_fcolor *vals) {
395   int ch, count, i;
396   int off;
397   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
398     if (r > im->xsize)
399       r = im->xsize;
400     off = (l+y*im->xsize) * im->channels;
401     count = r - l;
402     if (I_ALL_CHANNELS_WRITABLE(im)) {
403       for (i = 0; i < count; ++i) {
404         for (ch = 0; ch < im->channels; ++ch) {
405           STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
406           ++off;
407         }
408       }
409     }
410     else {
411       for (i = 0; i < count; ++i) {
412         for (ch = 0; ch < im->channels; ++ch) {
413           if (im->ch_mask & (1 << ch))
414             STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
415           ++off;
416         }
417       }
418     }
419     return count;
420   }
421   else {
422     return 0;
423   }
424 }
425
426 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
427                        int const *chans, int chan_count) {
428   int ch, count, i, w;
429   int off;
430
431   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
432     if (r > im->xsize)
433       r = im->xsize;
434     off = (l+y*im->xsize) * im->channels;
435     w = r - l;
436     count = 0;
437
438     if (chans) {
439       /* make sure we have good channel numbers */
440       for (ch = 0; ch < chan_count; ++ch) {
441         if (chans[ch] < 0 || chans[ch] >= im->channels) {
442           i_push_errorf(0, "No channel %d in this image", chans[ch]);
443           return 0;
444         }
445       }
446       for (i = 0; i < w; ++i) {
447         for (ch = 0; ch < chan_count; ++ch) {
448           *samps++ = GET16as8(im->idata, off+chans[ch]);
449           ++count;
450         }
451         off += im->channels;
452       }
453     }
454     else {
455       for (i = 0; i < w; ++i) {
456         for (ch = 0; ch < chan_count; ++ch) {
457           *samps++ = GET16as8(im->idata, off+ch);
458           ++count;
459         }
460         off += im->channels;
461       }
462     }
463
464     return count;
465   }
466   else {
467     return 0;
468   }
469 }
470
471 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
472                         int const *chans, int chan_count) {
473   int ch, count, i, w;
474   int off;
475
476   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
477     if (r > im->xsize)
478       r = im->xsize;
479     off = (l+y*im->xsize) * im->channels;
480     w = r - l;
481     count = 0;
482
483     if (chans) {
484       /* make sure we have good channel numbers */
485       for (ch = 0; ch < chan_count; ++ch) {
486         if (chans[ch] < 0 || chans[ch] >= im->channels) {
487           i_push_errorf(0, "No channel %d in this image", chans[ch]);
488           return 0;
489         }
490       }
491       for (i = 0; i < w; ++i) {
492         for (ch = 0; ch < chan_count; ++ch) {
493           *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
494           ++count;
495         }
496         off += im->channels;
497       }
498     }
499     else {
500       for (i = 0; i < w; ++i) {
501         for (ch = 0; ch < chan_count; ++ch) {
502           *samps++ = Sample16ToF(GET16(im->idata, off+ch));
503           ++count;
504         }
505         off += im->channels;
506       }
507     }
508
509     return count;
510   }
511   else {
512     return 0;
513   }
514 }
515
516 /*
517 =back
518
519 =head1 AUTHOR
520
521 Tony Cook <tony@develop-help.com>
522
523 =head1 SEE ALSO
524
525 Imager(3)
526
527 =cut
528 */