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