示例#1
0
void gui_cleanup(struct dt_iop_module_t *self)
{
  dt_iop_colortransfer_gui_data_t *g = (dt_iop_colortransfer_gui_data_t *)self->gui_data;
  dt_colorspaces_cleanup_profile(g->hsRGB);
  dt_colorspaces_cleanup_profile(g->hLab);
  cmsDeleteTransform(g->xform);
  free(self->gui_data);
  self->gui_data = NULL;
}
示例#2
0
void gui_cleanup(struct dt_iop_module_t *self)
{
  dt_iop_colorzones_gui_data_t *c = (dt_iop_colorzones_gui_data_t *)self->gui_data;
  dt_conf_set_int("plugins/darkroom/colorzones/gui_channel", c->channel);
  dt_colorspaces_cleanup_profile(c->hsRGB);
  dt_colorspaces_cleanup_profile(c->hLab);
  cmsDeleteTransform(c->xform);
  dt_draw_curve_destroy(c->minmax_curve);
  free(self->gui_data);
  self->gui_data = NULL;
}
示例#3
0
void cleanup_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
{
  dt_iop_colorout_data_t *d = (dt_iop_colorout_data_t *)piece->data;
  if(d->output) dt_colorspaces_cleanup_profile(d->output);
  dt_colorspaces_cleanup_profile(d->Lab);
  if (d->xform)
  {
    cmsDeleteTransform(d->xform);
    d->xform = 0;
  }

  free(piece->data);
}
示例#4
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, 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_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*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;
}
示例#5
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;
}
示例#6
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);
}
示例#7
0
void commit_params (struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
{
  dt_iop_colorout_params_t *p = (dt_iop_colorout_params_t *)p1;
  dt_iop_colorout_data_t *d = (dt_iop_colorout_data_t *)piece->data;
  gchar *overprofile = dt_conf_get_string("plugins/lighttable/export/iccprofile");
  const int overintent = dt_conf_get_int("plugins/lighttable/export/iccintent");
  const int high_quality_processing = dt_conf_get_bool("plugins/lighttable/export/force_lcms2");
  gchar *outprofile=NULL;
  int outintent = 0;

  /* cleanup profiles */
  if (d->output)
    dt_colorspaces_cleanup_profile(d->output);
  d->output = NULL;

  if (d->softproof_enabled)
    dt_colorspaces_cleanup_profile(d->softproof);
  d->softproof = NULL;

  d->softproof_enabled = p->softproof_enabled;
  if(self->dev->gui_attached && self->gui_data != NULL)
  {
    dt_iop_colorout_gui_data_t *g = (dt_iop_colorout_gui_data_t *)self->gui_data;
    g->softproof_enabled = p->softproof_enabled;
  }
  if (d->xform)
  {
    cmsDeleteTransform(d->xform);
    d->xform = 0;
  }
  d->cmatrix[0] = NAN;
  d->lut[0][0] = -1.0f;
  d->lut[1][0] = -1.0f;
  d->lut[2][0] = -1.0f;
  piece->process_cl_ready = 1;

  /* if we are exporting then check and set usage of override profile */
  if (pipe->type == DT_DEV_PIXELPIPE_EXPORT)
  {
    if (overprofile && strcmp(overprofile, "image"))
      snprintf(p->iccprofile, DT_IOP_COLOR_ICC_LEN, "%s", overprofile);
    if (overintent >= 0)
      p->intent = overintent;

    outprofile = p->iccprofile;
    outintent = p->intent;
  }
  else
  {
    /* we are not exporting, using display profile as output */
    outprofile = p->displayprofile;
    outintent = p->displayintent;
  }

  /*
   * Setup transform flags
   */
  uint32_t transformFlags = 0;

  /* creating output profile */
  d->output = _create_profile(outprofile);

  /* creating softproof profile if softproof is enabled */
  if (d->softproof_enabled && pipe->type == DT_DEV_PIXELPIPE_FULL)
  {
    d->softproof =  _create_profile(p->softproofprofile);

    /* TODO: the use of bpc should be userconfigurable either from module or preference pane */
    /* softproof flag and black point compensation */
    transformFlags |= cmsFLAGS_SOFTPROOFING|cmsFLAGS_NOCACHE|cmsFLAGS_BLACKPOINTCOMPENSATION;

    if(d->softproof_enabled == DT_SOFTPROOF_GAMUTCHECK)
      transformFlags |= cmsFLAGS_GAMUTCHECK;
  }


  /* get matrix from profile, if softproofing or high quality exporting always go xform codepath */
  if (d->softproof_enabled || (pipe->type == DT_DEV_PIXELPIPE_EXPORT && high_quality_processing) ||
      dt_colorspaces_get_matrix_from_output_profile (d->output, d->cmatrix, d->lut[0], d->lut[1], d->lut[2], LUT_SAMPLES))
  {
    d->cmatrix[0] = NAN;
    piece->process_cl_ready = 0;
    d->xform = cmsCreateProofingTransform(d->Lab,
                                          TYPE_Lab_FLT,
                                          d->output,
                                          TYPE_RGB_FLT,
                                          d->softproof,
                                          outintent,
                                          INTENT_RELATIVE_COLORIMETRIC,
                                          transformFlags);
  }

  // user selected a non-supported output profile, check that:
  if (!d->xform && isnan(d->cmatrix[0]))
  {
    dt_control_log(_("unsupported output profile has been replaced by sRGB!"));
    if (d->output)
      dt_colorspaces_cleanup_profile(d->output);
    d->output = dt_colorspaces_create_srgb_profile();
    if (d->softproof_enabled || dt_colorspaces_get_matrix_from_output_profile (d->output, d->cmatrix, d->lut[0], d->lut[1], d->lut[2], LUT_SAMPLES))
    {
      d->cmatrix[0] = NAN;
      piece->process_cl_ready = 0;

      d->xform = cmsCreateProofingTransform(d->Lab,
                                            TYPE_Lab_FLT,
                                            d->output,
                                            TYPE_RGB_FLT,
                                            d->softproof,
                                            outintent,
                                            INTENT_RELATIVE_COLORIMETRIC,
                                            transformFlags);
    }
  }

  // now try to initialize unbounded mode:
  // we do extrapolation for input values above 1.0f.
  // unfortunately we can only do this if we got the computation
  // in our hands, i.e. for the fast builtin-dt-matrix-profile path.
  for(int k=0; k<3; k++)
  {
    // omit luts marked as linear (negative as marker)
    if(d->lut[k][0] >= 0.0f)
    {
      const float x[4] = {0.7f, 0.8f, 0.9f, 1.0f};
      const float y[4] = {lerp_lut(d->lut[k], x[0]),
                          lerp_lut(d->lut[k], x[1]),
                          lerp_lut(d->lut[k], x[2]),
                          lerp_lut(d->lut[k], x[3])
                         };
      dt_iop_estimate_exp(x, y, 4, d->unbounded_coeffs[k]);
    }
    else d->unbounded_coeffs[k][0] = -1.0f;
  }

  //fprintf(stderr, " Output profile %s, softproof %s%s%s\n", outprofile, d->softproof_enabled?"enabled ":"disabled",d->softproof_enabled?"using profile ":"",d->softproof_enabled?p->softproofprofile:"");

  g_free(overprofile);
}
示例#8
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;
}
示例#9
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;
}
示例#10
0
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe,
                   dt_dev_pixelpipe_iop_t *piece)
{
  dt_iop_colorout_params_t *p = (dt_iop_colorout_params_t *)p1;
  dt_iop_colorout_data_t *d = (dt_iop_colorout_data_t *)piece->data;

  d->type = p->type;
  const dt_colorspaces_color_profile_type_t over_type = dt_conf_get_int("plugins/lighttable/export/icctype");
  gchar *over_filename = dt_conf_get_string("plugins/lighttable/export/iccprofile");
  const dt_iop_color_intent_t over_intent = dt_conf_get_int("plugins/lighttable/export/iccintent");

  const int force_lcms2 = dt_conf_get_bool("plugins/lighttable/export/force_lcms2");

  dt_colorspaces_color_profile_type_t out_type = DT_COLORSPACE_SRGB;
  gchar *out_filename = NULL;
  dt_iop_color_intent_t out_intent = DT_INTENT_PERCEPTUAL;

  const cmsHPROFILE Lab = dt_colorspaces_get_profile(DT_COLORSPACE_LAB, "", DT_PROFILE_DIRECTION_ANY)->profile;

  cmsHPROFILE output = NULL;
  cmsHPROFILE softproof = NULL;

  d->mode = pipe->type == DT_DEV_PIXELPIPE_FULL ? darktable.color_profiles->mode : DT_PROFILE_NORMAL;

  if(d->xform)
  {
    cmsDeleteTransform(d->xform);
    d->xform = NULL;
  }
  d->cmatrix[0] = NAN;
  d->lut[0][0] = -1.0f;
  d->lut[1][0] = -1.0f;
  d->lut[2][0] = -1.0f;
  piece->process_cl_ready = 1;

  /* if we are exporting then check and set usage of override profile */
  if(pipe->type == DT_DEV_PIXELPIPE_EXPORT)
  {
    if(over_type != DT_COLORSPACE_NONE)
    {
      p->type = over_type;
      g_strlcpy(p->filename, over_filename, sizeof(p->filename));
    }
    if((unsigned int)over_intent < DT_INTENT_LAST) p->intent = over_intent;

    out_type = p->type;
    out_filename = p->filename;
    out_intent = p->intent;
  }
  else if(pipe->type == DT_DEV_PIXELPIPE_THUMBNAIL)
  {
    out_type = dt_mipmap_cache_get_colorspace();
    out_filename = (out_type == DT_COLORSPACE_DISPLAY ? darktable.color_profiles->display_filename : "");
    out_intent = darktable.color_profiles->display_intent;
  }
  else
  {
    /* we are not exporting, using display profile as output */
    out_type = darktable.color_profiles->display_type;
    out_filename = darktable.color_profiles->display_filename;
    out_intent = darktable.color_profiles->display_intent;
  }

  // when the output type is Lab then process is a nop, so we can avoid creating a transform
  // and the subsequent error messages
  if(out_type == DT_COLORSPACE_LAB)
    goto end;

  /*
   * Setup transform flags
   */
  uint32_t transformFlags = 0;

  /* creating output profile */
  if(out_type == DT_COLORSPACE_DISPLAY) pthread_rwlock_rdlock(&darktable.color_profiles->xprofile_lock);

  const dt_colorspaces_color_profile_t *out_profile
        = dt_colorspaces_get_profile(out_type, out_filename, DT_PROFILE_DIRECTION_OUT | DT_PROFILE_DIRECTION_DISPLAY);
  if(out_profile)
    output = out_profile->profile;
  else
  {
    output = dt_colorspaces_get_profile(DT_COLORSPACE_SRGB, "",
                                        DT_PROFILE_DIRECTION_OUT | DT_PROFILE_DIRECTION_DISPLAY)->profile;
    dt_control_log(_("missing output profile has been replaced by sRGB!"));
    fprintf(stderr, "missing output profile `%s' has been replaced by sRGB!\n",
            dt_colorspaces_get_name(out_type, out_filename));
  }

  /* creating softproof profile if softproof is enabled */
  if(d->mode != DT_PROFILE_NORMAL && pipe->type == DT_DEV_PIXELPIPE_FULL)
  {
    const dt_colorspaces_color_profile_t *prof = dt_colorspaces_get_profile(
        darktable.color_profiles->softproof_type, darktable.color_profiles->softproof_filename,
        DT_PROFILE_DIRECTION_OUT | DT_PROFILE_DIRECTION_DISPLAY);
    if(prof)
      softproof = prof->profile;
    else
    {
      softproof = dt_colorspaces_get_profile(DT_COLORSPACE_SRGB, "",
                                             DT_PROFILE_DIRECTION_OUT | DT_PROFILE_DIRECTION_DISPLAY)->profile;
      dt_control_log(_("missing softproof profile has been replaced by sRGB!"));
      fprintf(stderr, "missing softproof profile `%s' has been replaced by sRGB!\n",
              dt_colorspaces_get_name(darktable.color_profiles->softproof_type,
                                      darktable.color_profiles->softproof_filename));
    }

    // some of our internal profiles are what lcms considers ideal profiles as they have a parametric TRC so
    // taking a roundtrip through those profiles during softproofing has no effect. as a workaround we have to
    // make lcms quantisize those gamma tables to get the desired effect.
    // in case that fails we don't enable softproofing.
    softproof = _make_clipping_profile(softproof);
    if(softproof)
    {
      /* TODO: the use of bpc should be userconfigurable either from module or preference pane */
      /* softproof flag and black point compensation */
      transformFlags |= cmsFLAGS_SOFTPROOFING | cmsFLAGS_NOCACHE | cmsFLAGS_BLACKPOINTCOMPENSATION;

      if(d->mode == DT_PROFILE_GAMUTCHECK) transformFlags |= cmsFLAGS_GAMUTCHECK;
    }
  }

  /*
   * NOTE: theoretically, we should be passing
   * UsedDirection = LCMS_USED_AS_PROOF  into
   * dt_colorspaces_get_matrix_from_output_profile() so that
   * dt_colorspaces_get_matrix_from_profile() knows it, but since we do not try
   * to use our matrix codepath when softproof is enabled, this seemed redundant.
   */

  /* get matrix from profile, if softproofing or high quality exporting always go xform codepath */
  if(d->mode != DT_PROFILE_NORMAL || force_lcms2
     || dt_colorspaces_get_matrix_from_output_profile(output, d->cmatrix, d->lut[0], d->lut[1], d->lut[2],
                                                      LUT_SAMPLES, out_intent))
  {
    d->cmatrix[0] = NAN;
    piece->process_cl_ready = 0;
    d->xform = cmsCreateProofingTransform(Lab, TYPE_LabA_FLT, output, TYPE_RGBA_FLT, softproof,
                                          out_intent, INTENT_RELATIVE_COLORIMETRIC, transformFlags);
  }

  // user selected a non-supported output profile, check that:
  if(!d->xform && isnan(d->cmatrix[0]))
  {
    dt_control_log(_("unsupported output profile has been replaced by sRGB!"));
    fprintf(stderr, "unsupported output profile `%s' has been replaced by sRGB!\n", out_profile->name);
    output = dt_colorspaces_get_profile(DT_COLORSPACE_SRGB, "", DT_PROFILE_DIRECTION_OUT)->profile;
    if(d->mode != DT_PROFILE_NORMAL
       || dt_colorspaces_get_matrix_from_output_profile(output, d->cmatrix, d->lut[0], d->lut[1],
                                                        d->lut[2], LUT_SAMPLES, out_intent))
    {
      d->cmatrix[0] = NAN;
      piece->process_cl_ready = 0;

      d->xform = cmsCreateProofingTransform(Lab, TYPE_LabA_FLT, output, TYPE_RGBA_FLT, softproof,
                                            out_intent, INTENT_RELATIVE_COLORIMETRIC, transformFlags);
    }
  }

  if(out_type == DT_COLORSPACE_DISPLAY) pthread_rwlock_unlock(&darktable.color_profiles->xprofile_lock);

  // now try to initialize unbounded mode:
  // we do extrapolation for input values above 1.0f.
  // unfortunately we can only do this if we got the computation
  // in our hands, i.e. for the fast builtin-dt-matrix-profile path.
  for(int k = 0; k < 3; k++)
  {
    // omit luts marked as linear (negative as marker)
    if(d->lut[k][0] >= 0.0f)
    {
      const float x[4] = { 0.7f, 0.8f, 0.9f, 1.0f };
      const float y[4] = { lerp_lut(d->lut[k], x[0]), lerp_lut(d->lut[k], x[1]), lerp_lut(d->lut[k], x[2]),
                           lerp_lut(d->lut[k], x[3]) };
      dt_iop_estimate_exp(x, y, 4, d->unbounded_coeffs[k]);
    }
    else
      d->unbounded_coeffs[k][0] = -1.0f;
  }

  // softproof is never the original but always a copy that went through _make_clipping_profile()
  dt_colorspaces_cleanup_profile(softproof);

end:
  g_free(over_filename);
}