예제 #1
0
int dt_imageio_jpeg_write_with_icc_profile(const char *filename, const uint8_t *in, const int width,
                                           const int height, const int quality, const void *exif, int exif_len,
                                           int imgid)
{
  struct dt_imageio_jpeg_error_mgr jerr;
  dt_imageio_jpeg_t jpg;

  jpg.cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = dt_imageio_jpeg_error_exit;
  if(setjmp(jerr.setjmp_buffer))
  {
    jpeg_destroy_compress(&(jpg.cinfo));
    return 1;
  }
  jpeg_create_compress(&(jpg.cinfo));
  FILE *f = fopen(filename, "wb");
  if(!f) return 1;
  jpeg_stdio_dest(&(jpg.cinfo), f);

  jpg.cinfo.image_width = width;
  jpg.cinfo.image_height = height;
  jpg.cinfo.input_components = 3;
  jpg.cinfo.in_color_space = JCS_RGB;
  jpeg_set_defaults(&(jpg.cinfo));
  jpeg_set_quality(&(jpg.cinfo), quality, TRUE);
  if(quality > 90) jpg.cinfo.comp_info[0].v_samp_factor = 1;
  if(quality > 92) jpg.cinfo.comp_info[0].h_samp_factor = 1;
  jpeg_start_compress(&(jpg.cinfo), TRUE);

  if(imgid > 0)
  {
    cmsHPROFILE out_profile = dt_colorspaces_get_output_profile(imgid)->profile;
    uint32_t len = 0;
    cmsSaveProfileToMem(out_profile, 0, &len);
    if(len > 0)
    {
      unsigned char buf[len];
      cmsSaveProfileToMem(out_profile, buf, &len);
      write_icc_profile(&(jpg.cinfo), buf, len);
    }
  }

  if(exif && exif_len > 0 && exif_len < 65534) jpeg_write_marker(&(jpg.cinfo), JPEG_APP0 + 1, exif, exif_len);

  uint8_t row[3 * width];
  const uint8_t *buf;
  while(jpg.cinfo.next_scanline < jpg.cinfo.image_height)
  {
    JSAMPROW tmp[1];
    buf = in + jpg.cinfo.next_scanline * jpg.cinfo.image_width * 4;
    for(int i = 0; i < width; i++)
      for(int k = 0; k < 3; k++) row[3 * i + k] = buf[4 * i + k];
    tmp[0] = row;
    jpeg_write_scanlines(&(jpg.cinfo), tmp, 1);
  }
  jpeg_finish_compress(&(jpg.cinfo));
  jpeg_destroy_compress(&(jpg.cinfo));
  fclose(f);
  return 0;
}
예제 #2
0
파일: gimplcms.c 프로젝트: STRNG/gimp
guint8 *
gimp_lcms_profile_save_to_data (GimpColorProfile   profile,
                                gsize             *length,
                                GError           **error)
{
  cmsUInt32Number size;

  g_return_val_if_fail (profile != NULL, NULL);
  g_return_val_if_fail (length != NULL, NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  if (cmsSaveProfileToMem (profile, NULL, &size))
    {
      guint8 *data = g_malloc (size);

      if (cmsSaveProfileToMem (profile, data, &size))
        {
          *length = size;

          return data;
        }

      g_free (data);
    }

  g_set_error_literal (error, gimp_lcms_error_quark (), 0,
                       _("Could not save color profile to memory"));

  return NULL;
}
예제 #3
0
cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
{
  cmsUInt32Number pfSize = 0;
  cmsUInt8Number* pfBuffer = NULL;
  cmsBool status = FALSE;

  if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||
      pfSize < sizeof(cmsICCHeader) ||
      bufferSize < sizeof(cmsICCHeader))
  {
    return FALSE;
  }

  pfBuffer = malloc(pfSize);
  if (pfBuffer == NULL) {
    return FALSE;
  }

  // load raw profile data into the buffer
  if (cmsSaveProfileToMem(pf, pfBuffer, &pfSize)) {
    memcpy(pBuffer, pfBuffer, sizeof(cmsICCHeader));
    status = TRUE;
  }
  free(pfBuffer);
  return status;
}
예제 #4
0
QByteArray LcmsColorProfileContainer::lcmsProfileToByteArray(const cmsHPROFILE profile)
{
    cmsUInt32Number  bytesNeeded = 0;
    // Make a raw data image ready for saving
    cmsSaveProfileToMem(profile, 0, &bytesNeeded); // calc size
    QByteArray rawData;
    rawData.resize(bytesNeeded);
    if (rawData.size() >= (int)bytesNeeded) {
        cmsSaveProfileToMem(profile, rawData.data(), &bytesNeeded); // fill buffer
    } else {
        qWarning() << "Couldn't resize the profile buffer, system is probably running out of memory.";
        rawData.resize(0);
    }
    return rawData;
}
예제 #5
0
파일: colorout.c 프로젝트: dtorop/darktable
static cmsHPROFILE _make_clipping_profile(cmsHPROFILE profile)
{
  cmsUInt32Number size;
  cmsHPROFILE old_profile = profile;
  profile = NULL;

  if(old_profile && cmsSaveProfileToMem(old_profile, NULL, &size))
  {
    char *data = malloc(size);

    if(cmsSaveProfileToMem(old_profile, data, &size))
      profile = cmsOpenProfileFromMem(data, size);

    free(data);
  }

  return profile;
}
예제 #6
0
/**
 * gimp_color_profile_new_from_lcms_profile:
 * @lcms_profile: an LCMS cmsHPROFILE pointer
 * @error:        return location for #GError
 *
 * This function creates a GimpColorProfile from a cmsHPROFILE. On
 * error, %NULL is returned and @error is set. The passed
 * @lcms_profile pointer is not retained by the created
 * #GimpColorProfile.
 *
 * Return value: the #GimpColorProfile, or %NULL.
 *
 * Since: 2.10
 **/
GimpColorProfile *
gimp_color_profile_new_from_lcms_profile (gpointer   lcms_profile,
                                          GError   **error)
{
  cmsUInt32Number size;

  g_return_val_if_fail (lcms_profile != NULL, NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  if (cmsSaveProfileToMem (lcms_profile, NULL, &size))
    {
      guint8 *data = g_malloc (size);

      if (cmsSaveProfileToMem (lcms_profile, data, &size))
        {
          gsize length = size;

          lcms_profile = cmsOpenProfileFromMem (data, length);

          if (lcms_profile)
            {
              GimpColorProfile *profile;

              profile = g_object_new (GIMP_TYPE_COLOR_PROFILE, NULL);

              profile->priv->lcms_profile = lcms_profile;
              profile->priv->data         = data;
              profile->priv->length       = length;

              return profile;
            }
        }

      g_free (data);
    }

  g_set_error_literal (error, gimp_color_profile_error_quark (), 0,
                       _("Could not save color profile to memory"));

  return NULL;
}
예제 #7
0
/*
 * Class:     sun_java2d_cmm_lcms_LCMS
 * Method:    getProfileData
 * Signature: (J[B)V
 */
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData
  (JNIEnv *env, jobject obj, jlong id, jbyteArray data)
{
    storeID_t sProf;
    jint size;
    jbyte* dataArray;
    cmsUInt32Number pfSize = 0;
    cmsBool status;

    sProf.j = id;

    // determine actual profile size
    if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize)) {
        JNU_ThrowByName(env, "java/awt/color/CMMException",
                        "Can not access specified profile.");
        return;
    }

    // verify java buffer capacity
    size = (*env)->GetArrayLength(env, data);
    if (0 >= size || pfSize > (cmsUInt32Number)size) {
        JNU_ThrowByName(env, "java/awt/color/CMMException",
                        "Insufficient buffer capacity.");
        return;
    }

    dataArray = (*env)->GetByteArrayElements (env, data, 0);

    status = cmsSaveProfileToMem(sProf.pf, dataArray, &pfSize);

    (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);

    if (!status) {
        JNU_ThrowByName(env, "java/awt/color/CMMException",
                        "Can not access specified profile.");
        return;
    }
}
예제 #8
0
/*
 * Class:     sun_java2d_cmm_lcms_LCMS
 * Method:    getProfileSize
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSize
  (JNIEnv *env, jobject obj, jlong id)
{
    storeID_t sProf;
    cmsUInt32Number pfSize = 0;
    sProf.j = id;

    if (cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) && ((jint)pfSize > 0)) {
        return (jint)pfSize;
    } else {
      JNU_ThrowByName(env, "java/awt/color/CMMException",
                      "Can not access specified profile.");
        return -1;
    }
}
예제 #9
0
int write_image(dt_imageio_module_data_t *jpg_tmp, const char *filename, const void *in_tmp, void *exif,
                int exif_len, int imgid)
{
  dt_imageio_jpeg_t *jpg = (dt_imageio_jpeg_t *)jpg_tmp;
  const uint8_t *in = (const uint8_t *)in_tmp;
  struct dt_imageio_jpeg_error_mgr jerr;

  jpg->cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = dt_imageio_jpeg_error_exit;
  if(setjmp(jerr.setjmp_buffer))
  {
    jpeg_destroy_compress(&(jpg->cinfo));
    return 1;
  }
  jpeg_create_compress(&(jpg->cinfo));
  FILE *f = fopen(filename, "wb");
  if(!f) return 1;
  jpeg_stdio_dest(&(jpg->cinfo), f);

  jpg->cinfo.image_width = jpg->width;
  jpg->cinfo.image_height = jpg->height;
  jpg->cinfo.input_components = 3;
  jpg->cinfo.in_color_space = JCS_RGB;
  jpeg_set_defaults(&(jpg->cinfo));
  jpeg_set_quality(&(jpg->cinfo), jpg->quality, TRUE);
  if(jpg->quality > 90) jpg->cinfo.comp_info[0].v_samp_factor = 1;
  if(jpg->quality > 92) jpg->cinfo.comp_info[0].h_samp_factor = 1;
  if(jpg->quality > 95) jpg->cinfo.dct_method = JDCT_FLOAT;
  if(jpg->quality < 50) jpg->cinfo.dct_method = JDCT_IFAST;
  if(jpg->quality < 80) jpg->cinfo.smoothing_factor = 20;
  if(jpg->quality < 60) jpg->cinfo.smoothing_factor = 40;
  if(jpg->quality < 40) jpg->cinfo.smoothing_factor = 60;
  jpg->cinfo.optimize_coding = 1;

  // according to specs density_unit = 0, X_density = 1, Y_density = 1 should be fine and valid since it
  // describes an image with unknown unit and square pixels.
  // however, some applications (like the Telekom cloud thingy) seem to be confused by that, so let's set
  // these calues to the same as stored in exiv :/
  int resolution = dt_conf_get_int("metadata/resolution");
  if(resolution > 0)
  {
    jpg->cinfo.density_unit = 1;
    jpg->cinfo.X_density = resolution;
    jpg->cinfo.Y_density = resolution;
  }
  else
  {
    jpg->cinfo.density_unit = 0;
    jpg->cinfo.X_density = 1;
    jpg->cinfo.Y_density = 1;
  }

  jpeg_start_compress(&(jpg->cinfo), TRUE);

  if(imgid > 0)
  {
    cmsHPROFILE out_profile = dt_colorspaces_create_output_profile(imgid);
    uint32_t len = 0;
    cmsSaveProfileToMem(out_profile, 0, &len);
    if(len > 0)
    {
      unsigned char buf[len];
      cmsSaveProfileToMem(out_profile, buf, &len);
      write_icc_profile(&(jpg->cinfo), buf, len);
    }
    dt_colorspaces_cleanup_profile(out_profile);
  }

  if(exif && exif_len > 0 && exif_len < 65534)
    jpeg_write_marker(&(jpg->cinfo), JPEG_APP0 + 1, exif, exif_len);

  uint8_t row[3 * jpg->width];
  const uint8_t *buf;
  while(jpg->cinfo.next_scanline < jpg->cinfo.image_height)
  {
    JSAMPROW tmp[1];
    buf = in + (size_t)jpg->cinfo.next_scanline * jpg->cinfo.image_width * 4;
    for(int i = 0; i < jpg->width; i++)
      for(int k = 0; k < 3; k++) row[3 * i + k] = buf[4 * i + k];
    tmp[0] = row;
    jpeg_write_scanlines(&(jpg->cinfo), tmp, 1);
  }
  jpeg_finish_compress(&(jpg->cinfo));
  jpeg_destroy_compress(&(jpg->cinfo));
  fclose(f);
  return 0;
}
예제 #10
0
파일: tiff.c 프로젝트: AntonSh/darktable
int write_image (dt_imageio_tiff_t *d, const char *filename, const void *in_void, void *exif, int exif_len, int imgid)
{
  // Fetch colorprofile into buffer if wanted
  uint8_t *profile = NULL;
  uint32_t profile_len = 0;
  int rc = 0;

  if(imgid > 0)
  {
    cmsHPROFILE out_profile = dt_colorspaces_create_output_profile(imgid);
    cmsSaveProfileToMem(out_profile, 0, &profile_len);
    if (profile_len > 0)
    {
      profile=malloc(profile_len);
      cmsSaveProfileToMem(out_profile, profile, &profile_len);
    }
    dt_colorspaces_cleanup_profile(out_profile);
  }

  // Create tiff image
  TIFF *tif=TIFFOpen(filename,"wb");
  if(d->bpp == 8) TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
  else            TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
  TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
  if(profile!=NULL)
    TIFFSetField(tif, TIFFTAG_ICCPROFILE, profile_len, profile);
  TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, d->width);
  TIFFSetField(tif, TIFFTAG_IMAGELENGTH, d->height);
  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
  TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  TIFFSetField(tif, TIFFTAG_PREDICTOR, 1);		// Reference www.awaresystems.be/imaging/tiff/tifftags/predictor.html
  TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
  TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, DT_TIFFIO_STRIPE);
  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
  TIFFSetField(tif, TIFFTAG_XRESOLUTION, 300.0);
  TIFFSetField(tif, TIFFTAG_YRESOLUTION, 300.0);
  TIFFSetField(tif, TIFFTAG_ZIPQUALITY, 9);

  const uint8_t  *in8 =(const uint8_t  *)in_void;
  const uint16_t *in16=(const uint16_t *)in_void;
  if(d->bpp == 16)
  {
    uint32_t rowsize=(d->width*3)*sizeof(uint16_t);
    uint32_t stripesize=rowsize*DT_TIFFIO_STRIPE;
    uint16_t *rowdata = (uint16_t *)malloc(stripesize);
    uint16_t *wdata = rowdata;
    uint32_t stripe=0;
    // uint32_t insize=((d->width*d->height)*3)*sizeof(uint16_t);
    // while(stripedata<(in8+insize)-(stripesize)) {
    // TIFFWriteEncodedStrip(tif,stripe++,stripedata,stripesize);
    // stripedata+=stripesize;
    // }
    for (int y = 0; y < d->height; y++)
    {
      for(int x=0; x<d->width; x++)
        for(int k=0; k<3; k++)
        {
          (wdata)[0] = in16[4*d->width*y + 4*x + k];
          wdata++;
        }
      if((wdata-stripesize/sizeof(uint16_t))==rowdata)
      {
        TIFFWriteEncodedStrip(tif,stripe++,rowdata,rowsize*DT_TIFFIO_STRIPE);
        wdata=rowdata;
      }
    }
    if((wdata-stripesize/sizeof(uint16_t))!=rowdata)
      TIFFWriteEncodedStrip(tif,stripe,rowdata,(wdata-rowdata)*sizeof(uint16_t));
    TIFFClose(tif);
    free(rowdata);
  }
  else
  {
    uint32_t rowsize=(d->width*3)*sizeof(uint8_t);
    uint32_t stripesize=rowsize*DT_TIFFIO_STRIPE;
    uint8_t *rowdata = (uint8_t *)malloc(stripesize);
    uint8_t *wdata = rowdata;
    uint32_t stripe=0;

    for (int y = 0; y < d->height; y++)
    {
      for(int x=0; x<d->width; x++)
        for(int k=0; k<3; k++)
        {
          (wdata)[0] = in8[4*d->width*y + 4*x + k];
          wdata++;
        }
      if((wdata-stripesize)==rowdata)
      {
        TIFFWriteEncodedStrip(tif,stripe++,rowdata,rowsize*DT_TIFFIO_STRIPE);
        wdata=rowdata;
      }
    }
    if((wdata-stripesize)!=rowdata)
      TIFFWriteEncodedStrip(tif,stripe,rowdata,wdata-rowdata);
    TIFFClose(tif);
    free(rowdata);
  }

  if(exif)
    rc = dt_exif_write_blob(exif,exif_len,filename);

  free(profile);

  /*
   * Until we get symbolic error status codes, if rc is 1, return 0.
   */
  return ((rc == 1) ? 0 : 1);
}
예제 #11
0
파일: jpeg.c 프로젝트: Coshibu/darktable
int
write_image (dt_imageio_module_data_t *jpg_tmp, const char *filename, const void *in_tmp, void *exif, int exif_len, int imgid)
{
  dt_imageio_jpeg_t *jpg = (dt_imageio_jpeg_t*)jpg_tmp;
  const uint8_t*in =(const uint8_t*)in_tmp;
  struct dt_imageio_jpeg_error_mgr jerr;

  jpg->cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = dt_imageio_jpeg_error_exit;
  if (setjmp(jerr.setjmp_buffer))
  {
    jpeg_destroy_compress(&(jpg->cinfo));
    return 1;
  }
  jpeg_create_compress(&(jpg->cinfo));
  FILE *f = fopen(filename, "wb");
  if(!f) return 1;
  jpeg_stdio_dest(&(jpg->cinfo), f);

  jpg->cinfo.image_width = jpg->width;
  jpg->cinfo.image_height = jpg->height;
  jpg->cinfo.input_components = 3;
  jpg->cinfo.in_color_space = JCS_RGB;
  jpeg_set_defaults(&(jpg->cinfo));
  jpeg_set_quality(&(jpg->cinfo), jpg->quality, TRUE);
  if(jpg->quality > 90) jpg->cinfo.comp_info[0].v_samp_factor = 1;
  if(jpg->quality > 92) jpg->cinfo.comp_info[0].h_samp_factor = 1;
  if(jpg->quality > 95) jpg->cinfo.dct_method = JDCT_FLOAT;
  if(jpg->quality < 50) jpg->cinfo.dct_method = JDCT_IFAST;
  if(jpg->quality < 80) jpg->cinfo.smoothing_factor = 20;
  if(jpg->quality < 60) jpg->cinfo.smoothing_factor = 40;
  if(jpg->quality < 40) jpg->cinfo.smoothing_factor = 60;
  jpg->cinfo.optimize_coding = 1;

  jpeg_start_compress(&(jpg->cinfo), TRUE);

  if(imgid > 0)
  {
    cmsHPROFILE out_profile = dt_colorspaces_create_output_profile(imgid);
    uint32_t len = 0;
    cmsSaveProfileToMem(out_profile, 0, &len);
    if (len > 0)
    {
      unsigned char buf[len];
      cmsSaveProfileToMem(out_profile, buf, &len);
      write_icc_profile(&(jpg->cinfo), buf, len);
    }
    dt_colorspaces_cleanup_profile(out_profile);
  }

  if(exif && exif_len > 0 && exif_len < 65534)
    jpeg_write_marker(&(jpg->cinfo), JPEG_APP0+1, exif, exif_len);

  uint8_t row[3*jpg->width];
  const uint8_t *buf;
  while(jpg->cinfo.next_scanline < jpg->cinfo.image_height)
  {
    JSAMPROW tmp[1];
    buf = in + (size_t)jpg->cinfo.next_scanline * jpg->cinfo.image_width * 4;
    for(int i=0; i<jpg->width; i++) for(int k=0; k<3; k++) row[3*i+k] = buf[4*i+k];
    tmp[0] = row;
    jpeg_write_scanlines(&(jpg->cinfo), tmp, 1);
  }
  jpeg_finish_compress (&(jpg->cinfo));
  jpeg_destroy_compress(&(jpg->cinfo));
  fclose(f);
  return 0;
}
예제 #12
0
int write_image(dt_imageio_module_data_t *d_tmp, const char *filename, const void *in_void, void *exif,
                int exif_len, int imgid)
{
  const dt_imageio_tiff_t *d = (dt_imageio_tiff_t *)d_tmp;

  uint8_t *profile = NULL;
  uint32_t profile_len = 0;

  TIFF *tif = NULL;

  void *rowdata = NULL;

  int rc = 1; // default to error

  if(imgid > 0)
  {
    cmsHPROFILE out_profile = dt_colorspaces_create_output_profile(imgid);
    cmsSaveProfileToMem(out_profile, 0, &profile_len);
    if(profile_len > 0)
    {
      profile = malloc(profile_len);
      if(!profile)
      {
        rc = 1;
        goto exit;
      }
      cmsSaveProfileToMem(out_profile, profile, &profile_len);
    }
    dt_colorspaces_cleanup_profile(out_profile);
  }

  // Create little endian tiff image
  tif = TIFFOpen(filename, "wl");
  if(!tif)
  {
    rc = 1;
    goto exit;
  }

  // http://partners.adobe.com/public/developer/en/tiff/TIFFphotoshop.pdf (dated 2002)
  // "A proprietary ZIP/Flate compression code (0x80b2) has been used by some"
  // "software vendors. This code should be considered obsolete. We recommend"
  // "that TIFF implentations recognize and read the obsolete code but only"
  // "write the official compression code (0x0008)."
  // http://www.awaresystems.be/imaging/tiff/tifftags/compression.html
  // http://www.awaresystems.be/imaging/tiff/tifftags/predictor.html
  if(d->compress == 1)
  {
    TIFFSetField(tif, TIFFTAG_COMPRESSION, (uint16_t)COMPRESSION_ADOBE_DEFLATE);
    TIFFSetField(tif, TIFFTAG_PREDICTOR, (uint16_t)1);
    TIFFSetField(tif, TIFFTAG_ZIPQUALITY, (uint16_t)9);
  }
  else if(d->compress == 2)
  {
    TIFFSetField(tif, TIFFTAG_COMPRESSION, (uint16_t)COMPRESSION_ADOBE_DEFLATE);
    TIFFSetField(tif, TIFFTAG_PREDICTOR, (uint16_t)2);
    TIFFSetField(tif, TIFFTAG_ZIPQUALITY, (uint16_t)9);
  }
  else if(d->compress == 3)
  {
    TIFFSetField(tif, TIFFTAG_COMPRESSION, (uint16_t)COMPRESSION_ADOBE_DEFLATE);
    if(d->bpp == 32)
      TIFFSetField(tif, TIFFTAG_PREDICTOR, (uint16_t)3);
    else
      TIFFSetField(tif, TIFFTAG_PREDICTOR, (uint16_t)2);
    TIFFSetField(tif, TIFFTAG_ZIPQUALITY, (uint16_t)9);
  }
  else // (d->compress == 0)
  {
    TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
  }

  TIFFSetField(tif, TIFFTAG_FILLORDER, (uint16_t)FILLORDER_MSB2LSB);
  if(profile != NULL)
  {
    TIFFSetField(tif, TIFFTAG_ICCPROFILE, (uint32_t)profile_len, profile);
  }
  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (uint16_t)3);
  TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (uint16_t)d->bpp);
  TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, (uint16_t)(d->bpp == 32 ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT));
  TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32_t)d->width);
  TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32_t)d->height);
  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, (uint16_t)PHOTOMETRIC_RGB);
  TIFFSetField(tif, TIFFTAG_PLANARCONFIG, (uint16_t)PLANARCONFIG_CONTIG);
  TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, (uint32_t)1);
  TIFFSetField(tif, TIFFTAG_ORIENTATION, (uint16_t)ORIENTATION_TOPLEFT);

  int resolution = dt_conf_get_int("metadata/resolution");
  if(resolution > 0)
  {
    TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)resolution);
    TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)resolution);
    TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16_t)RESUNIT_INCH);
  }

  const size_t rowsize = (d->width * 3) * d->bpp / 8;
  if((rowdata = malloc(rowsize)) == NULL)
  {
    rc = 1;
    goto exit;
  }

  if(d->bpp == 32)
  {
    for(int y = 0; y < d->height; y++)
    {
      float *in = (float *)in_void + (size_t)4 * y * d->width;
      float *out = (float *)rowdata;

      for(int x = 0; x < d->width; x++, in += 4, out += 3)
      {
        memcpy(out, in, 3 * sizeof(float));
      }

      if(TIFFWriteScanline(tif, rowdata, y, 0) == -1)
      {
        rc = 1;
        goto exit;
      }
    }
  }
  else if(d->bpp == 16)
  {
    for(int y = 0; y < d->height; y++)
    {
      uint16_t *in = (uint16_t *)in_void + (size_t)4 * y * d->width;
      uint16_t *out = (uint16_t *)rowdata;

      for(int x = 0; x < d->width; x++, in += 4, out += 3)
      {
        memcpy(out, in, 3 * sizeof(uint16_t));
      }

      if(TIFFWriteScanline(tif, rowdata, y, 0) == -1)
      {
        rc = 1;
        goto exit;
      }
    }
  }
  else
  {
    for(int y = 0; y < d->height; y++)
    {
      uint8_t *in = (uint8_t *)in_void + (size_t)4 * y * d->width;
      uint8_t *out = (uint8_t *)rowdata;

      for(int x = 0; x < d->width; x++, in += 4, out += 3)
      {
        memcpy(out, in, 3 * sizeof(uint8_t));
      }

      if(TIFFWriteScanline(tif, rowdata, y, 0) == -1)
      {
        rc = 1;
        goto exit;
      }
    }
  }

  // success
  rc = 0;

exit:
  // close the file before adding exif data
  if(tif)
  {
    TIFFClose(tif);
    tif = NULL;
  }
  if(!rc && exif)
  {
    rc = dt_exif_write_blob(exif, exif_len, filename);
    // Until we get symbolic error status codes, if rc is 1, return 0
    rc = (rc == 1) ? 0 : 1;
  }
  free(profile);
  profile = NULL;
  free(rowdata);
  rowdata = NULL;

  return rc;
}
예제 #13
0
    bool write(const pfs::Frame &frame, const JpegWriterParams& params,
               const std::string& filename)
    {
        cmsUInt32Number cmsProfileSize = 0;
        utils::ScopedCmsProfile hsRGB( cmsCreate_sRGBProfile() );

        cmsSaveProfileToMem(hsRGB.data(), NULL, &cmsProfileSize);           // get the size

        std::vector<JOCTET> cmsOutputProfile(cmsProfileSize);

        cmsSaveProfileToMem(hsRGB.data(), cmsOutputProfile.data(), &cmsProfileSize);

        struct jpeg_compress_struct cinfo;
        struct jpeg_error_mgr errorHandler;

        jpeg_create_compress(&cinfo);

        cinfo.err                        = jpeg_std_error(&errorHandler);
        errorHandler.error_exit          = my_writer_error_handler;
        errorHandler.output_message      = my_writer_output_message;

        cinfo.image_width           = frame.getWidth();                 // image width and height, in pixels
        cinfo.image_height          = frame.getHeight();
        cinfo.input_components      = cinfo.num_components = 3;         // # of color components per pixel
        cinfo.in_color_space        = JCS_RGB;                          // colorspace of input image
        cinfo.jpeg_color_space      = JCS_YCbCr;
        cinfo.density_unit          = 1;                                // dots/inch
        cinfo.X_density             = cinfo.Y_density = 72;

        jpeg_set_defaults(&cinfo);
        jpeg_set_colorspace(&cinfo, JCS_YCbCr);

        // avoid subsampling on high quality factor
        jpeg_set_quality(&cinfo, params.quality_, 1);
        if ( params.quality_ >= 70 ) {
            for (int i = 0; i < cinfo.num_components; i++) {
                cinfo.comp_info[i].h_samp_factor = 1;
                cinfo.comp_info[i].v_samp_factor = 1;
            }
        }

        try
        {
            setupJpegDest(&cinfo, filename);

            jpeg_start_compress(&cinfo, true);

            const Channel* rChannel;
            const Channel* gChannel;
            const Channel* bChannel;
            frame.getXYZChannels(rChannel, gChannel, bChannel);

            write_icc_profile(&cinfo, cmsOutputProfile.data(), cmsProfileSize);

            // If an exception is raised, this buffer gets automatically destructed!
            std::vector<JSAMPLE> scanLineOut(cinfo.image_width * cinfo.num_components);
            JSAMPROW scanLineOutArray[1] = { scanLineOut.data() };

            while (cinfo.next_scanline < cinfo.image_height)
            {
                // copy line from Frame into scanLineOut
                utils::transform(
                            rChannel->row_begin(cinfo.next_scanline),
                            rChannel->row_end(cinfo.next_scanline),
                            gChannel->row_begin(cinfo.next_scanline),
                            bChannel->row_begin(cinfo.next_scanline),
                            FixedStrideIterator<JSAMPLE*, 3>(scanLineOut.data()),
                            FixedStrideIterator<JSAMPLE*, 3>(scanLineOut.data() + 1),
                            FixedStrideIterator<JSAMPLE*, 3>(scanLineOut.data() + 2),
                            utils::chain(
                                colorspace::Normalizer(params.minLuminance_, params.maxLuminance_),
                                utils::CLAMP_F32,
                                Remapper<JSAMPLE>(params.luminanceMapping_)
                                )
                            );
                jpeg_write_scanlines(&cinfo, scanLineOutArray, 1);
            }
        }
        catch (const std::runtime_error& err)
        {
            std::clog << err.what() << std::endl;

            jpeg_destroy_compress(&cinfo);

            return false;
        }

        jpeg_finish_compress(&cinfo);
        jpeg_destroy_compress(&cinfo);

        close();

        return true;
    }