IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Oct 25, 2010, 12:54:22 PM (16 years ago)
Author:
eugene
Message:

merge changes from eam_branches/ipp-20100823

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/jpeg/psImageJpeg.c

    r28998 r29542  
    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
     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
     71bool psImageJpegColormapSet(psImageJpegOptions *options, const char *name)
    5172{
    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
     164bDrawBuffer *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")
     175bool 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
     197bool 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
    142209// 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)
     210bool psImageJpeg(const psImageJpegOptions *options, const psImage *image, bDrawBuffer *bdbuf, const char *filename)
    145211{
    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);
    272371    psFree(jpegLine);
    273372    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.