Changeset 29542 for trunk/psLib/src/jpeg/psImageJpeg.c
- Timestamp:
- Oct 25, 2010, 12:54:22 PM (16 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/jpeg/psImageJpeg.c (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/jpeg/psImageJpeg.c
r28998 r29542 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 52 psImageJpegOptions *options = psAlloc(sizeof(psImageJpegOptions)); 53 psMemSetDeallocator(options, (psFreeFunc)imageJpegOptionsFree); 54 55 options->red = psVectorAlloc(256, PS_TYPE_U8); 56 options->blue = psVectorAlloc(256, PS_TYPE_U8); 57 options->green = psVectorAlloc(256, PS_TYPE_U8); 58 59 options->min = 0.0; 60 options->max = 1000.0; 61 62 options->xFlip = false; 63 options->yFlip = false; 64 options->showScale = PS_JPEG_SHOWSCALE_BOTTOM; 65 66 psImageJpegColormapSet(options, "greyscale"); 67 68 return options; 69 } 70 71 bool psImageJpegColormapSet(psImageJpegOptions *options, const char *name) 51 72 { 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?) 73 PS_ASSERT_PTR_NON_NULL(options, false); 74 75 /* grayscale */ 76 if ((!strcasecmp (name, "grayscale")) || (!strcasecmp (name, "greyscale"))) { 77 for (int i = 0; i < options->red->n; i++) { 78 options->red->data.U8[i] = PS_JPEG_RANGELIM(i); 79 options->green->data.U8[i] = PS_JPEG_RANGELIM(i); 80 options->blue->data.U8[i] = PS_JPEG_RANGELIM(i); 81 } 82 options->white = 255; 83 options->black = 0; 84 return options; 85 } 86 87 /* -grayscale */ 88 if ((!strcasecmp (name, "-grayscale")) || (!strcasecmp (name, "-greyscale"))) { 89 for (int i = 0; i < options->red->n; i++) { 90 options->red->data.U8[i] = PS_JPEG_RANGELIM(256 - i); 91 options->green->data.U8[i] = PS_JPEG_RANGELIM(256 - i); 92 options->blue->data.U8[i] = PS_JPEG_RANGELIM(256 - i); 93 } 94 options->white = 0; 95 options->black = 255; 96 return options; 97 } 98 99 /* rainbow */ 100 if (!strcasecmp (name, "rainbow")) { 101 int I1 = 0.25*options->red->n; 102 int I2 = 0.50*options->red->n; 103 int I3 = 0.75*options->red->n; 104 for (int i = 0; i < I1; i++) { 105 options->red->data.U8[i] = 0; 106 options->green->data.U8[i] = 0; 107 options->blue->data.U8[i] = PS_JPEG_RANGELIM(4*i); 108 } 109 for (int i = I1; i < I2; i++) { 110 options->red->data.U8[i] = PS_JPEG_RANGELIM(4*(i - I1)); 111 options->green->data.U8[i] = 0; 112 options->blue->data.U8[i] = PS_JPEG_RANGELIM(4*(I2 - i)); 113 } 114 for (int i = I2; i < I3; i++) { 115 options->red->data.U8[i] = 255; 116 options->green->data.U8[i] = 4*(i - I2); 117 options->blue->data.U8[i] = 0; 118 } 119 for (int i = I3; i < options->red->n; i++) { 120 options->red->data.U8[i] = 255; 121 options->green->data.U8[i] = 255; 122 options->blue->data.U8[i] = PS_JPEG_RANGELIM(4*(i - I3)); 123 } 124 options->white = 255; 125 options->black = 0; 126 return options; 127 } 128 129 /* heat */ 130 if (!strcasecmp (name, "heat")) { 131 int I1 = 0.25*options->red->n; 132 int I2 = 0.50*options->red->n; 133 int I3 = 0.75*options->red->n; 134 for (int i = 0; i < I1; i++) { 135 options->red->data.U8[i] = PS_JPEG_RANGELIM(2*i); 136 options->green->data.U8[i] = 0; 137 options->blue->data.U8[i] = 0; 138 } 139 for (int i = I1; i < I2; i++) { 140 options->red->data.U8[i] = PS_JPEG_RANGELIM(2*i); 141 options->green->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I1)); 142 options->blue->data.U8[i] = 0; 143 } 144 for (int i = I2; i < I3; i++) { 145 options->red->data.U8[i] = 255; 146 options->green->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I1)); 147 options->blue->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I2)); 148 } 149 for (int i = I3; i < options->red->n; i++) { 150 options->red->data.U8[i] = 255; 151 options->green->data.U8[i] = 255; 152 options->blue->data.U8[i] = PS_JPEG_RANGELIM(2*(i - I2)); 153 } 154 options->white = 255; 155 options->black = 0; 156 return options; 157 } 158 159 // invalid colormap: warn user 160 psWarning("Invalid colormap name: %s --- using greyscale\n", name); 161 return psImageJpegColormapSet (options, "greyscale"); 162 } 163 164 bDrawBuffer *psImageJpegOverlayInit (const psImage *image) { 165 166 int dx = image->numCols; 167 int dy = image->numRows; 168 169 bDrawBuffer *bdbuf = bDrawBufferCreate(dx, dy); 170 171 return bdbuf; 172 } 173 174 // copy the buffer pixels which are not white (probably should be "not blank") 175 bool psImageJpegOverlayDraw (JSAMPLE *jpegImage, bDrawBuffer *bdbuf, int offX, int offY) { 176 177 // XXX check valid limits 178 179 int dx = bdbuf->Nx; 180 int dy = bdbuf->Ny; 181 182 int Npalette; 183 png_color *palette = KapaPNGPalette (&Npalette); 184 bDrawColor white = KapaColorByName ("white"); 185 for (int j = 0; j < dy; j++) { 186 for (int i = 0; i < dx; i++) { 187 bDrawColor color = bdbuf->pixels[j][i]; 188 if (color == white) continue; 189 jpegImage[(j + offY)*3*dx + 3*(i + offX) + 0] = palette[color].red; 190 jpegImage[(j + offY)*3*dx + 3*(i + offX) + 1] = palette[color].green; 191 jpegImage[(j + offY)*3*dx + 3*(i + offX) + 2] = palette[color].blue; 192 } 193 } 194 return true; 195 } 196 197 bool sprint_double (char *string, double value) { 198 199 int Nexp = fabs(log10(fabs(value))); 200 201 if (Nexp > 3) { 202 sprintf (string, "%.1e", value); 203 } else { 204 sprintf (string, "%.1f", value); 205 } 206 return true; 207 } 208 142 209 // 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) 210 bool psImageJpeg(const psImageJpegOptions *options, const psImage *image, bDrawBuffer *bdbuf, const char *filename) 145 211 { 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 212 PS_ASSERT_PTR_NON_NULL(options, false); 213 PS_ASSERT_VECTOR_NON_NULL(options->red, false); 214 PS_ASSERT_VECTOR_NON_NULL(options->green, false); 215 PS_ASSERT_VECTOR_NON_NULL(options->blue, false); 216 PS_ASSERT_FLOAT_REAL(options->min, false); 217 PS_ASSERT_FLOAT_REAL(options->max, false); 218 PS_ASSERT_IMAGE_NON_NULL(image, false); 219 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 220 PS_ASSERT_PTR_NON_NULL(filename, false); 221 PS_ASSERT_INT_POSITIVE(strlen(filename), false); 222 223 float zero, scale; 224 struct jpeg_compress_struct cinfo; 225 struct jpeg_error_mgr jerr; 226 227 long pixel; 228 JSAMPLE *jpegLine; // Points to data for current line 229 JSAMPROW jpegLineList[1]; // pointer to JSAMPLE row[s] 230 JSAMPLE *jpegImage; 231 JSAMPLE *outPix; 232 233 /* JPEG init calls */ 234 cinfo.err = jpeg_std_error (&jerr); 235 jpeg_create_compress (&cinfo); 236 237 /* open file, prep for jpeg */ 238 FILE *f = fopen(filename, "w"); 239 if (!f) { 240 psError(PS_ERR_IO, true, "failed to open %s for output\n", filename); 241 return false; 242 } 243 jpeg_stdio_dest(&cinfo, f); 244 245 /* set up color jpeg buffers */ 246 int quality = 75; 247 cinfo.image_width = image->numCols; // image width and height, in pixels 248 cinfo.image_height = image->numRows; 249 250 if (options->showScale != PS_JPEG_SHOWSCALE_NONE) { 251 cinfo.image_height += PS_JPEG_COLORPAD + PS_JPEG_LABELPAD; 252 } 253 254 cinfo.input_components = 3; 255 cinfo.in_color_space = JCS_RGB; 256 jpeg_set_defaults (&cinfo); 257 jpeg_set_quality (&cinfo, quality, true); // limit to baseline-JPEG values 258 jpeg_start_compress (&cinfo, true); 259 260 psU8 *Rpix = options->red->data.U8; 261 psU8 *Gpix = options->green->data.U8; 262 psU8 *Bpix = options->blue->data.U8; 263 264 if (options->max == options->min) { 265 zero = options->min - 0.1; 266 scale = 256.0/0.2; 267 } else { 268 zero = options->min; 269 scale = 256.0/(options->max - options->min); 270 } 271 272 // dx,dy is the size of the image itself. the drawing window may be larger 273 // by the size of the scalebar (depending on the location) 274 275 int dx = image->numCols; 276 int dy = image->numRows; 277 int Nx = cinfo.image_width; 278 int Ny = cinfo.image_height; 279 280 // output image buffer and line buffer 281 jpegLine = psAlloc (3*Nx*sizeof(JSAMPLE)); 282 jpegImage = psAlloc (3*Nx*Ny*sizeof(JSAMPLE)); 283 284 // first copy the image data into the output buffer 285 // output image ranges from offset to offset + dy 286 int offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? PS_JPEG_COLORPAD + PS_JPEG_LABELPAD : 0; 287 for (int j = 0; j < dy; j++) { 288 289 psF32 *row = options->yFlip ? image->data.F32[j] : image->data.F32[dy - j - 1]; 290 291 outPix = options->xFlip ? jpegLine + 3*(dx - 1) : jpegLine; 292 int delta = options->xFlip ? -3 : 3; 293 for (int i = 0; i < dx; i++, outPix += delta) { 294 if (isfinite(row[i])) { 295 pixel = PS_JPEG_SCALEVALUE(row[i],zero,scale); 296 outPix[0] = Rpix[pixel]; 297 outPix[1] = Gpix[pixel]; 298 outPix[2] = Bpix[pixel]; 299 } else { 300 // XXX NAN value should be set per-color map 301 outPix[0] = 0x00; 302 outPix[1] = 0xff; 303 outPix[2] = 0x00; 304 } 305 } 306 memcpy (&jpegImage[(j + offset)*3*dx], jpegLine, 3*dx); 307 } 308 309 if (options->showScale != PS_JPEG_SHOWSCALE_NONE) { 310 offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? 0 : dy; 311 zero = 0; 312 scale = 256.0 / dx; 313 for (int j = 0; j < PS_JPEG_COLORPAD; j++) { 314 outPix = jpegLine; 315 for (int i = 0; i < dx; i++, outPix += 3) { 316 pixel = PS_JPEG_SCALEVALUE(i, zero, scale); 317 outPix[0] = Rpix[pixel]; 318 outPix[1] = Gpix[pixel]; 319 outPix[2] = Bpix[pixel]; 320 } 321 memcpy (&jpegImage[(j + offset)*3*dx], jpegLine, 3*dx); 322 } 323 324 // set the LABEL region to white 325 psU8 white = options->white; 326 offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? PS_JPEG_COLORPAD : PS_JPEG_COLORPAD + dy; 327 for (int j = 0; j < PS_JPEG_LABELPAD; j++) { 328 outPix = jpegLine; 329 for (int i = 0; i < dx; i++, outPix += 3) { 330 outPix[0] = Rpix[white]; 331 outPix[1] = Gpix[white]; 332 outPix[2] = Bpix[white]; 333 } 334 memcpy (&jpegImage[(j + offset)*3*dx], jpegLine, 3*dx); 335 } 336 337 // set the scalebar labels 338 char string[64]; 339 bDrawBuffer *labels = bDrawBufferCreate(dx, PS_JPEG_LABELPAD); 340 SetRotFont ("helvetica", 8); 341 bDrawSetBuffer(labels); 342 sprint_double (string, options->min); 343 bDrawRotText(2, 2, string, 2, 0.0); 344 sprint_double (string, options->max); 345 bDrawRotText(dx - 2, 2, string, 0, 0.0); 346 sprint_double (string, 0.5*(options->min + options->max)); 347 bDrawRotText(0.5*dx, 2, string, 1, 0.0); 348 psImageJpegOverlayDraw(jpegImage, labels, 0, offset); 349 } 350 351 if (bdbuf) { 352 offset = (options->showScale == PS_JPEG_SHOWSCALE_TOP) ? PS_JPEG_COLORPAD + PS_JPEG_LABELPAD : 0; 353 psImageJpegOverlayDraw(jpegImage, bdbuf, 0, offset); 354 } 355 356 // write out the image buffer 357 for (int j = 0; j < Ny; j++) { 358 jpegLineList[0] = &jpegImage[j*3*dx]; 359 if (jpeg_write_scanlines(&cinfo, jpegLineList, 1) == 0) { 360 psError(PS_ERR_IO, true, "Unable to write line %d to JPEG", j); 361 psFree(jpegLine); 362 psFree(jpegImage); 363 fclose(f); 364 return false; 365 } 366 } 367 368 jpeg_finish_compress(&cinfo); 369 if (fclose(f) == EOF) { 370 psError(PS_ERR_IO, true, "Failed to close %s", filename); 272 371 psFree(jpegLine); 273 372 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 } 373 return false; 374 } 375 jpeg_destroy_compress(&cinfo); 376 377 psFree(jpegLine); 378 psFree(jpegImage); 379 return true; 380 }
Note:
See TracChangeset
for help on using the changeset viewer.
