IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Oct 4, 2010, 2:47:01 PM (16 years ago)
Author:
eugene
Message:

some rework on the jpeg functions to allow for overlays and a scale bar with labels (psLib now requires libkapa)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branches/ipp-20100823/psLib/src/jpeg/psImageJpeg.c

    r28998 r29309  
    1515#include "psImageJpeg.h"
    1616
     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
    1721#ifdef HAVE_STDLIB_H
    1822// jpeglib.h includes jconfig.h which is full of autoconf generated HAVE_*
    1923// defines. This is a hack to work around CPP redefinition errors.  Arrrrrgh!!!
    2024// -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
    2132# undef HAVE_STDLIB_H
    2233# include <jpeglib.h>
    2334#endif // ifdef HAVE_STDLIB_H
    2435
    25 static void imageJpegColormapFree(psImageJpegColormap *map)
     36static void imageJpegOptionsFree(psImageJpegOptions *options)
    2637{
    2738
    28     if (!map) {
    29         return;
    30     }
    31 
    32     psFree(map->red);
    33     psFree(map->green);
    34     psFree(map->blue);
     39  if (!options) {
    3540    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
     49psImageJpegOptions *psImageJpegOptionsAlloc(void)
    3950{
    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
     70bool psImageJpegColormapSet(psImageJpegOptions *options, const char *name)
    5171{
    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
     163bDrawBuffer *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")
     174bool 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
    142196// 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)
     197bool psImageJpeg(const psImageJpegOptions *options, const psImage *image, bDrawBuffer *bdbuf, const char *filename)
    145198{
    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);
    272358    psFree(jpegLine);
    273359    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.