1 /*
2 * image.c: Input and output of PNM images.
3 *
4 * Written by: Ullrich Hafner
5 *
6 * This file is part of FIASCO (Fractal Image And Sequence COdec)
7 * Copyright (C) 1994-2000 Ullrich Hafner
8 */
9
10 /*
11 * $Date: 2000/06/15 17:21:30 $
12 * $Author: hafner $
13 * $Revision: 5.2 $
14 * $State: Exp $
15 */
16
17 #include "pnm.h"
18
19 #include <string.h>
20
21 #include "nstring.h"
22
23 #include "types.h"
24 #include "macros.h"
25 #include "error.h"
26
27 #include "fiasco.h"
28 #include "misc.h"
29 #include "image.h"
30
31 /*****************************************************************************
32
33 prototypes
34
35 *****************************************************************************/
36
37 static void
38 init_chroma_tables (void);
39
40 /*****************************************************************************
41
42 local variables
43
44 *****************************************************************************/
45 static int *Cr_r_tab = NULL;
46 static int *Cr_g_tab = NULL;
47 static int *Cb_g_tab = NULL;
48 static int *Cb_b_tab = NULL;
49
50 /*****************************************************************************
51
52 public code
53
54 *****************************************************************************/
55
56 static fiasco_image_t *
make_image_base(void)57 make_image_base(void)
58 {
59 fiasco_image_t * const imageP = Calloc (1, sizeof (fiasco_image_t));
60
61 if (imageP == NULL)
62 pm_error("Failed to allocate memory for image object");
63 else {
64 imageP->delete = fiasco_image_delete;
65 imageP->get_width = fiasco_image_get_width;
66 imageP->get_height = fiasco_image_get_height;
67 imageP->is_color = fiasco_image_is_color;
68 }
69 return imageP;
70 }
71
72
73
74 fiasco_image_t *
fiasco_image_new_file(const char * const filename)75 fiasco_image_new_file(const char * const filename)
76 /*
77 * FIASCO image constructor.
78 * Allocate memory for the FIASCO image structure and
79 * load the image from PNM file `filename'.
80 *
81 * Return value:
82 * pointer to the new image structure
83 * or NULL in case of an error
84 */
85 {
86 fiasco_image_t * imageP;
87
88 imageP = make_image_base();
89
90 imageP->private = read_image_file(filename);
91
92 return imageP;
93 }
94
95
96
97 fiasco_image_t *
fiasco_image_new_stream(FILE * const ifP,unsigned int const width,unsigned int const height,xelval const maxval,int const format)98 fiasco_image_new_stream(FILE * const ifP,
99 unsigned int const width,
100 unsigned int const height,
101 xelval const maxval,
102 int const format)
103 /*
104 * FIASCO image constructor.
105 * Allocate memory for the FIASCO image structure and
106 * load the image from the PNM stream in *ifP, which is positioned just
107 * after the header. 'width', 'height', 'maxval', and 'format' are the
108 * parameters of the image, i.e. the contents of that header.
109 *
110 * Return value:
111 * pointer to the new image structure
112 * or NULL in case of an error
113 */
114 {
115 fiasco_image_t * imageP;
116
117 imageP = make_image_base();
118
119 imageP->private = read_image_stream(ifP, width, height, maxval, format);
120
121 return imageP;
122 }
123
124
125
126 void
fiasco_image_delete(fiasco_image_t * image)127 fiasco_image_delete (fiasco_image_t *image)
128 /*
129 * FIASCO image destructor.
130 * Free memory of FIASCO image struct.
131 *
132 * No return value.
133 *
134 * Side effects:
135 * structure 'image' is discarded.
136 */
137 {
138 image_t *this = cast_image (image);
139
140 if (!this)
141 return;
142
143 try
144 {
145 free_image (this);
146 }
147 catch
148 {
149 return;
150 }
151 }
152
153 unsigned
fiasco_image_get_width(fiasco_image_t * image)154 fiasco_image_get_width (fiasco_image_t *image)
155 {
156 image_t *this = cast_image (image);
157
158 if (!this)
159 return 0;
160 else
161 return this->width;
162 }
163
164 unsigned
fiasco_image_get_height(fiasco_image_t * image)165 fiasco_image_get_height (fiasco_image_t *image)
166 {
167 image_t *this = cast_image (image);
168
169 if (!this)
170 return 0;
171 else
172 return this->width;
173 }
174
175 int
fiasco_image_is_color(fiasco_image_t * image)176 fiasco_image_is_color (fiasco_image_t *image)
177 {
178 image_t *this = cast_image (image);
179
180 if (!this)
181 return 0;
182 else
183 return this->color;
184 }
185
186 image_t *
cast_image(fiasco_image_t * image)187 cast_image (fiasco_image_t *image)
188 /*
189 * Cast pointer `image' to type image_t.
190 * Check whether `image' is a valid object of type image_t.
191 *
192 * Return value:
193 * pointer to dfiasco_t struct on success
194 * NULL otherwise
195 */
196 {
197 image_t *this = (image_t *) image->private;
198 if (this)
199 {
200 if (!STRSEQ(this->id, "IFIASCO"))
201 {
202 set_error (_("Parameter `image' doesn't match required type."));
203 return NULL;
204 }
205 }
206 else
207 {
208 set_error (_("Parameter `%s' not defined (NULL)."), "image");
209 }
210
211 return this;
212 }
213
214 image_t *
alloc_image(unsigned width,unsigned height,bool_t color,format_e format)215 alloc_image (unsigned width, unsigned height, bool_t color, format_e format)
216 /*
217 * Image constructor:
218 * Allocate memory for the image_t structure.
219 * Image size is given by 'width' and 'height'.
220 * If 'color' == YES then allocate memory for three color bands (Y, Cb, Cr).
221 * otherwise just allocate memory for a grayscale image.
222 * 'format' specifies whether image pixels of color images
223 * are stored in 4:4:4 or 4:2:0 format.
224 *
225 * Return value:
226 * pointer to the new image structure.
227 */
228 {
229 image_t *image;
230 color_e band;
231
232 if ((width & 1) || (height & 1))
233 error ("Width and height of images must be even numbers.");
234 if (!color)
235 format = FORMAT_4_4_4;
236
237 image = Calloc (1, sizeof (image_t));
238 image->width = width;
239 image->height = height;
240 image->color = color;
241 image->format = format;
242 image->reference_count = 1;
243
244 STRSCPY(image->id, "IFIASCO");
245
246 for (band = first_band (color); band <= last_band (color); band++)
247 if (format == FORMAT_4_2_0 && band != Y)
248 image->pixels [band] = Calloc ((width * height) >> 2,
249 sizeof (word_t));
250 else
251 image->pixels [band] = Calloc (width * height, sizeof (word_t));
252
253 return image;
254 }
255
256 image_t *
clone_image(image_t * image)257 clone_image (image_t *image)
258 /*
259 * Copy constructor:
260 * Construct new image by copying the given `image'.
261 *
262 * Return value:
263 * pointer to the new image structure.
264 */
265 {
266 image_t *new = alloc_image (image->width, image->height, image->color,
267 image->format);
268 color_e band;
269
270 for (band = first_band (new->color); band <= last_band (new->color); band++)
271 if (new->format == FORMAT_4_2_0 && band != Y)
272 {
273 memcpy (new->pixels [band], image->pixels [band],
274 ((new->width * new->height) >> 2) * sizeof (word_t));
275 }
276 else
277 {
278 memcpy (new->pixels [band], image->pixels [band],
279 new->width * new->height * sizeof (word_t));
280 }
281
282 return new;
283 }
284
285 void
free_image(image_t * image)286 free_image (image_t *image)
287 /*
288 * Image destructor:
289 * Free memory of 'image' struct and pixel data.
290 *
291 * No return value.
292 *
293 * Side effects:
294 * structure 'image' is discarded.
295 */
296 {
297 if (image != NULL)
298 {
299 if (--image->reference_count)
300 return; /* image is still referenced */
301 else
302 {
303 color_e band;
304
305 for (band = first_band (image->color);
306 band <= last_band (image->color); band++)
307 if (image->pixels [band])
308 Free (image->pixels [band]);
309 Free (image);
310 }
311 }
312 else
313 warning ("Can't free image <NULL>.");
314 }
315
316
317 static void
read_image_data(image_t * const image,FILE * input,const bool_t color,const int width,const int height,const xelval maxval,const int format)318 read_image_data(image_t * const image, FILE *input, const bool_t color,
319 const int width, const int height, const xelval maxval,
320 const int format) {
321 int row;
322 int i; /* Cursor into image->pixels arrays */
323 xel * xelrow;
324 /* The following are just the normal rgb -> YCbCr conversion matrix,
325 except normalization to maxval 4095 (12 bit color) is built in
326 */
327 const double coeff_lu_r = +0.2989 / maxval * 4095;
328 const double coeff_lu_g = +0.5866 / maxval * 4095;
329 const double coeff_lu_b = +0.1145 / maxval * 4095;
330 const double coeff_cb_r = -0.1687 / maxval * 4095;
331 const double coeff_cb_g = -0.3312 / maxval * 4095;
332 const double coeff_cb_b = +0.5000 / maxval * 4095;
333 const double coeff_cr_r = +0.5000 / maxval * 4095;
334 const double coeff_cr_g = -0.4183 / maxval * 4095;
335 const double coeff_cr_b = -0.0816 / maxval * 4095;
336
337 xelrow = pnm_allocrow(width);
338
339 i = 0;
340 for (row = 0; row < height; row++) {
341 int col;
342 pnm_readpnmrow(input, xelrow, width, maxval, format);
343 for (col = 0; col < width; col++) {
344 if (color) {
345 image->pixels[Y][i] =
346 coeff_lu_r * PPM_GETR(xelrow[col])
347 + coeff_lu_g * PPM_GETG(xelrow[col])
348 + coeff_lu_b * PPM_GETB(xelrow[col]) - 2048;
349 image->pixels[Cb][i] =
350 coeff_cb_r * PPM_GETR(xelrow[col])
351 + coeff_cb_g * PPM_GETG(xelrow[col])
352 + coeff_cb_b * PPM_GETB(xelrow[col]);
353 image->pixels[Cr][i] =
354 coeff_cr_r * PPM_GETR(xelrow[col])
355 + coeff_cr_g * PPM_GETG(xelrow[col])
356 + coeff_cr_b * PPM_GETB(xelrow[col]);
357
358 i++;
359 } else
360 image->pixels[GRAY][i++] =
361 PNM_GET1(xelrow[col]) * 4095 / maxval - 2048;
362 }
363 }
364
365 free(xelrow);
366 }
367
368
369
370 image_t *
read_image_stream(FILE * const ifP,unsigned int const width,unsigned int const height,xelval const maxval,int const format)371 read_image_stream(FILE * const ifP,
372 unsigned int const width,
373 unsigned int const height,
374 xelval const maxval,
375 int const format)
376 /*
377 * Read one PNM image from stream *ifP, which is positioned just after the
378 * header. 'width', 'height', 'maxval', and 'format' are the parameters of
379 * the image (i.e. the contents of that header).
380 */
381 {
382 image_t *image; /* pointer to new image structure */
383 bool_t color; /* color image ? (YES/NO) */
384
385 if (PNM_FORMAT_TYPE(format) == PPM_FORMAT)
386 color = YES;
387 else
388 color = NO;
389
390 if (width < 32)
391 pm_error("Image must have a width of at least 32 pixels.");
392
393 if (height < 32)
394 pm_error("Image must have a height of at least 32 pixels.");
395
396 image = alloc_image (width, height, color, FORMAT_4_4_4);
397
398 read_image_data(image, ifP, color, width, height, maxval, format);
399
400 return image;
401 }
402
403
404
405 image_t *
read_image_file(const char * const filename)406 read_image_file(const char * const filename)
407 /*
408 * Read the PNM image from the file named 'filename'.
409 *
410 * Return value:
411 * pointer to the image structure.
412 */
413 {
414 FILE * ifP;
415 int width, height; /* image dimensions */
416 xelval maxval; /* Maxval of image */
417 int format; /* Image's format code */
418 image_t * imageP; /* pointer to new image structure */
419
420 ifP = pm_openr(filename);
421
422 pnm_readpnminit(ifP, &width, &height, &maxval, &format);
423
424 imageP = read_image_stream(ifP, width, height, maxval, format);
425
426 pm_close(ifP);
427
428 return imageP;
429 }
430
431
432
433 void
write_image(const char * image_name,const image_t * image)434 write_image (const char *image_name, const image_t *image)
435 /*
436 * Write given 'image' data to the file 'image_name'.
437 *
438 * No return value.
439 */
440 {
441 FILE *output; /* output stream */
442 int format;
443 int row;
444 int i; /* Cursor into image->pixel arrays */
445 xel * xelrow;
446 unsigned *gray_clip; /* clipping table */
447
448 assert (image && image_name);
449
450 if (image->format == FORMAT_4_2_0)
451 {
452 warning ("We cannot write images in 4:2:0 format.");
453 return;
454 }
455
456 if (image_name == NULL)
457 output = stdout;
458 else if (streq(image_name, "-"))
459 output = stdout;
460 else
461 output = pm_openw((char*)image_name);
462
463 gray_clip = init_clipping (); /* mapping of int -> unsigned */
464 if (!gray_clip)
465 error (fiasco_get_error_message ());
466 init_chroma_tables ();
467
468 format = image->color ? PPM_TYPE : PGM_TYPE;
469
470 pnm_writepnminit(output, image->width, image->height, 255, format, 0);
471
472 xelrow = pnm_allocrow(image->width);
473 i = 0;
474 for (row = 0; row < image->height; row++) {
475 int col;
476 for (col = 0; col < image->width; col++) {
477 if (image->color) {
478 word_t yval, cbval, crval;
479
480 yval = image->pixels[Y][i] / 16 + 128;
481 cbval = image->pixels[Cb][i] / 16;
482 crval = image->pixels[Cr][i] / 16;
483
484 PPM_ASSIGN(xelrow[col],
485 gray_clip[yval + Cr_r_tab[crval]],
486 gray_clip[yval + Cr_g_tab[crval] + Cb_g_tab [cbval]],
487 gray_clip[yval + Cb_b_tab[cbval]]);
488
489 } else
490 /* The 16 below should be 4095/255 = 16.0588 */
491 PNM_ASSIGN1(xelrow[col],
492 gray_clip[image->pixels[GRAY][i]/16+128]);
493 i++;
494 }
495 pnm_writepnmrow(output, xelrow,
496 image->width, 255, format, 0);
497 }
498 pnm_freerow(xelrow);
499
500 pm_close(output);
501 }
502
503 bool_t
same_image_type(const image_t * img1,const image_t * img2)504 same_image_type (const image_t *img1, const image_t *img2)
505 /*
506 * Check whether the given images 'img1' and `img2' are of the same type.
507 *
508 * Return value:
509 * YES if images 'img1' and `img2' are of the same type
510 * NO otherwise.
511 */
512 {
513 assert (img1 && img2);
514
515 return ((img1->width == img2->width)
516 && (img1->height == img2->height)
517 && (img1->color == img2->color)
518 && (img1->format == img2->format));
519 }
520
521 /*****************************************************************************
522
523 private code
524
525 *****************************************************************************/
526
527 static void
init_chroma_tables(void)528 init_chroma_tables (void)
529 /*
530 * Chroma tables are used to perform fast YCbCr->RGB color space conversion.
531 */
532 {
533 int crval, cbval, i;
534
535 if (Cr_r_tab != NULL || Cr_g_tab != NULL ||
536 Cb_g_tab != NULL || Cb_b_tab != NULL)
537 return;
538
539 Cr_r_tab = Calloc (768, sizeof (int));
540 Cr_g_tab = Calloc (768, sizeof (int));
541 Cb_g_tab = Calloc (768, sizeof (int));
542 Cb_b_tab = Calloc (768, sizeof (int));
543
544 for (i = 256; i < 512; i++)
545 {
546 cbval = crval = i - 128 - 256;
547
548 Cr_r_tab[i] = 1.4022 * crval + 0.5;
549 Cr_g_tab[i] = -0.7145 * crval + 0.5;
550 Cb_g_tab[i] = -0.3456 * cbval + 0.5;
551 Cb_b_tab[i] = 1.7710 * cbval + 0.5;
552 }
553 for (i = 0; i < 256; i++)
554 {
555 Cr_r_tab[i] = Cr_r_tab[256];
556 Cr_g_tab[i] = Cr_g_tab[256];
557 Cb_g_tab[i] = Cb_g_tab[256];
558 Cb_b_tab[i] = Cb_b_tab[256];
559 }
560 for (i = 512; i < 768; i++)
561 {
562 Cr_r_tab[i] = Cr_r_tab[511];
563 Cr_g_tab[i] = Cr_g_tab[511];
564 Cb_g_tab[i] = Cb_g_tab[511];
565 Cb_b_tab[i] = Cb_b_tab[511];
566 }
567
568 Cr_r_tab += 256 + 128;
569 Cr_g_tab += 256 + 128;
570 Cb_g_tab += 256 + 128;
571 Cb_b_tab += 256 + 128;
572 }
573