]> git.imager.perl.org - imager.git/blob - img8.c
[rt #69008] depend on a CPAN::Meta that depends on JSON::PP
[imager.git] / img8.c
1 #include "imager.h"
2 #include "imageri.h"
3
4 static int i_ppix_d(i_img *im, i_img_dim x, i_img_dim y, const i_color *val);
5 static int i_gpix_d(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
6 static i_img_dim i_glin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
7 static i_img_dim i_plin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals);
8 static int i_ppixf_d(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val);
9 static int i_gpixf_d(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val);
10 static i_img_dim i_glinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
11 static i_img_dim i_plinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals);
12 static i_img_dim i_gsamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, const int *chans, int chan_count);
13 static i_img_dim i_gsampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, const int *chans, int chan_count);
14
15 /*
16 =item IIM_base_8bit_direct (static)
17
18 A static i_img object used to initialize direct 8-bit per sample images.
19
20 =cut
21 */
22 static i_img IIM_base_8bit_direct =
23 {
24   0, /* channels set */
25   0, 0, 0, /* xsize, ysize, bytes */
26   ~0U, /* ch_mask */
27   i_8_bits, /* bits */
28   i_direct_type, /* type */
29   0, /* virtual */
30   NULL, /* idata */
31   { 0, 0, NULL }, /* tags */
32   NULL, /* ext_data */
33
34   i_ppix_d, /* i_f_ppix */
35   i_ppixf_d, /* i_f_ppixf */
36   i_plin_d, /* i_f_plin */
37   i_plinf_d, /* i_f_plinf */
38   i_gpix_d, /* i_f_gpix */
39   i_gpixf_d, /* i_f_gpixf */
40   i_glin_d, /* i_f_glin */
41   i_glinf_d, /* i_f_glinf */
42   i_gsamp_d, /* i_f_gsamp */
43   i_gsampf_d, /* i_f_gsampf */
44
45   NULL, /* i_f_gpal */
46   NULL, /* i_f_ppal */
47   NULL, /* i_f_addcolors */
48   NULL, /* i_f_getcolors */
49   NULL, /* i_f_colorcount */
50   NULL, /* i_f_maxcolors */
51   NULL, /* i_f_findcolor */
52   NULL, /* i_f_setcolors */
53
54   NULL, /* i_f_destroy */
55
56   i_gsamp_bits_fb,
57   NULL, /* i_f_psamp_bits */
58 };
59
60 /*static void set_8bit_direct(i_img *im) {
61   im->i_f_ppix = i_ppix_d;
62   im->i_f_ppixf = i_ppixf_d;
63   im->i_f_plin = i_plin_d;
64   im->i_f_plinf = i_plinf_d;
65   im->i_f_gpix = i_gpix_d;
66   im->i_f_gpixf = i_gpixf_d;
67   im->i_f_glin = i_glin_d;
68   im->i_f_glinf = i_glinf_d;
69   im->i_f_gpal = NULL;
70   im->i_f_ppal = NULL;
71   im->i_f_addcolor = NULL;
72   im->i_f_getcolor = NULL;
73   im->i_f_colorcount = NULL;
74   im->i_f_findcolor = NULL;
75   }*/
76
77 /*
78 =item IIM_new(x, y, ch)
79
80 =item i_img_8_new(x, y, ch)
81
82 =category Image creation/destruction
83
84 =synopsis i_img *img = i_img_8_new(width, height, channels);
85
86 Creates a new image object I<x> pixels wide, and I<y> pixels high with
87 I<ch> channels.
88
89 =cut
90 */
91
92
93 i_img *
94 IIM_new(i_img_dim x,i_img_dim y,int ch) {
95   i_img *im;
96
97   mm_log((1,"IIM_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
98           i_DFc(x), i_DFc(y), ch));
99
100   im=i_img_empty_ch(NULL,x,y,ch);
101   
102   mm_log((1,"(%p) <- IIM_new\n",im));
103   return im;
104 }
105
106
107 void
108 IIM_DESTROY(i_img *im) {
109   mm_log((1,"IIM_DESTROY(im* %p)\n",im));
110   i_img_destroy(im);
111   /*   myfree(cl); */
112 }
113
114 /* 
115 =item i_img_new()
116
117 Create new image reference - notice that this isn't an object yet and
118 this should be fixed asap.
119
120 =cut
121 */
122
123
124 i_img *
125 i_img_new() {
126   i_img *im;
127   
128   mm_log((1,"i_img_struct()\n"));
129
130   im = i_img_alloc();
131   
132   *im = IIM_base_8bit_direct;
133   im->xsize=0;
134   im->ysize=0;
135   im->channels=3;
136   im->ch_mask=MAXINT;
137   im->bytes=0;
138   im->idata=NULL;
139
140   i_img_init(im);
141   
142   mm_log((1,"(%p) <- i_img_struct\n",im));
143   return im;
144 }
145
146 /* 
147 =item i_img_empty(im, x, y)
148
149 Re-new image reference (assumes 3 channels)
150
151    im - Image pointer
152    x - xsize of destination image
153    y - ysize of destination image
154
155 **FIXME** what happens if a live image is passed in here?
156
157 Should this just call i_img_empty_ch()?
158
159 =cut
160 */
161
162 i_img *
163 i_img_empty(i_img *im,i_img_dim x,i_img_dim y) {
164   mm_log((1,"i_img_empty(*im %p, x %" i_DF ", y %" i_DF ")\n",
165           im, i_DFc(x), i_DFc(y)));
166   return i_img_empty_ch(im, x, y, 3);
167 }
168
169 /* 
170 =item i_img_empty_ch(im, x, y, ch)
171
172 Re-new image reference 
173
174    im - Image pointer
175    x  - xsize of destination image
176    y  - ysize of destination image
177    ch - number of channels
178
179 =cut
180 */
181
182 i_img *
183 i_img_empty_ch(i_img *im,i_img_dim x,i_img_dim y,int ch) {
184   size_t bytes;
185
186   mm_log((1,"i_img_empty_ch(*im %p, x %" i_DF ", y %" i_DF ", ch %d)\n",
187           im, i_DFc(x), i_DFc(y), ch));
188
189   if (x < 1 || y < 1) {
190     i_push_error(0, "Image sizes must be positive");
191     return NULL;
192   }
193   if (ch < 1 || ch > MAXCHANNELS) {
194     i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
195     return NULL;
196   }
197   /* check this multiplication doesn't overflow */
198   bytes = x*y*ch;
199   if (bytes / y / ch != x) {
200     i_push_errorf(0, "integer overflow calculating image allocation");
201     return NULL;
202   }
203
204   if (im == NULL)
205     im = i_img_alloc();
206
207   memcpy(im, &IIM_base_8bit_direct, sizeof(i_img));
208   i_tags_new(&im->tags);
209   im->xsize    = x;
210   im->ysize    = y;
211   im->channels = ch;
212   im->ch_mask  = MAXINT;
213   im->bytes=bytes;
214   if ( (im->idata=mymalloc(im->bytes)) == NULL) 
215     i_fatal(2,"malloc() error\n"); 
216   memset(im->idata,0,(size_t)im->bytes);
217   
218   im->ext_data = NULL;
219
220   i_img_init(im);
221   
222   mm_log((1,"(%p) <- i_img_empty_ch\n",im));
223   return im;
224 }
225
226 /*
227 =head2 8-bit per sample image internal functions
228
229 These are the functions installed in an 8-bit per sample image.
230
231 =over
232
233 =item i_ppix_d(im, x, y, col)
234
235 Internal function.
236
237 This is the function kept in the i_f_ppix member of an i_img object.
238 It does a normal store of a pixel into the image with range checking.
239
240 Returns 0 if the pixel could be set, -1 otherwise.
241
242 =cut
243 */
244 static
245 int
246 i_ppix_d(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) {
247   int ch;
248   
249   if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
250     for(ch=0;ch<im->channels;ch++)
251       if (im->ch_mask&(1<<ch)) 
252         im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
253     return 0;
254   }
255   return -1; /* error was clipped */
256 }
257
258 /*
259 =item i_gpix_d(im, x, y, &col)
260
261 Internal function.
262
263 This is the function kept in the i_f_gpix member of an i_img object.
264 It does normal retrieval of a pixel from the image with range checking.
265
266 Returns 0 if the pixel could be set, -1 otherwise.
267
268 =cut
269 */
270 static
271 int 
272 i_gpix_d(i_img *im, i_img_dim x, i_img_dim y, i_color *val) {
273   int ch;
274   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
275     for(ch=0;ch<im->channels;ch++) 
276       val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
277     return 0;
278   }
279   for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
280   return -1; /* error was cliped */
281 }
282
283 /*
284 =item i_glin_d(im, l, r, y, vals)
285
286 Reads a line of data from the image, storing the pixels at vals.
287
288 The line runs from (l,y) inclusive to (r,y) non-inclusive
289
290 vals should point at space for (r-l) pixels.
291
292 l should never be less than zero (to avoid confusion about where to
293 put the pixels in vals).
294
295 Returns the number of pixels copied (eg. if r, l or y is out of range)
296
297 =cut
298 */
299 static
300 i_img_dim
301 i_glin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) {
302   int ch;
303   i_img_dim count, i;
304   unsigned char *data;
305   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
306     if (r > im->xsize)
307       r = im->xsize;
308     data = im->idata + (l+y*im->xsize) * im->channels;
309     count = r - l;
310     for (i = 0; i < count; ++i) {
311       for (ch = 0; ch < im->channels; ++ch)
312         vals[i].channel[ch] = *data++;
313     }
314     return count;
315   }
316   else {
317     return 0;
318   }
319 }
320
321 /*
322 =item i_plin_d(im, l, r, y, vals)
323
324 Writes a line of data into the image, using the pixels at vals.
325
326 The line runs from (l,y) inclusive to (r,y) non-inclusive
327
328 vals should point at (r-l) pixels.
329
330 l should never be less than zero (to avoid confusion about where to
331 get the pixels in vals).
332
333 Returns the number of pixels copied (eg. if r, l or y is out of range)
334
335 =cut
336 */
337 static
338 i_img_dim
339 i_plin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) {
340   int ch;
341   i_img_dim count, i;
342   unsigned char *data;
343   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
344     if (r > im->xsize)
345       r = im->xsize;
346     data = im->idata + (l+y*im->xsize) * im->channels;
347     count = r - l;
348     for (i = 0; i < count; ++i) {
349       for (ch = 0; ch < im->channels; ++ch) {
350         if (im->ch_mask & (1 << ch)) 
351           *data = vals[i].channel[ch];
352         ++data;
353       }
354     }
355     return count;
356   }
357   else {
358     return 0;
359   }
360 }
361
362 /*
363 =item i_ppixf_d(im, x, y, val)
364
365 =cut
366 */
367 static
368 int
369 i_ppixf_d(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) {
370   int ch;
371   
372   if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
373     for(ch=0;ch<im->channels;ch++)
374       if (im->ch_mask&(1<<ch)) {
375         im->idata[(x+y*im->xsize)*im->channels+ch] = 
376           SampleFTo8(val->channel[ch]);
377       }
378     return 0;
379   }
380   return -1; /* error was clipped */
381 }
382
383 /*
384 =item i_gpixf_d(im, x, y, val)
385
386 =cut
387 */
388 static
389 int
390 i_gpixf_d(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) {
391   int ch;
392   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
393     for(ch=0;ch<im->channels;ch++) {
394       val->channel[ch] = 
395         Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
396     }
397     return 0;
398   }
399   return -1; /* error was cliped */
400 }
401
402 /*
403 =item i_glinf_d(im, l, r, y, vals)
404
405 Reads a line of data from the image, storing the pixels at vals.
406
407 The line runs from (l,y) inclusive to (r,y) non-inclusive
408
409 vals should point at space for (r-l) pixels.
410
411 l should never be less than zero (to avoid confusion about where to
412 put the pixels in vals).
413
414 Returns the number of pixels copied (eg. if r, l or y is out of range)
415
416 =cut
417 */
418 static
419 i_img_dim
420 i_glinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) {
421   int ch;
422   i_img_dim count, i;
423   unsigned char *data;
424   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
425     if (r > im->xsize)
426       r = im->xsize;
427     data = im->idata + (l+y*im->xsize) * im->channels;
428     count = r - l;
429     for (i = 0; i < count; ++i) {
430       for (ch = 0; ch < im->channels; ++ch)
431         vals[i].channel[ch] = Sample8ToF(*data++);
432     }
433     return count;
434   }
435   else {
436     return 0;
437   }
438 }
439
440 /*
441 =item i_plinf_d(im, l, r, y, vals)
442
443 Writes a line of data into the image, using the pixels at vals.
444
445 The line runs from (l,y) inclusive to (r,y) non-inclusive
446
447 vals should point at (r-l) pixels.
448
449 l should never be less than zero (to avoid confusion about where to
450 get the pixels in vals).
451
452 Returns the number of pixels copied (eg. if r, l or y is out of range)
453
454 =cut
455 */
456 static
457 i_img_dim
458 i_plinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) {
459   int ch;
460   i_img_dim count, i;
461   unsigned char *data;
462   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
463     if (r > im->xsize)
464       r = im->xsize;
465     data = im->idata + (l+y*im->xsize) * im->channels;
466     count = r - l;
467     for (i = 0; i < count; ++i) {
468       for (ch = 0; ch < im->channels; ++ch) {
469         if (im->ch_mask & (1 << ch)) 
470           *data = SampleFTo8(vals[i].channel[ch]);
471         ++data;
472       }
473     }
474     return count;
475   }
476   else {
477     return 0;
478   }
479 }
480
481 /*
482 =item i_gsamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int *chans, int chan_count)
483
484 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
485 for the channels specified by chans, an array of int with chan_count
486 elements.
487
488 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
489
490 =cut
491 */
492 static
493 i_img_dim
494 i_gsamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, 
495               const int *chans, int chan_count) {
496   int ch;
497   i_img_dim count, i, w;
498   unsigned char *data;
499
500   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
501     if (r > im->xsize)
502       r = im->xsize;
503     data = im->idata + (l+y*im->xsize) * im->channels;
504     w = r - l;
505     count = 0;
506
507     if (chans) {
508       /* make sure we have good channel numbers */
509       for (ch = 0; ch < chan_count; ++ch) {
510         if (chans[ch] < 0 || chans[ch] >= im->channels) {
511           i_push_errorf(0, "No channel %d in this image", chans[ch]);
512           return 0;
513         }
514       }
515       for (i = 0; i < w; ++i) {
516         for (ch = 0; ch < chan_count; ++ch) {
517           *samps++ = data[chans[ch]];
518           ++count;
519         }
520         data += im->channels;
521       }
522     }
523     else {
524       if (chan_count <= 0 || chan_count > im->channels) {
525         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
526                       chan_count);
527         return 0;
528       }
529       for (i = 0; i < w; ++i) {
530         for (ch = 0; ch < chan_count; ++ch) {
531           *samps++ = data[ch];
532           ++count;
533         }
534         data += im->channels;
535       }
536     }
537
538     return count;
539   }
540   else {
541     return 0;
542   }
543 }
544
545 /*
546 =item i_gsampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, int *chans, int chan_count)
547
548 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
549 for the channels specified by chan_mask, where bit 0 is the first
550 channel.
551
552 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
553
554 =cut
555 */
556 static
557 i_img_dim
558 i_gsampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, 
559            const int *chans, int chan_count) {
560   int ch;
561   i_img_dim count, i, w;
562   unsigned char *data;
563   for (ch = 0; ch < chan_count; ++ch) {
564     if (chans[ch] < 0 || chans[ch] >= im->channels) {
565       i_push_errorf(0, "No channel %d in this image", chans[ch]);
566     }
567   }
568   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
569     if (r > im->xsize)
570       r = im->xsize;
571     data = im->idata + (l+y*im->xsize) * im->channels;
572     w = r - l;
573     count = 0;
574
575     if (chans) {
576       /* make sure we have good channel numbers */
577       for (ch = 0; ch < chan_count; ++ch) {
578         if (chans[ch] < 0 || chans[ch] >= im->channels) {
579           i_push_errorf(0, "No channel %d in this image", chans[ch]);
580           return 0;
581         }
582       }
583       for (i = 0; i < w; ++i) {
584         for (ch = 0; ch < chan_count; ++ch) {
585           *samps++ = Sample8ToF(data[chans[ch]]);
586           ++count;
587         }
588         data += im->channels;
589       }
590     }
591     else {
592       if (chan_count <= 0 || chan_count > im->channels) {
593         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
594                       chan_count);
595         return 0;
596       }
597       for (i = 0; i < w; ++i) {
598         for (ch = 0; ch < chan_count; ++ch) {
599           *samps++ = Sample8ToF(data[ch]);
600           ++count;
601         }
602         data += im->channels;
603       }
604     }
605     return count;
606   }
607   else {
608     return 0;
609   }
610 }
611
612 /*
613 =back
614
615 =head1 AUTHOR
616
617 Arnar M. Hrafnkelsson <addi@umich.edu>
618
619 Tony Cook <tony@develop-help.com>
620
621 =head1 SEE ALSO
622
623 L<Imager>
624
625 =cut
626 */