1 /* 2 * wrppm.c 3 * 4 * This file was part of the Independent JPEG Group's software: 5 * Copyright (C) 1991-1996, Thomas G. Lane. 6 * Modified 2009 by Guido Vollbeding. 7 * It was modified by The libjpeg-turbo Project to include only code and 8 * information relevant to libjpeg-turbo. 9 * For conditions of distribution and use, see the accompanying README.ijg 10 * file. 11 * 12 * This file contains routines to write output images in PPM/PGM format. 13 * The extended 2-byte-per-sample raw PPM/PGM formats are supported. 14 * The PBMPLUS library is NOT required to compile this software 15 * (but it is highly useful as a set of PPM image manipulation programs). 16 * 17 * These routines may need modification for non-Unix environments or 18 * specialized applications. As they stand, they assume output to 19 * an ordinary stdio stream. 20 */ 21 22 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ 23 #include "wrppm.h" 24 25 #ifdef PPM_SUPPORTED 26 27 28 /* 29 * For 12-bit JPEG data, we either downscale the values to 8 bits 30 * (to write standard byte-per-sample PPM/PGM files), or output 31 * nonstandard word-per-sample PPM/PGM files. Downscaling is done 32 * if PPM_NORAWWORD is defined (this can be done in the Makefile 33 * or in jconfig.h). 34 * (When the core library supports data precision reduction, a cleaner 35 * implementation will be to ask for that instead.) 36 */ 37 38 #if BITS_IN_JSAMPLE == 8 39 #define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) (v) 40 #define BYTESPERSAMPLE 1 41 #define PPM_MAXVAL 255 42 #else 43 #ifdef PPM_NORAWWORD 44 #define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) ((v) >> (BITS_IN_JSAMPLE-8)) 45 #define BYTESPERSAMPLE 1 46 #define PPM_MAXVAL 255 47 #else 48 /* The word-per-sample format always puts the MSB first. */ 49 #define PUTPPMSAMPLE(ptr,v) \ 50 { register int val_ = v; \ 51 *ptr++ = (char) ((val_ >> 8) & 0xFF); \ 52 *ptr++ = (char) (val_ & 0xFF); \ 53 } 54 #define BYTESPERSAMPLE 2 55 #define PPM_MAXVAL ((1<<BITS_IN_JSAMPLE)-1) 56 #endif 57 #endif 58 59 60 /* 61 * When JSAMPLE is the same size as char, we can just fwrite() the 62 * decompressed data to the PPM or PGM file. 63 */ 64 65 66 /* 67 * Write some pixel data. 68 * In this module rows_supplied will always be 1. 69 * 70 * put_pixel_rows handles the "normal" 8-bit case where the decompressor 71 * output buffer is physically the same as the fwrite buffer. 72 */ 73 74 METHODDEF(void) 75 put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, 76 JDIMENSION rows_supplied) 77 { 78 ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; 79 80 (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); 81 } 82 83 84 /* 85 * This code is used when we have to copy the data and apply a pixel 86 * format translation. Typically this only happens in 12-bit mode. 87 */ 88 89 METHODDEF(void) 90 copy_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, 91 JDIMENSION rows_supplied) 92 { 93 ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; 94 register char *bufferptr; 95 register JSAMPROW ptr; 96 register JDIMENSION col; 97 98 ptr = dest->pub.buffer[0]; 99 bufferptr = dest->iobuffer; 100 for (col = dest->samples_per_row; col > 0; col--) { 101 PUTPPMSAMPLE(bufferptr, GETJSAMPLE(*ptr++)); 102 } 103 (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); 104 } 105 106 107 /* 108 * Write some pixel data when color quantization is in effect. 109 * We have to demap the color index values to straight data. 110 */ 111 112 METHODDEF(void) 113 put_demapped_rgb (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, 114 JDIMENSION rows_supplied) 115 { 116 ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; 117 register char *bufferptr; 118 register int pixval; 119 register JSAMPROW ptr; 120 register JSAMPROW color_map0 = cinfo->colormap[0]; 121 register JSAMPROW color_map1 = cinfo->colormap[1]; 122 register JSAMPROW color_map2 = cinfo->colormap[2]; 123 register JDIMENSION col; 124 125 ptr = dest->pub.buffer[0]; 126 bufferptr = dest->iobuffer; 127 for (col = cinfo->output_width; col > 0; col--) { 128 pixval = GETJSAMPLE(*ptr++); 129 PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[pixval])); 130 PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map1[pixval])); 131 PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map2[pixval])); 132 } 133 (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); 134 } 135 136 137 METHODDEF(void) 138 put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, 139 JDIMENSION rows_supplied) 140 { 141 ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; 142 register char *bufferptr; 143 register JSAMPROW ptr; 144 register JSAMPROW color_map = cinfo->colormap[0]; 145 register JDIMENSION col; 146 147 ptr = dest->pub.buffer[0]; 148 bufferptr = dest->iobuffer; 149 for (col = cinfo->output_width; col > 0; col--) { 150 PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map[GETJSAMPLE(*ptr++)])); 151 } 152 (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); 153 } 154 155 156 /* 157 * Startup: write the file header. 158 */ 159 160 METHODDEF(void) 161 start_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) 162 { 163 ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; 164 165 /* Emit file header */ 166 switch (cinfo->out_color_space) { 167 case JCS_GRAYSCALE: 168 /* emit header for raw PGM format */ 169 fprintf(dest->pub.output_file, "P5\n%ld %ld\n%d\n", 170 (long) cinfo->output_width, (long) cinfo->output_height, 171 PPM_MAXVAL); 172 break; 173 case JCS_RGB: 174 /* emit header for raw PPM format */ 175 fprintf(dest->pub.output_file, "P6\n%ld %ld\n%d\n", 176 (long) cinfo->output_width, (long) cinfo->output_height, 177 PPM_MAXVAL); 178 break; 179 default: 180 ERREXIT(cinfo, JERR_PPM_COLORSPACE); 181 } 182 } 183 184 185 /* 186 * Finish up at the end of the file. 187 */ 188 189 METHODDEF(void) 190 finish_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) 191 { 192 /* Make sure we wrote the output file OK */ 193 fflush(dinfo->output_file); 194 if (ferror(dinfo->output_file)) 195 ERREXIT(cinfo, JERR_FILE_WRITE); 196 } 197 198 199 /* 200 * The module selection routine for PPM format output. 201 */ 202 203 GLOBAL(djpeg_dest_ptr) 204 jinit_write_ppm (j_decompress_ptr cinfo) 205 { 206 ppm_dest_ptr dest; 207 208 /* Create module interface object, fill in method pointers */ 209 dest = (ppm_dest_ptr) 210 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, 211 sizeof(ppm_dest_struct)); 212 dest->pub.start_output = start_output_ppm; 213 dest->pub.finish_output = finish_output_ppm; 214 215 /* Calculate output image dimensions so we can allocate space */ 216 jpeg_calc_output_dimensions(cinfo); 217 218 /* Create physical I/O buffer */ 219 dest->samples_per_row = cinfo->output_width * cinfo->out_color_components; 220 dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * sizeof(char)); 221 dest->iobuffer = (char *) (*cinfo->mem->alloc_small) 222 ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width); 223 224 if (cinfo->quantize_colors || BITS_IN_JSAMPLE != 8 || 225 sizeof(JSAMPLE) != sizeof(char)) { 226 /* When quantizing, we need an output buffer for colormap indexes 227 * that's separate from the physical I/O buffer. We also need a 228 * separate buffer if pixel format translation must take place. 229 */ 230 dest->pub.buffer = (*cinfo->mem->alloc_sarray) 231 ((j_common_ptr) cinfo, JPOOL_IMAGE, 232 cinfo->output_width * cinfo->output_components, (JDIMENSION) 1); 233 dest->pub.buffer_height = 1; 234 if (! cinfo->quantize_colors) 235 dest->pub.put_pixel_rows = copy_pixel_rows; 236 else if (cinfo->out_color_space == JCS_GRAYSCALE) 237 dest->pub.put_pixel_rows = put_demapped_gray; 238 else 239 dest->pub.put_pixel_rows = put_demapped_rgb; 240 } else { 241 /* We will fwrite() directly from decompressor output buffer. */ 242 /* Synthesize a JSAMPARRAY pointer structure */ 243 dest->pixrow = (JSAMPROW) dest->iobuffer; 244 dest->pub.buffer = & dest->pixrow; 245 dest->pub.buffer_height = 1; 246 dest->pub.put_pixel_rows = put_pixel_rows; 247 } 248 249 return (djpeg_dest_ptr) dest; 250 } 251 252 #endif /* PPM_SUPPORTED */ 253