]> git.imager.perl.org - imager.git/blame - img8.c
split 8-bit image implementation out of the megafile image.c
[imager.git] / img8.c
CommitLineData
a2f9a61c
TC
1#include "imager.h"
2#include "imageri.h"
3
4static int i_ppix_d(i_img *im, int x, int y, const i_color *val);
5static int i_gpix_d(i_img *im, int x, int y, i_color *val);
6static int i_glin_d(i_img *im, int l, int r, int y, i_color *vals);
7static int i_plin_d(i_img *im, int l, int r, int y, const i_color *vals);
8static int i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val);
9static int i_gpixf_d(i_img *im, int x, int y, i_fcolor *val);
10static int i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals);
11static int i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals);
12static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, const int *chans, int chan_count);
13static 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
18A static i_img object used to initialize direct 8-bit per sample images.
19
20=cut
21*/
22static 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
86Creates a new image object I<x> pixels wide, and I<y> pixels high with
87I<ch> channels.
88
89=cut
90*/
91
92
93i_img *
94IIM_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
105void
106IIM_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
115Create new image reference - notice that this isn't an object yet and
116this should be fixed asap.
117
118=cut
119*/
120
121
122i_img *
123i_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
147Re-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
155Should this just call i_img_empty_ch()?
156
157=cut
158*/
159
160i_img *
161i_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
169Re-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
179i_img *
180i_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
225These 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
231Internal function.
232
233This is the function kept in the i_f_ppix member of an i_img object.
234It does a normal store of a pixel into the image with range checking.
235
236Returns 0 if the pixel could be set, -1 otherwise.
237
238=cut
239*/
240static
241int
242i_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
257Internal function.
258
259This is the function kept in the i_f_gpix member of an i_img object.
260It does normal retrieval of a pixel from the image with range checking.
261
262Returns 0 if the pixel could be set, -1 otherwise.
263
264=cut
265*/
266static
267int
268i_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
282Reads a line of data from the image, storing the pixels at vals.
283
284The line runs from (l,y) inclusive to (r,y) non-inclusive
285
286vals should point at space for (r-l) pixels.
287
288l should never be less than zero (to avoid confusion about where to
289put the pixels in vals).
290
291Returns the number of pixels copied (eg. if r, l or y is out of range)
292
293=cut
294*/
295static
296int
297i_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
319Writes a line of data into the image, using the pixels at vals.
320
321The line runs from (l,y) inclusive to (r,y) non-inclusive
322
323vals should point at (r-l) pixels.
324
325l should never be less than zero (to avoid confusion about where to
326get the pixels in vals).
327
328Returns the number of pixels copied (eg. if r, l or y is out of range)
329
330=cut
331*/
332static
333int
334i_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*/
361static
362int
363i_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*/
382static
383int
384i_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
399Reads a line of data from the image, storing the pixels at vals.
400
401The line runs from (l,y) inclusive to (r,y) non-inclusive
402
403vals should point at space for (r-l) pixels.
404
405l should never be less than zero (to avoid confusion about where to
406put the pixels in vals).
407
408Returns the number of pixels copied (eg. if r, l or y is out of range)
409
410=cut
411*/
412static
413int
414i_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
436Writes a line of data into the image, using the pixels at vals.
437
438The line runs from (l,y) inclusive to (r,y) non-inclusive
439
440vals should point at (r-l) pixels.
441
442l should never be less than zero (to avoid confusion about where to
443get the pixels in vals).
444
445Returns the number of pixels copied (eg. if r, l or y is out of range)
446
447=cut
448*/
449static
450int
451i_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
476Reads sample values from im for the horizontal line (l, y) to (r-1,y)
477for the channels specified by chans, an array of int with chan_count
478elements.
479
480Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
481
482=cut
483*/
484static
485int
486i_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
539Reads sample values from im for the horizontal line (l, y) to (r-1,y)
540for the channels specified by chan_mask, where bit 0 is the first
541channel.
542
543Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
544
545=cut
546*/
547static
548int
549i_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
607Arnar M. Hrafnkelsson <addi@umich.edu>
608
609Tony Cook <tony@develop-help.com>
610
611=head1 SEE ALSO
612
613L<Imager>
614
615=cut
616*/