Esempio n. 1
0
static void
gimp_tile_put (GimpTile *tile)
{
  extern GIOChannel *_writechannel;

  GPTileReq        tile_req;
  GPTileData       tile_data;
  GPTileData      *tile_info;
  GimpWireMessage  msg;

  tile_req.drawable_ID = -1;
  tile_req.tile_num    = 0;
  tile_req.shadow      = 0;

  gp_lock ();
  if (! gp_tile_req_write (_writechannel, &tile_req, NULL))
    gimp_quit ();

  gimp_read_expect_msg (&msg, GP_TILE_DATA);

  tile_info = msg.data;

  tile_data.drawable_ID = tile->drawable->drawable_id;
  tile_data.tile_num    = tile->tile_num;
  tile_data.shadow      = tile->shadow;
  tile_data.bpp         = tile->bpp;
  tile_data.width       = tile->ewidth;
  tile_data.height      = tile->eheight;
  tile_data.use_shm     = tile_info->use_shm;
  tile_data.data        = NULL;

  if (tile_info->use_shm)
    memcpy (gimp_shm_addr (),
            tile->data,
            tile->ewidth * tile->eheight * tile->bpp);
  else
    tile_data.data = tile->data;

  if (! gp_tile_data_write (_writechannel, &tile_data, NULL))
    gimp_quit ();

  if (! tile_info->use_shm)
    tile_data.data = NULL;

  gimp_wire_destroy (&msg);

  gimp_read_expect_msg (&msg, GP_TILE_ACK);
  gp_unlock ();
  gimp_wire_destroy (&msg);
}
Esempio n. 2
0
static void
gimp_tile_get (GimpTile *tile)
{
  extern GIOChannel *_writechannel;

  GPTileReq        tile_req;
  GPTileData      *tile_data;
  GimpWireMessage  msg;

  tile_req.drawable_ID = tile->drawable->drawable_id;
  tile_req.tile_num    = tile->tile_num;
  tile_req.shadow      = tile->shadow;

  gp_lock ();
  if (! gp_tile_req_write (_writechannel, &tile_req, NULL))
    gimp_quit ();

  gimp_read_expect_msg (&msg, GP_TILE_DATA);

  tile_data = msg.data;
  if (tile_data->drawable_ID != tile->drawable->drawable_id ||
      tile_data->tile_num    != tile->tile_num              ||
      tile_data->shadow      != tile->shadow                ||
      tile_data->width       != tile->ewidth                ||
      tile_data->height      != tile->eheight               ||
      tile_data->bpp         != tile->bpp)
    {
      g_message ("received tile info did not match computed tile info");
      gimp_quit ();
    }

  if (tile_data->use_shm)
    {
      tile->data = g_memdup (gimp_shm_addr (),
                             tile->ewidth * tile->eheight * tile->bpp);
    }
  else
    {
      tile->data = tile_data->data;
      tile_data->data = NULL;
    }

  if (! gp_tile_ack_write (_writechannel, NULL))
    gimp_quit ();
  gp_unlock ();

  gimp_wire_destroy (&msg);
}
Esempio n. 3
0
static void
indexed_autostretch_hsv (gint32 image_ID)
{
  guchar *cmap;
  AutostretchData data = {0.0, 1.0, 0.0, 1.0};
  gint ncols, i;

  cmap = gimp_image_get_colormap (image_ID, &ncols);

  if (!cmap)
    {
      g_message (_("autostretch_hsv: cmap was NULL!  Quitting...\n"));
      gimp_quit ();
    }

  for (i = 0; i < ncols; i++)
    {
      find_max (&cmap[i * 3], 3, &data);
    }

  for (i = 0; i < ncols; i++)
    {
      autostretch_hsv_func (&cmap[i * 3], &cmap[i * 3], 3, &data);
    }

  gimp_image_set_colormap (image_ID, cmap, ncols);
}
Esempio n. 4
0
static void
query (void)
{
  char *date=NULL;
  
  static GimpParamDef load_args[] =
  {
    { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
    { GIMP_PDB_STRING, "filename", "The name of the file to load" },
    { GIMP_PDB_STRING, "raw_filename", "The name of the file to load." },
  };
  static GimpParamDef load_return_vals[] =
  {
    { GIMP_PDB_IMAGE, "image", "Output image" },
  };
  static int nload_args = (int)sizeof (load_args) / (int)sizeof (load_args[0]);
  static int nload_return_vals = (int)sizeof (load_return_vals) / (int)sizeof (load_return_vals[0]);

  static GimpParamDef save_args[] =
  {
    { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
    { GIMP_PDB_IMAGE, "image", "Input image" },
    { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
    { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
    { GIMP_PDB_STRING, "raw_filename", "The name of the file to save the image in" },
  };
  static int nsave_args = (int)sizeof (save_args) / (int)sizeof (save_args[0]);

  m_new (date, char,(200 + strlen(version())), gimp_quit())
  sprintf (date,"%s\n2005-2007", version()); 
  gimp_install_procedure ("file_pnm_load",
                          "loads files of the pnm file format",
                          "This plug-in loades PNM files. "
                          "The RAW_WIDTH, RAW_HEIGHT, RAW_TYPE and RAW_MAXVAL "
                          "variables can be used to load raw data ending with "
                          "\".raw\" .",
                          "Kai-Uwe Behrmann",
                          "2005-2007 Kai-Uwe Behrmann",
                          date,
                          "<Load>/PNM",
                          NULL,
                          GIMP_PLUGIN,
                          nload_args, nload_return_vals,
                          load_args, load_return_vals);
  gimp_register_load_handler ("file_pnm_load", "pgm,pnm,ppm,pfm,raw", "");

  gimp_install_procedure ("file_pnm_save",
                          "saves files in the pnm file format",
                          "This plug-in saves PNM files.",
                          "Kai-Uwe Behrmann",
                          "2005-2007 Kai-Uwe Behrmann",
                          date,
                          "<Save>/PNM",
                          "RGB*, GRAY*, U16_RGB*, U16_GRAY*",
                          GIMP_PLUGIN,
                          nsave_args, 0,
                          save_args, NULL);

  gimp_register_save_handler ("file_pnm_save", "pgm,pnm,ppm", "");

  gimp_install_procedure ("file_pfm_save",
                          "saves files in the pfm file format",
                          "This plug-in saves PFM files.",
                          "Kai-Uwe Behrmann",
                          "2005-2007 Kai-Uwe Behrmann",
                          date,
                          "<Save>/PFM",
                          "FLOAT_RGB*, FLOAT_GRAY*",
                          GIMP_PLUGIN,
                          nsave_args, 0,
                          save_args, NULL);

  gimp_register_save_handler ("file_pfm_save", "pfm", "");

  m_free (date)
}
Esempio n. 5
0
static gint32
ReadImage (FILE        *fd,
           const gchar *filename,
           gint         len,
           gint         height,
           CMap         cmap,
           gint         ncols,
           gint         format,
           gint         interlace,
           gint         number,
           guint        leftpos,
           guint        toppos,
           guint        screenwidth,
           guint        screenheight)
{
  static gint32 image_ID   = -1;
  static gint   frame_number = 1;

  gint32        layer_ID;
  GimpPixelRgn  pixel_rgn;
  GimpDrawable *drawable;
  guchar       *dest, *temp;
  guchar        c;
  gint          xpos = 0, ypos = 0, pass = 0;
  gint          cur_progress, max_progress;
  gint          v;
  gint          i, j;
  gchar        *framename;
  gchar        *framename_ptr;
  gboolean      alpha_frame = FALSE;
  static gint   previous_disposal;

  /* Guard against bogus frame size */
  if (len < 1 || height < 1)
    {
      g_message ("Bogus frame dimensions");
      return -1;
    }

  /*
   **  Initialize the Compression routines
   */
  if (! ReadOK (fd, &c, 1))
    {
      g_message ("EOF / read error on image data");
      return -1;
    }

  if (LZWReadByte (fd, TRUE, c) < 0)
    {
      g_message ("Error while reading");
      return -1;
    }

  if (frame_number == 1)
    {
      /* Guard against bogus logical screen size values */
      if (screenwidth == 0)
        screenwidth = len;

      if (screenheight == 0)
        screenheight = height;

      image_ID = gimp_image_new (screenwidth, screenheight, GIMP_INDEXED);
      gimp_image_set_filename (image_ID, filename);

      for (i = 0, j = 0; i < ncols; i++)
        {
          used_cmap[0][i] = gimp_cmap[j++] = cmap[0][i];
          used_cmap[1][i] = gimp_cmap[j++] = cmap[1][i];
          used_cmap[2][i] = gimp_cmap[j++] = cmap[2][i];
        }

      gimp_image_set_colormap (image_ID, gimp_cmap, ncols);

      if (Gif89.delayTime < 0)
        framename = g_strdup (_("Background"));
      else
        framename = g_strdup_printf (_("Background (%d%s)"),
                                     10 * Gif89.delayTime, "ms");

      previous_disposal = Gif89.disposal;

      if (Gif89.transparent == -1)
        {
          layer_ID = gimp_layer_new (image_ID, framename,
                                     len, height,
                                     GIMP_INDEXED_IMAGE, 100, GIMP_NORMAL_MODE);
        }
      else
        {
          layer_ID = gimp_layer_new (image_ID, framename,
                                     len, height,
                                     GIMP_INDEXEDA_IMAGE, 100, GIMP_NORMAL_MODE);
          alpha_frame=TRUE;
        }

      g_free (framename);
    }
  else /* NOT FIRST FRAME */
    {
      gimp_progress_set_text_printf (_("Opening '%s' (frame %d)"),
                                     gimp_filename_to_utf8 (filename),
                                     frame_number);
      gimp_progress_pulse ();

       /* If the colourmap is now different, we have to promote to RGB! */
      if (! promote_to_rgb)
        {
          for (i = 0; i < ncols; i++)
            {
              if ((used_cmap[0][i] != cmap[0][i]) ||
                  (used_cmap[1][i] != cmap[1][i]) ||
                  (used_cmap[2][i] != cmap[2][i]))
                {
                  /* Everything is RGB(A) from now on... sigh. */
                  promote_to_rgb = TRUE;

                  /* Promote everything we have so far into RGB(A) */
#ifdef GIFDEBUG
                  g_print ("GIF: Promoting image to RGB...\n");
#endif
                  gimp_image_convert_rgb (image_ID);

                  break;
                }
            }
        }

      if (Gif89.delayTime < 0)
        framename = g_strdup_printf (_("Frame %d"), frame_number);
      else
        framename = g_strdup_printf (_("Frame %d (%d%s)"),
                                     frame_number, 10 * Gif89.delayTime, "ms");

      switch (previous_disposal)
        {
        case 0x00:
          break; /* 'don't care' */
        case 0x01:
          framename_ptr = framename;
          framename = g_strconcat (framename, " (combine)", NULL);
          g_free (framename_ptr);
          break;
        case 0x02:
          framename_ptr = framename;
          framename = g_strconcat (framename, " (replace)", NULL);
          g_free (framename_ptr);
          break;
        case 0x03:  /* Rarely-used, and unhandled by many
                       loaders/players (including GIMP: we treat as
                       'combine' mode). */
          framename_ptr = framename;
          framename = g_strconcat (framename, " (combine) (!)", NULL);
          g_free (framename_ptr);
          break;
        case 0x04: /* I've seen a composite of this type. stvo_online_banner2.gif */
        case 0x05:
        case 0x06: /* I've seen a composite of this type. bn31.Gif */
        case 0x07:
          framename_ptr = framename;
          framename = g_strconcat (framename, " (unknown disposal)", NULL);
          g_free (framename_ptr);
          g_message (_("GIF: Undocumented GIF composite type %d is "
                       "not handled.  Animation might not play or "
                       "re-save perfectly."),
                     previous_disposal);
          break;
        default:
          g_message ("Disposal word got corrupted.  Bug.");
          break;
        }
      previous_disposal = Gif89.disposal;

      layer_ID = gimp_layer_new (image_ID, framename,
                                 len, height,
                                 promote_to_rgb ?
                                 GIMP_RGBA_IMAGE : GIMP_INDEXEDA_IMAGE,
                                 100, GIMP_NORMAL_MODE);
      alpha_frame = TRUE;
      g_free (framename);
    }

  frame_number++;

  gimp_image_insert_layer (image_ID, layer_ID, -1, 0);
  gimp_layer_translate (layer_ID, (gint) leftpos, (gint) toppos);

  drawable = gimp_drawable_get (layer_ID);

  cur_progress = 0;
  max_progress = height;

  if (alpha_frame)
    dest = (guchar *) g_malloc (len * height * (promote_to_rgb ? 4 : 2));
  else
    dest = (guchar *) g_malloc (len * height);

#ifdef GIFDEBUG
    g_print ("GIF: reading %d by %d%s GIF image, ncols=%d\n",
             len, height, interlace ? " interlaced" : "", ncols);
#endif

  if (! alpha_frame && promote_to_rgb)
    {
      /* I don't see how one would easily construct a GIF in which
         this could happen, but it's a mad mad world. */
      g_message ("Ouch!  Can't handle non-alpha RGB frames.\n"
                 "Please file a bug report in GIMP's bugzilla.");
      gimp_quit ();
    }

  while ((v = LZWReadByte (fd, FALSE, c)) >= 0)
    {
      if (alpha_frame)
        {
          if (((guchar) v > highest_used_index) && !(v == Gif89.transparent))
            highest_used_index = (guchar) v;

          if (promote_to_rgb)
            {
              temp = dest + ( (ypos * len) + xpos ) * 4;
              *(temp  ) = (guchar) cmap[0][v];
              *(temp+1) = (guchar) cmap[1][v];
              *(temp+2) = (guchar) cmap[2][v];
              *(temp+3) = (guchar) ((v == Gif89.transparent) ? 0 : 255);
            }
          else
            {
              temp = dest + ( (ypos * len) + xpos ) * 2;
              *temp = (guchar) v;
              *(temp+1) = (guchar) ((v == Gif89.transparent) ? 0 : 255);
            }
        }
      else
        {
          if ((guchar) v > highest_used_index)
            highest_used_index = (guchar) v;

          temp = dest + (ypos * len) + xpos;
          *temp = (guchar) v;
        }

      xpos++;
      if (xpos == len)
        {
          xpos = 0;
          if (interlace)
            {
              switch (pass)
                {
                case 0:
                case 1:
                  ypos += 8;
                  break;
                case 2:
                  ypos += 4;
                  break;
                case 3:
                  ypos += 2;
                  break;
                }

              if (ypos >= height)
                {
                  pass++;
                  switch (pass)
                    {
                    case 1:
                      ypos = 4;
                      break;
                    case 2:
                      ypos = 2;
                      break;
                    case 3:
                      ypos = 1;
                      break;
                    default:
                      goto fini;
                    }
                }
            }
          else
            {
              ypos++;
            }

          if (frame_number == 1)
            {
              cur_progress++;
              if ((cur_progress % 16) == 0)
                gimp_progress_update ((gdouble) cur_progress /
                                      (gdouble) max_progress);
            }
        }

      if (ypos >= height)
        break;
    }

 fini:
  if (LZWReadByte (fd, FALSE, c) >= 0)
    g_print ("GIF: too much input data, ignoring extra...\n");

  gimp_pixel_rgn_init (&pixel_rgn, drawable,
                       0, 0, drawable->width, drawable->height, TRUE, FALSE);
  gimp_pixel_rgn_set_rect (&pixel_rgn, dest,
                           0, 0, drawable->width, drawable->height);

  g_free (dest);

  gimp_drawable_flush (drawable);
  gimp_drawable_detach (drawable);

  return image_ID;
}
Esempio n. 6
0
static gint
LZWReadByte (FILE *fd,
             gint  just_reset_LZW,
             gint  input_code_size)
{
  static gint fresh = FALSE;
  gint        code, incode;
  static gint code_size, set_code_size;
  static gint max_code, max_code_size;
  static gint firstcode, oldcode;
  static gint clear_code, end_code;
  static gint table[2][(1 << MAX_LZW_BITS)];
  static gint stack[(1 << (MAX_LZW_BITS)) * 2], *sp;
  gint        i;

  if (just_reset_LZW)
    {
      if (input_code_size > MAX_LZW_BITS)
        {
          g_message ("Value out of range for code size (corrupted file?)");
          return -1;
        }

      set_code_size = input_code_size;
      code_size     = set_code_size + 1;
      clear_code    = 1 << set_code_size;
      end_code      = clear_code + 1;
      max_code_size = 2 * clear_code;
      max_code      = clear_code + 2;

      GetCode (fd, 0, TRUE);

      fresh = TRUE;

      sp = stack;

      for (i = 0; i < clear_code; ++i)
        {
          table[0][i] = 0;
          table[1][i] = i;
        }
      for (; i < (1 << MAX_LZW_BITS); ++i)
        {
          table[0][i] = 0;
          table[1][i] = 0;
        }

      return 0;
    }
  else if (fresh)
    {
      fresh = FALSE;
      do
        {
          firstcode = oldcode = GetCode (fd, code_size, FALSE);
        }
      while (firstcode == clear_code);

      return firstcode;
    }

  if (sp > stack)
    return *--sp;

  while ((code = GetCode (fd, code_size, FALSE)) >= 0)
    {
      if (code == clear_code)
        {
          for (i = 0; i < clear_code; ++i)
            {
              table[0][i] = 0;
              table[1][i] = i;
            }
          for (; i < (1 << MAX_LZW_BITS); ++i)
            {
              table[0][i] = 0;
              table[1][i] = 0;
            }

          code_size     = set_code_size + 1;
          max_code_size = 2 * clear_code;
          max_code      = clear_code + 2;
          sp            = stack;
          firstcode     = oldcode = GetCode (fd, code_size, FALSE);

          return firstcode;
        }
      else if (code == end_code)
        {
          gint   count;
          guchar buf[260];

          if (ZeroDataBlock)
            return -2;

          while ((count = GetDataBlock (fd, buf)) > 0)
            ;

          if (count != 0)
            g_print ("GIF: missing EOD in data stream (common occurence)");

          return -2;
        }

      incode = code;

      if (code >= max_code)
        {
          *sp++ = firstcode;
          code = oldcode;
        }

      while (code >= clear_code)
        {
          *sp++ = table[1][code];
          if (code == table[0][code])
            {
              g_message ("Circular table entry.  Corrupt file.");
              gimp_quit ();
            }
          code = table[0][code];
        }

      *sp++ = firstcode = table[1][code];

      if ((code = max_code) < (1 << MAX_LZW_BITS))
        {
          table[0][code] = oldcode;
          table[1][code] = firstcode;
          ++max_code;
          if ((max_code >= max_code_size) &&
              (max_code_size < (1 << MAX_LZW_BITS)))
            {
              max_code_size *= 2;
              ++code_size;
            }
        }

      oldcode = incode;

      if (sp > stack)
        return *--sp;
    }

  return code;
}
Esempio n. 7
0
static gint32
load_image (char *filename)
{
  GPixelRgn pixel_rgn;
  TileDrawable *drawable;
  gint32 image_ID;
  gint32 layer_ID;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr jerr;
  FILE *infile;
  guchar *buf;
  guchar **rowbuf;
  char *name;
  int image_type;
  int layer_type;
  int tile_height;
  int scanlines;
  int i, start, end;
  int m;
  int depth = 8;

  /* We set up the normal JPEG error routines. */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  if ((infile = fopen (filename, "rb")) == NULL)
    {
      g_warning ("can't open \"%s\"\n", filename);
      gimp_quit ();
    }

  if( strrchr(filename,'.') &&
      strcmp( strrchr(filename, '.'), ".jp4") == 0 )
    depth = 16;

  name = malloc (strlen (filename) + 12);
  sprintf (name, "%s %s:", _("Loading"), filename);
  gimp_progress_init (name);
  free (name);

  image_ID = -1;
  /* Establish the setjmp return context for my_error_exit to use. */
  if (setjmp (jerr.setjmp_buffer))
    {
      /* If we get here, the JPEG code has signaled an error.
       * We need to clean up the JPEG object, close the input file, and return.
       */
      jpeg_destroy_decompress (&cinfo);
      if (infile)
	fclose (infile);
      if (image_ID != -1)
	gimp_image_delete (image_ID);
      gimp_quit ();
    }
  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress (&cinfo);

  /* Step 2: specify data source (eg, a file) */

  jpeg_stdio_src (&cinfo, infile);

  setup_read_icc_profile(&cinfo);  
  for (m = 0; m < 16; m++)
    jpeg_save_markers(&cinfo, JPEG_APP0 + m, 0xFFFF);

  /* Step 3: read file parameters with jpeg_read_header() */

  (void) jpeg_read_header (&cinfo, TRUE);
  /* We can ignore the return value from jpeg_read_header since
   *   (a) suspension is not possible with the stdio data source, and
   *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
   * See libjpeg.doc for more info.
   */

  /* Step 4: set parameters for decompression */

  /* In this example, we don't need to change any of the defaults set by
   * jpeg_read_header(), so we do nothing here.
   */
  prepareColour( &cinfo );

  /* Step 5: Start decompressor */

  jpeg_start_decompress (&cinfo);

  /* We may need to do some setup of our own at this point before reading
   * the data.  After jpeg_start_decompress() we have the correct scaled
   * output image dimensions available, as well as the output colormap
   * if we asked for color quantization.
   * In this example, we need to make an output work buffer of the right size.
   */
  /* temporary buffer */
  tile_height = gimp_tile_height ();
  buf = g_new (guchar, tile_height * cinfo.output_width * cinfo.output_components);
  rowbuf = g_new (guchar*, tile_height);

  for (i = 0; i < tile_height; i++)
    rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i;

  /* Create a new image of the proper size and associate the filename with it.
   */
  if(depth == 8)
  {
    switch (cinfo.output_components)
    {
    case 1:
      image_type = GRAY;
      layer_type = GRAY_IMAGE;
      break;
    case 3:
      image_type = RGB;
      layer_type = RGB_IMAGE;
      break;
    case 4:
      image_type = RGB;
      layer_type = RGBA_IMAGE;
      break;
    default:
      gimp_quit ();
    }
  } else {
    switch (cinfo.output_components)
    {
    case 1:
      image_type = U16_GRAY;
      layer_type = U16_GRAY_IMAGE;
      break;
    case 3:
      image_type = U16_RGB;
      layer_type = U16_RGB_IMAGE;
      break;
    case 4:
      image_type = U16_RGB;
      layer_type = U16_RGBA_IMAGE;
      break;
    default:
      gimp_quit ();
    }
  }

  image_ID = gimp_image_new (cinfo.output_width / (depth/8), cinfo.output_height,
                             image_type);
  gimp_image_set_filename (image_ID, filename);

  layer_ID = gimp_layer_new (image_ID, _("Background"),
			     cinfo.output_width / (depth/8),
			     cinfo.output_height,
			     layer_type, 100, NORMAL_MODE);
  gimp_image_add_layer (image_ID, layer_ID, 0);

  drawable = gimp_drawable_get (layer_ID);
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE);

  /* Step 6: while (scan lines remain to be read) */
  /*           jpeg_read_scanlines(...); */

  /* Here we use the library's state variable cinfo.output_scanline as the
   * loop counter, so that we don't have to keep track ourselves.
   */
  while (cinfo.output_scanline < cinfo.output_height)
    {
      start = cinfo.output_scanline;
      end = cinfo.output_scanline + tile_height;
      end = MIN (end,CAST(int) cinfo.output_height);
      scanlines = end - start;

      for (i = 0; i < scanlines; i++)
	jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1);

      /*
      for (i = start; i < end; i++)
	gimp_pixel_rgn_set_row (&pixel_rgn, tilerow[i - start], 0, i, drawable->width);
	*/

      if(cinfo.out_color_space == JCS_CMYK)
        for(i = 0; i < scanlines*drawable->width*cinfo.output_components; ++i)
          buf[i] = 255 - buf[i];

      if(depth == 16 && 0)
        for(i = 0; i < scanlines*drawable->width*cinfo.output_components; ++i)
        {
          unsigned char c = buf[2*i];
          buf[2*i] = buf[2*i+1];
          buf[2*i+1] = c;
        }

      gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, start, drawable->width, scanlines);

      gimp_progress_update ((double) cinfo.output_scanline / (double) cinfo.output_height);
    }

  // Step 6a: read icc profile
  {
    LPBYTE Buffer = NULL;
    size_t Len = 0;
    cmsHPROFILE hProfile=NULL;

    if (read_icc_profile(&cinfo, &Buffer, &Len))
    {
      printf ("%s:%d %s() embedded profile found\n",__FILE__,__LINE__,__func__);
    } else if (read_icc_profile2(&cinfo, &Buffer, &Len)) {
      printf ("%s:%d %s() default profile selected\n",__FILE__,__LINE__,__func__);
    }

    if(Buffer && Len)
    {
      hProfile = cmsOpenProfileFromMem(Buffer, Len);
      if (hProfile) {
        gimp_image_set_icc_profile_by_mem (image_ID, Len, Buffer, ICC_IMAGE_PROFILE);
        cmsCloseProfile (hProfile);
        free(Buffer);
        printf ("%s:%d %s() set profile\n",__FILE__,__LINE__,__func__);
      }
    }
  }

  /* Step 7: Finish decompression */

  jpeg_finish_decompress (&cinfo);
  /* We can ignore the return value since suspension is not possible
   * with the stdio data source.
   */

  /* Step 8: Release JPEG decompression object */

  /* This is an important step since it will release a good deal of memory. */
  jpeg_destroy_decompress (&cinfo);

  /* free up the temporary buffers */
  g_free (rowbuf);
  g_free (buf);

  /* After finish_decompress, we can close the input file.
   * Here we postpone it until after no more JPEG errors are possible,
   * so as to simplify the setjmp error logic above.  (Actually, I don't
   * think that jpeg_destroy can do an error exit, but why assume anything...)
   */
  fclose (infile);

  /* At this point you may want to check to see whether any corrupt-data
   * warnings occurred (test whether jerr.num_warnings is nonzero).
   */

  /* Tell the GIMP to display the image.
   */
  gimp_drawable_flush (drawable);

  return image_ID;
}