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