- Timestamp:
- Oct 4, 2010, 2:47:01 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/ipp-20100823/psLib/src/jpeg/psImageJpeg.c
r28998 r29309 15 15 #include "psImageJpeg.h" 16 16 17 /* XXX this to do to make this reasonably complete 18 * update bDraw APIs to accept a bDrawBuffer structure as an input operand 19 */ 20 17 21 #ifdef HAVE_STDLIB_H 18 22 // jpeglib.h includes jconfig.h which is full of autoconf generated HAVE_* 19 23 // defines. This is a hack to work around CPP redefinition errors. Arrrrrgh!!! 20 24 // -JH 25 26 // XXX specifically, jconfig.h has defines like the following. these 27 // could be individually tested here and specifically undefed. EAM. 28 // #define HAVE_PROTOTYPES 29 // #define HAVE_UNSIGNED_CHAR 30 // #define HAVE_UNSIGNED_SHORT 31 21 32 # undef HAVE_STDLIB_H 22 33 # include <jpeglib.h> 23 34 #endif // ifdef HAVE_STDLIB_H 24 35 25 static void imageJpeg ColormapFree(psImageJpegColormap *map)36 static void imageJpegOptionsFree(psImageJpegOptions *options) 26 37 { 27 38 28 if (!map) { 29 return; 30 } 31 32 psFree(map->red); 33 psFree(map->green); 34 psFree(map->blue); 39 if (!options) { 35 40 return; 36 } 37 38 psImageJpegColormap *psImageJpegColormapAlloc(void) 41 } 42 43 psFree(options->red); 44 psFree(options->green); 45 psFree(options->blue); 46 return; 47 } 48 49 psImageJpegOptions *psImageJpegOptionsAlloc(void) 39 50 { 40 psImageJpegColormap *map = psAlloc(sizeof(psImageJpegColormap)); 41 psMemSetDeallocator(map, (psFreeFunc)imageJpegColormapFree); 42 43 map->red = psVectorAlloc(256, PS_TYPE_U8); 44 map->blue = psVectorAlloc(256, PS_TYPE_U8); 45 map->green = psVectorAlloc(256, PS_TYPE_U8); 46 47 return map; 48 } 49 50 psImageJpegColormap *psImageJpegColormapSet(psImageJpegColormap *map, const char *name) 51 psImageJpegOptions *options = psAlloc(sizeof(psImageJpegOptions)); 52 psMemSetDeallocator(options, (psFreeFunc)imageJpegOptionsFree); 53 54 options->red = psVectorAlloc(256, PS_TYPE_U8); 55 options->blue = psVectorAlloc(256, PS_TYPE_U8); 56 options->green = psVectorAlloc(256, PS_TYPE_U8); 57 58 options->min = 0.0; 59 options->max = 1000.0; 60 61 options->xFlip = false; 62 options->yFlip = false; 63 options->showScale = PS_JPEG_SHOWSCALE_BOTTOM; 64 65 psImageJpegColormapSet(options, "greyscale"); 66 67 return options; 68 } 69 70 bool psImageJpegColormapSet(psImageJpegOptions *options, const char *name) 51 71 { 52 53 if (!map) { 54 map = psImageJpegColormapAlloc (); 55 } 56 57 /* grayscale */ 58 if ((!strcasecmp (name, "grayscale")) || (!strcasecmp (name, "greyscale"))) { 59 for (int i = 0; i < map->red->n; i++) { 60 map->red->data.U8[i] = PS_JPEG_RANGELIM(i); 61 map->green->data.U8[i] = PS_JPEG_RANGELIM(i); 62 map->blue->data.U8[i] = PS_JPEG_RANGELIM(i); 63 } 64 return map; 65 } 66 67 /* -grayscale */ 68 if ((!strcasecmp (name, "-grayscale")) || (!strcasecmp (name, "-greyscale"))) { 69 for (int i = 0; i < map->red->n; i++) { 70 map->red->data.U8[i] = PS_JPEG_RANGELIM(256 - i); 71 map->green->data.U8[i] = PS_JPEG_RANGELIM(256 - i); 72 map->blue->data.U8[i] = PS_JPEG_RANGELIM(256 - i); 73 } 74 return map; 75 } 76 77 /* rainbow */ 78 if (!strcasecmp (name, "rainbow")) { 79 int I1 = 0.25*map->red->n; 80 int I2 = 0.50*map->red->n; 81 int I3 = 0.75*map->red->n; 82 for (int i = 0; i < I1; i++) { 83 map->red->data.U8[i] = 0; 84 map->green->data.U8[i] = 0; 85 map->blue->data.U8[i] = PS_JPEG_RANGELIM(4*i); 86 } 87 for (int i = I1; i < I2; i++) { 88 map->red->data.U8[i] = PS_JPEG_RANGELIM(4*(i - I1)); 89 map->green->data.U8[i] = 0; 90 map->blue->data.U8[i] = PS_JPEG_RANGELIM(4*(I2 - i)); 91 } 92 for (int i = I2; i < I3; i++) { 93 map->red->data.U8[i] = 255; 94 map->green->data.U8[i] = 4*(i - I2); 95 map->blue->data.U8[i] = 0; 96 } 97 for (int i = I3; i < map->red->n; i++) { 98 map->red->data.U8[i] = 255; 99 map->green->data.U8[i] = 255; 100 map->blue->data.U8[i] = PS_JPEG_RANGELIM(4*(i - I3)); 101 } 102 return map; 103 } 104 105 /* heat */ 106 if (!strcasecmp (name, "heat")) { 107 int I1 = 0.25*map->red->n; 108 int I2 = 0.50*map->red->n; 109 int I3 = 0.75*map->red->n; 110 for (int i = 0; i < I1; i++) { 111 map->red->data.U8[i] = PS_JPEG_RANGELIM(2*i); 112 map->green->data.U8[i] = 0; 113 map->blue->data.U8[i] = 0; 114 } 115 for (int i = I1; i < I2; i++) { 116 map->red->data.U8[i] = PS_JPEG_RANGELIM(2*i); 117 map->green->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I1)); 118 map->blue->data.U8[i] = 0; 119 } 120 for (int i = I2; i < I3; i++) { 121 map->red->data.U8[i] = 255; 122 map->green->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I1)); 123 map->blue->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I2)); 124 } 125 for (int i = I3; i < map->red->n; i++) { 126 map->red->data.U8[i] = 255; 127 map->green->data.U8[i] = 255; 128 map->blue->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I2)); 129 } 130 return map; 131 } 132 133 // invalid colormap: warn user 134 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Invalid colormap name: %s --- using greyscale\n", name); 135 return psImageJpegColormapSet (map, "greyscale"); 136 } 137 138 // XXX need to fix library references for this (psLib does not depend on libkapa) 139 # if (0) 140 // XXX Add colormap bar with scale (min -> max) 141 // XXX Add option to plot the source overlay (pass in bDrawBuffer populated with points?) 72 PS_ASSERT_PTR_NON_NULL(options, false); 73 74 /* grayscale */ 75 if ((!strcasecmp (name, "grayscale")) || (!strcasecmp (name, "greyscale"))) { 76 for (int i = 0; i < options->red->n; i++) { 77 options->red->data.U8[i] = PS_JPEG_RANGELIM(i); 78 options->green->data.U8[i] = PS_JPEG_RANGELIM(i); 79 options->blue->data.U8[i] = PS_JPEG_RANGELIM(i); 80 } 81 options->white = 255; 82 options->black = 0; 83 return options; 84 } 85 86 /* -grayscale */ 87 if ((!strcasecmp (name, "-grayscale")) || (!strcasecmp (name, "-greyscale"))) { 88 for (int i = 0; i < options->red->n; i++) { 89 options->red->data.U8[i] = PS_JPEG_RANGELIM(256 - i); 90 options->green->data.U8[i] = PS_JPEG_RANGELIM(256 - i); 91 options->blue->data.U8[i] = PS_JPEG_RANGELIM(256 - i); 92 } 93 options->white = 0; 94 options->black = 255; 95 return options; 96 } 97 98 /* rainbow */ 99 if (!strcasecmp (name, "rainbow")) { 100 int I1 = 0.25*options->red->n; 101 int I2 = 0.50*options->red->n; 102 int I3 = 0.75*options->red->n; 103 for (int i = 0; i < I1; i++) { 104 options->red->data.U8[i] = 0; 105 options->green->data.U8[i] = 0; 106 options->blue->data.U8[i] = PS_JPEG_RANGELIM(4*i); 107 } 108 for (int i = I1; i < I2; i++) { 109 options->red->data.U8[i] = PS_JPEG_RANGELIM(4*(i - I1)); 110 options->green->data.U8[i] = 0; 111 options->blue->data.U8[i] = PS_JPEG_RANGELIM(4*(I2 - i)); 112 } 113 for (int i = I2; i < I3; i++) { 114 options->red->data.U8[i] = 255; 115 options->green->data.U8[i] = 4*(i - I2); 116 options->blue->data.U8[i] = 0; 117 } 118 for (int i = I3; i < options->red->n; i++) { 119 options->red->data.U8[i] = 255; 120 options->green->data.U8[i] = 255; 121 options->blue->data.U8[i] = PS_JPEG_RANGELIM(4*(i - I3)); 122 } 123 options->white = 255; 124 options->black = 0; 125 return options; 126 } 127 128 /* heat */ 129 if (!strcasecmp (name, "heat")) { 130 int I1 = 0.25*options->red->n; 131 int I2 = 0.50*options->red->n; 132 int I3 = 0.75*options->red->n; 133 for (int i = 0; i < I1; i++) { 134 options->red->data.U8[i] = PS_JPEG_RANGELIM(2*i); 135 options->green->data.U8[i] = 0; 136 options->blue->data.U8[i] = 0; 137 } 138 for (int i = I1; i < I2; i++) { 139 options->red->data.U8[i] = PS_JPEG_RANGELIM(2*i); 140 options->green->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I1)); 141 options->blue->data.U8[i] = 0; 142 } 143 for (int i = I2; i < I3; i++) { 144 options->red->data.U8[i] = 255; 145 options->green->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I1)); 146 options->blue->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I2)); 147 } 148 for (int i = I3; i < options->red->n; i++) { 149 options->red->data.U8[i] = 255; 150 options->green->data.U8[i] = 255; 151 options->blue->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I2)); 152 } 153 options->white = 255; 154 options->black = 0; 155 return options; 156 } 157 158 // invalid colormap: warn user 159 psWarning("Invalid colormap name: %s --- using greyscale\n", name); 160 return psImageJpegColormapSet (options, "greyscale"); 161 } 162 163 bDrawBuffer *psImageJpegOverlayInit (const psImage *image) { 164 165 int dx = image->numCols; 166 int dy = image->numRows; 167 168 bDrawBuffer *bdbuf = bDrawBufferCreate(dx, dy); 169 170 return bdbuf; 171 } 172 173 // copy the buffer pixels which are not white (probably should be "not blank") 174 bool psImageJpegOverlayDraw (JSAMPLE *jpegImage, bDrawBuffer *bdbuf, int offX, int offY) { 175 176 // XXX check valid limits 177 178 int dx = bdbuf->Nx; 179 int dy = bdbuf->Ny; 180 181 int Npalette; 182 png_color *palette = KapaPNGPalette (&Npalette); 183 bDrawColor white = KapaColorByName ("white"); 184 for (int j = 0; j < dy; j++) { 185 for (int i = 0; i < dx; i++) { 186 bDrawColor color = bdbuf->pixels[j][i]; 187 if (color == white) continue; 188 jpegImage[(j + offY)*3*dx + 3*(i + offX) + 0] = palette[color].red; 189 jpegImage[(j + offY)*3*dx + 3*(i + offX) + 1] = palette[color].green; 190 jpegImage[(j + offY)*3*dx + 3*(i + offX) + 2] = palette[color].blue; 191 } 192 } 193 return true; 194 } 195 142 196 // XXX need to update bDraw APIs to pass in/out structure and avoid the local static 143 bool psImageJpegNew(const psImageJpegColormap *map, const psImage *image, const char *filename, 144 float min, float max) 197 bool psImageJpeg(const psImageJpegOptions *options, const psImage *image, bDrawBuffer *bdbuf, const char *filename) 145 198 { 146 PS_ASSERT_PTR_NON_NULL(map, false); 147 PS_ASSERT_IMAGE_NON_NULL(image, false); 148 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 149 PS_ASSERT_VECTOR_NON_NULL(map->red, false); 150 PS_ASSERT_VECTOR_NON_NULL(map->green, false); 151 PS_ASSERT_VECTOR_NON_NULL(map->blue, false); 152 PS_ASSERT_PTR_NON_NULL(filename, false); 153 PS_ASSERT_INT_POSITIVE(strlen(filename), false); 154 PS_ASSERT_FLOAT_REAL(min, false); 155 PS_ASSERT_FLOAT_REAL(max, false); 156 157 float zero, scale; 158 struct jpeg_compress_struct cinfo; 159 struct jpeg_error_mgr jerr; 160 161 long pixel; 162 JSAMPLE *jpegLine; // Points to data for current line 163 JSAMPROW jpegLineList[1]; // pointer to JSAMPLE row[s] 164 JSAMPLE *jpegImage; 165 JSAMPLE *outPix; 166 167 /* JPEG init calls */ 168 cinfo.err = jpeg_std_error (&jerr); 169 jpeg_create_compress (&cinfo); 170 171 /* open file, prep for jpeg */ 172 FILE *f = fopen(filename, "w"); 173 if (!f) { 174 psError(PS_ERR_IO, true, "failed to open %s for output\n", filename); 175 return false; 176 } 177 jpeg_stdio_dest(&cinfo, f); 178 179 /* set up color jpeg buffers */ 180 int quality = 75; 181 cinfo.image_width = image->numCols; // image width and height, in pixels 182 cinfo.image_height = image->numRows; 183 cinfo.input_components = 3; 184 cinfo.in_color_space = JCS_RGB; 185 jpeg_set_defaults (&cinfo); 186 jpeg_set_quality (&cinfo, quality, true); // limit to baseline-JPEG values 187 jpeg_start_compress (&cinfo, true); 188 189 psU8 *Rpix = map->red->data.U8; 190 psU8 *Gpix = map->green->data.U8; 191 psU8 *Bpix = map->blue->data.U8; 192 193 if (max == min) { 194 zero = min - 0.1; 195 scale = 256.0/0.2; 196 } else { 197 zero = min; 198 scale = 256.0/(max - min); 199 } 200 201 int dx = image->numCols; 202 int dy = image->numRows; 203 204 // output image buffer and line buffer 205 jpegLine = psAlloc (3*dx*sizeof(JSAMPLE)); 206 jpegImage = psAlloc (3*dx*dy*sizeof(JSAMPLE)); 207 208 // first copy the image data into the output buffer 209 for (int j = 0; j < dy; j++) { 210 psF32 *row = image->data.F32[j]; 211 212 outPix = jpegLine; 213 for (int i = 0; i < dx; i++, outPix += 3) { 214 if (isfinite(row[i])) { 215 pixel = PS_JPEG_SCALEVALUE(row[i],zero,scale); 216 outPix[0] = Rpix[pixel]; 217 outPix[1] = Gpix[pixel]; 218 outPix[2] = Bpix[pixel]; 219 } else { 220 // XXX NAN value should be set per-color map 221 outPix[0] = 0x00; 222 outPix[1] = 0xff; 223 outPix[2] = 0x00; 224 } 225 } 226 memcpy (&jpegImage[j*3*dx], jpegLine, 3*dx); 227 } 228 229 bDrawBuffer *bdbuf = bDrawBufferCreate(dx, dy); 230 bDrawSetBuffer(bdbuf); 231 bDrawColor red = KapaColorByName("red"); 232 bDrawSetStyle (red, 1, 0); 233 bDrawCircle(40.0, 20.0, 3.0); 234 235 { 236 int Npalette; 237 png_color *palette = KapaPNGPalette (&Npalette); 238 bDrawColor white = KapaColorByName ("white"); 239 for (int j = 0; j < dy; j++) { 240 for (int i = 0; i < dx; i++) { 241 bDrawColor color = bdbuf[0].pixels[j][i]; 242 if (color == white) continue; 243 jpegImage[j*3*dx + 3*i + 0] = palette[color].red; 244 jpegImage[j*3*dx + 3*i + 1] = palette[color].green; 245 jpegImage[j*3*dx + 3*i + 2] = palette[color].blue; 246 } 247 } 248 } 249 bDrawBufferFree (bdbuf); 250 251 // write out the image buffer 252 for (int j = 0; j < image->numRows; j++) { 253 jpegLineList[0] = &jpegImage[j*3*dx]; 254 if (jpeg_write_scanlines(&cinfo, jpegLineList, 1) == 0) { 255 psError(PS_ERR_IO, true, "Unable to write line %d to JPEG", j); 256 psFree(jpegLine); 257 psFree(jpegImage); 258 fclose(f); 259 return false; 260 } 261 } 262 263 jpeg_finish_compress(&cinfo); 264 if (fclose(f) == EOF) { 265 psError(PS_ERR_IO, true, "Failed to close %s", filename); 266 psFree(jpegLine); 267 psFree(jpegImage); 268 return false; 269 } 270 jpeg_destroy_compress(&cinfo); 271 199 PS_ASSERT_PTR_NON_NULL(options, false); 200 PS_ASSERT_VECTOR_NON_NULL(options->red, false); 201 PS_ASSERT_VECTOR_NON_NULL(options->green, false); 202 PS_ASSERT_VECTOR_NON_NULL(options->blue, false); 203 PS_ASSERT_FLOAT_REAL(options->min, false); 204 PS_ASSERT_FLOAT_REAL(options->max, false); 205 PS_ASSERT_IMAGE_NON_NULL(image, false); 206 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 207 PS_ASSERT_PTR_NON_NULL(filename, false); 208 PS_ASSERT_INT_POSITIVE(strlen(filename), false); 209 210 float zero, scale; 211 struct jpeg_compress_struct cinfo; 212 struct jpeg_error_mgr jerr; 213 214 long pixel; 215 JSAMPLE *jpegLine; // Points to data for current line 216 JSAMPROW jpegLineList[1]; // pointer to JSAMPLE row[s] 217 JSAMPLE *jpegImage; 218 JSAMPLE *outPix; 219 220 /* JPEG init calls */ 221 cinfo.err = jpeg_std_error (&jerr); 222 jpeg_create_compress (&cinfo); 223 224 /* open file, prep for jpeg */ 225 FILE *f = fopen(filename, "w"); 226 if (!f) { 227 psError(PS_ERR_IO, true, "failed to open %s for output\n", filename); 228 return false; 229 } 230 jpeg_stdio_dest(&cinfo, f); 231 232 /* set up color jpeg buffers */ 233 int quality = 75; 234 cinfo.image_width = image->numCols; // image width and height, in pixels 235 cinfo.image_height = image->numRows; 236 237 if (options->showScale != PS_JPEG_SHOWSCALE_NONE) { 238 cinfo.image_height += PS_JPEG_COLORPAD + PS_JPEG_LABELPAD; 239 } 240 241 cinfo.input_components = 3; 242 cinfo.in_color_space = JCS_RGB; 243 jpeg_set_defaults (&cinfo); 244 jpeg_set_quality (&cinfo, quality, true); // limit to baseline-JPEG values 245 jpeg_start_compress (&cinfo, true); 246 247 psU8 *Rpix = options->red->data.U8; 248 psU8 *Gpix = options->green->data.U8; 249 psU8 *Bpix = options->blue->data.U8; 250 251 if (options->max == options->min) { 252 zero = options->min - 0.1; 253 scale = 256.0/0.2; 254 } else { 255 zero = options->min; 256 scale = 256.0/(options->max - options->min); 257 } 258 259 // dx,dy is the size of the image itself. the drawing window may be larger 260 // by the size of the scalebar (depending on the location) 261 262 int dx = image->numCols; 263 int dy = image->numRows; 264 int Nx = cinfo.image_width; 265 int Ny = cinfo.image_height; 266 267 // output image buffer and line buffer 268 jpegLine = psAlloc (3*Nx*sizeof(JSAMPLE)); 269 jpegImage = psAlloc (3*Nx*Ny*sizeof(JSAMPLE)); 270 271 // first copy the image data into the output buffer 272 // output image ranges from offset to offset + dy 273 int offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? PS_JPEG_COLORPAD + PS_JPEG_LABELPAD : 0; 274 for (int j = 0; j < dy; j++) { 275 276 psF32 *row = options->yFlip ? image->data.F32[j] : image->data.F32[dy - j - 1]; 277 278 outPix = options->xFlip ? jpegLine + 3*(dx - 1) : jpegLine; 279 int delta = options->xFlip ? -3 : 3; 280 for (int i = 0; i < dx; i++, outPix += delta) { 281 if (isfinite(row[i])) { 282 pixel = PS_JPEG_SCALEVALUE(row[i],zero,scale); 283 outPix[0] = Rpix[pixel]; 284 outPix[1] = Gpix[pixel]; 285 outPix[2] = Bpix[pixel]; 286 } else { 287 // XXX NAN value should be set per-color map 288 outPix[0] = 0x00; 289 outPix[1] = 0xff; 290 outPix[2] = 0x00; 291 } 292 } 293 memcpy (&jpegImage[(j + offset)*3*dx], jpegLine, 3*dx); 294 } 295 296 if (options->showScale != PS_JPEG_SHOWSCALE_NONE) { 297 offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? 0 : dy; 298 zero = 0; 299 scale = 256.0 / dx; 300 for (int j = 0; j < PS_JPEG_COLORPAD; j++) { 301 outPix = jpegLine; 302 for (int i = 0; i < dx; i++, outPix += 3) { 303 pixel = PS_JPEG_SCALEVALUE(i, zero, scale); 304 outPix[0] = Rpix[pixel]; 305 outPix[1] = Gpix[pixel]; 306 outPix[2] = Bpix[pixel]; 307 } 308 memcpy (&jpegImage[(j + offset)*3*dx], jpegLine, 3*dx); 309 } 310 311 // set the LABEL region to white 312 psU8 white = options->white; 313 offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? PS_JPEG_COLORPAD : PS_JPEG_COLORPAD + dy; 314 for (int j = 0; j < PS_JPEG_LABELPAD; j++) { 315 outPix = jpegLine; 316 for (int i = 0; i < dx; i++, outPix += 3) { 317 outPix[0] = Rpix[white]; 318 outPix[1] = Gpix[white]; 319 outPix[2] = Bpix[white]; 320 } 321 memcpy (&jpegImage[(j + offset)*3*dx], jpegLine, 3*dx); 322 } 323 324 // set the scalebar labels 325 char string[64]; 326 bDrawBuffer *labels = bDrawBufferCreate(dx, PS_JPEG_LABELPAD); 327 SetRotFont ("helvetica", 8); 328 bDrawSetBuffer(labels); 329 sprintf (string, "%g", options->min); 330 bDrawRotText(2, 2, string, 2, 0.0); 331 sprintf (string, "%g", options->max); 332 bDrawRotText(dx - 2, 2, string, 0, 0.0); 333 sprintf (string, "%g", 0.5*(options->min + options->max)); 334 bDrawRotText(0.5*dx, 2, string, 1, 0.0); 335 psImageJpegOverlayDraw(jpegImage, labels, 0, offset); 336 } 337 338 if (bdbuf) { 339 offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? PS_JPEG_COLORPAD + PS_JPEG_LABELPAD : 0; 340 psImageJpegOverlayDraw(jpegImage, bdbuf, 0, offset); 341 } 342 343 // write out the image buffer 344 for (int j = 0; j < Ny; j++) { 345 jpegLineList[0] = &jpegImage[j*3*dx]; 346 if (jpeg_write_scanlines(&cinfo, jpegLineList, 1) == 0) { 347 psError(PS_ERR_IO, true, "Unable to write line %d to JPEG", j); 348 psFree(jpegLine); 349 psFree(jpegImage); 350 fclose(f); 351 return false; 352 } 353 } 354 355 jpeg_finish_compress(&cinfo); 356 if (fclose(f) == EOF) { 357 psError(PS_ERR_IO, true, "Failed to close %s", filename); 272 358 psFree(jpegLine); 273 359 psFree(jpegImage); 274 return true; 275 } 276 # endif 277 278 bool psImageJpeg(const psImageJpegColormap *map, const psImage *image, const char *filename, 279 float min, float max) 280 { 281 PS_ASSERT_PTR_NON_NULL(map, false); 282 PS_ASSERT_IMAGE_NON_NULL(image, false); 283 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 284 PS_ASSERT_VECTOR_NON_NULL(map->red, false); 285 PS_ASSERT_VECTOR_NON_NULL(map->green, false); 286 PS_ASSERT_VECTOR_NON_NULL(map->blue, false); 287 PS_ASSERT_PTR_NON_NULL(filename, false); 288 PS_ASSERT_INT_POSITIVE(strlen(filename), false); 289 PS_ASSERT_FLOAT_REAL(min, false); 290 PS_ASSERT_FLOAT_REAL(max, false); 291 292 float zero, scale; 293 struct jpeg_compress_struct cinfo; 294 struct jpeg_error_mgr jerr; 295 296 long pixel; 297 JSAMPLE *jpegLine; // Points to data for current line 298 JSAMPROW jpegLineList[1]; // pointer to JSAMPLE row[s] 299 JSAMPLE *outPix; 300 301 /* JPEG init calls */ 302 cinfo.err = jpeg_std_error (&jerr); 303 jpeg_create_compress (&cinfo); 304 305 /* open file, prep for jpeg */ 306 FILE *f = fopen(filename, "w"); 307 if (!f) { 308 psError(PS_ERR_IO, true, "failed to open %s for output\n", filename); 309 return false; 310 } 311 jpeg_stdio_dest(&cinfo, f); 312 313 /* set up color jpeg buffers */ 314 int quality = 75; 315 cinfo.image_width = image->numCols; // image width and height, in pixels 316 cinfo.image_height = image->numRows; 317 cinfo.input_components = 3; 318 cinfo.in_color_space = JCS_RGB; 319 jpeg_set_defaults (&cinfo); 320 jpeg_set_quality (&cinfo, quality, true); // limit to baseline-JPEG values 321 jpeg_start_compress (&cinfo, true); 322 323 jpegLine = psAlloc (3*image->numCols*sizeof(JSAMPLE)); 324 jpegLineList[0] = jpegLine; 325 326 psU8 *Rpix = map->red->data.U8; 327 psU8 *Gpix = map->green->data.U8; 328 psU8 *Bpix = map->blue->data.U8; 329 330 if (max == min) { 331 zero = min - 0.1; 332 scale = 256.0/0.2; 333 } else { 334 zero = min; 335 scale = 256.0/(max - min); 336 } 337 338 for (int j = 0; j < image->numRows; j++) { 339 psF32 *row = image->data.F32[j]; 340 341 outPix = jpegLine; 342 for (int i = 0; i < image->numCols; i++, outPix += 3) { 343 if (isfinite(row[i])) { 344 pixel = PS_JPEG_SCALEVALUE(row[i],zero,scale); 345 outPix[0] = Rpix[pixel]; 346 outPix[1] = Gpix[pixel]; 347 outPix[2] = Bpix[pixel]; 348 } else { 349 // XXX NAN value should be set per-color map 350 outPix[0] = 0xff; 351 outPix[1] = 0x00; 352 outPix[2] = 0xff; 353 } 354 } 355 if (jpeg_write_scanlines(&cinfo, jpegLineList, 1) == 0) { 356 psError(PS_ERR_IO, true, "Unable to write line %d to JPEG", j); 357 psFree(jpegLine); 358 return false; 359 } 360 } 361 362 jpeg_finish_compress(&cinfo); 363 if (fclose(f) == EOF) { 364 psError(PS_ERR_IO, true, "Failed to close %s", filename); 365 psFree(jpegLine); 366 return false; 367 } 368 jpeg_destroy_compress(&cinfo); 369 370 psFree(jpegLine); 371 372 return true; 373 } 360 return false; 361 } 362 jpeg_destroy_compress(&cinfo); 363 364 psFree(jpegLine); 365 psFree(jpegImage); 366 return true; 367 }
Note:
See TracChangeset
for help on using the changeset viewer.
