Exemplo n.º 1
0
static void
run (const gchar      *name,
     gint              n_params,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
{
  static GimpParam   values[1];
  GimpDrawable      *drawable;
  GimpRunMode        run_mode;
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
  gint32             image_id;

  *nreturn_vals = 1;
  *return_vals  = values;

  run_mode = param[0].data.d_int32;

  if (run_mode == GIMP_RUN_NONINTERACTIVE)
    {
      if (n_params != 3)
        {
          status = GIMP_PDB_CALLING_ERROR;
        }
    }

  if (status == GIMP_PDB_SUCCESS)
    {
      /*  Get the specified drawable  */
      drawable = gimp_drawable_get(param[2].data.d_drawable);
      image_id = param[1].data.d_image;

      /*  Make sure that the drawable is gray or RGB or indexed  */
      if (gimp_drawable_is_rgb (drawable->drawable_id) ||
          gimp_drawable_is_gray (drawable->drawable_id) ||
          gimp_drawable_is_indexed (drawable->drawable_id))
        {
          gimp_progress_init ("Autocropping...");

          gimp_tile_cache_ntiles (1 +
                                  (drawable->width > drawable->height ?
                                  (drawable->width / gimp_tile_width()) :
                                  (drawable->height / gimp_tile_height())));

          do_acrop(drawable, image_id);

          if (run_mode != GIMP_RUN_NONINTERACTIVE)
            gimp_displays_flush ();

          gimp_drawable_detach (drawable);
        }
      else
        {
          status = GIMP_PDB_EXECUTION_ERROR;
        }
    }

  values[0].type          = GIMP_PDB_STATUS;
  values[0].data.d_status = status;
}
Exemplo n.º 2
0
/**
 * gimp_tile_cache_ntiles:
 * @ntiles: number of tiles that should fit into the cache
 *
 * Sets the size of the tile cache on the plug-in side. This function
 * is similar to gimp_tile_cache_size() but supports specifying the
 * number of tiles directly.
 *
 * If your plug-in access pixels tile-by-tile, it doesn't need a tile
 * cache at all. If however the plug-in accesses drawable pixel data
 * row-by-row, it should set the tile cache large enough to hold the
 * number of tiles per row. Double this size if your plug-in uses
 * shadow tiles.
 **/
void
gimp_tile_cache_ntiles (gulong ntiles)
{
  max_cache_size = (ntiles *
                    gimp_tile_width () *
                    gimp_tile_height () * 4);
}
Exemplo n.º 3
0
static void
pixelize (GimpDrawable *drawable,
          GimpPreview  *preview)
{
  gint tile_width;
  gint tile_height;
  gint pixelwidth;
  gint pixelheight;

  tile_width  = gimp_tile_width ();
  tile_height = gimp_tile_height ();

  pixelwidth  = pvals.pixelwidth;
  pixelheight = pvals.pixelheight;

  if (pixelwidth < 0)
    pixelwidth = - pixelwidth;
  if (pixelwidth < 1)
    pixelwidth = 1;

  if (pixelheight < 0)
    pixelheight = - pixelheight;
  if (pixelheight < 1)
    pixelheight = 1;

  if (pixelwidth >= tile_width || pixelheight >= tile_height || preview)
    pixelize_large (drawable, pixelwidth, pixelheight, preview);
  else
    pixelize_small (drawable, pixelwidth, pixelheight, tile_width, tile_height);
}
Exemplo n.º 4
0
/*
 * sendBMPToGIMP
 *
 * Take the captured data and send it across
 * to GIMP.
 */
static void
sendBMPToGimp(HBITMAP hBMP, HDC hDC, RECT rect)
{
  int		width, height;
  int		imageType, layerType;
  gint32	image_id;
  gint32	layer_id;
  GimpPixelRgn	pixel_rgn;
  GimpDrawable    *drawable;

  /* Our width and height */
  width = (rect.right - rect.left);
  height = (rect.bottom - rect.top);

  /* Check that we got the memory */
  if (!capBytes) {
    g_message (_("No data captured"));
    return;
  }

  /* Flip the red and blue bytes */
  flipRedAndBlueBytes(width, height);

  /* Set up the image and layer types */
  imageType = GIMP_RGB;
  layerType = GIMP_RGB_IMAGE;

  /* Create the GIMP image and layers */
  image_id = gimp_image_new(width, height, imageType);
  layer_id = gimp_layer_new(image_id, _("Background"),
			    ROUND4(width), height,
			    layerType, 100, GIMP_NORMAL_MODE);
  gimp_image_insert_layer(image_id, layer_id, -1, 0);

  /* Get our drawable */
  drawable = gimp_drawable_get(layer_id);

  gimp_tile_cache_size(ROUND4(width) * gimp_tile_height() * 3);

  /* Initialize a pixel region for writing to the image */
  gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0,
		      ROUND4(width), height, TRUE, FALSE);

  gimp_pixel_rgn_set_rect(&pixel_rgn, (guchar *) capBytes,
			  0, 0, ROUND4(width), height);

  /* HB: update data BEFORE size change */
  gimp_drawable_flush(drawable);
  /* Now resize the layer down to the correct size if necessary. */
  if (width != ROUND4(width)) {
    gimp_layer_resize (layer_id, width, height, 0, 0);
    gimp_image_resize (image_id, width, height, 0, 0);
  }
  /* Finish up */
  gimp_drawable_detach(drawable);
  gimp_display_new (image_id);

  return;
}
Exemplo n.º 5
0
/* Draw the hole at the specified position */
static void
draw_hole_rgb (GimpDrawable *drw,
               gint          x,
               gint          y,
               gint          width,
               gint          height,
               guchar       *hole)
{
  GimpPixelRgn    rgn;
  guchar         *data;
  gint            tile_height = gimp_tile_height ();
  gint            i, j, scan_lines;
  gint            d_width = gimp_drawable_width (drw->drawable_id);
  gint            length;

  if ((width <= 0) || (height <= 0))
    return;
  if ((x+width <= 0) || (x >= d_width))
    return;
  length = width;   /* Check that we dont draw past the image */
  if ((x+length) >= d_width)
    length = d_width-x;

  data = g_new (guchar, length * tile_height * drw->bpp);

  gimp_pixel_rgn_init (&rgn, drw, x, y, length, height, TRUE, FALSE);

  i = 0;
  while (i < height)
    {
      scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i);
      if (length == width)
        {
          memcpy (data, hole + 3*width*i, width*scan_lines*3);
        }
      else  /* We have to do some clipping */
        {
          for (j = 0; j < scan_lines; j++)
            memcpy (data + j*length*3, hole + (i+j)*width*3, length*3);
        }
      gimp_pixel_rgn_set_rect (&rgn, data, x, y+i, length, scan_lines);

      i += scan_lines;
    }

  g_free (data);
}
Exemplo n.º 6
0
/* Decompose an image. It returns the number of new (gray) images.
   The image IDs for the new images are returned in image_ID_dst.
   On failure, -1 is returned.
*/
static gint32
decompose (gint32       image_ID,
           gint32       drawable_ID,
           const gchar *extract_type,
           gint32      *image_ID_dst,
           gint32      *nlayers,
           gint32      *layer_ID_dst)
{
  const gchar  *layername;
  gint          i, j, extract_idx, scan_lines;
  gint          height, width, tile_height, num_layers;
  gchar        *filename;
  guchar       *src;
  guchar       *dst[MAX_EXTRACT_IMAGES];
  GimpDrawable *drawable_src;
  GimpDrawable *drawable_dst[MAX_EXTRACT_IMAGES];
  GimpPixelRgn  pixel_rgn_src;
  GimpPixelRgn  pixel_rgn_dst[MAX_EXTRACT_IMAGES];

  extract_idx = -1;   /* Search extract type */
  for (j = 0; j < G_N_ELEMENTS (extract); j++)
    {
      if (g_ascii_strcasecmp (extract_type, extract[j].type) == 0)
	{
	  extract_idx = j;
	  break;
	}
    }
  if (extract_idx < 0)
    return -1;

  /* Check structure of source image */
  drawable_src = gimp_drawable_get (drawable_ID);
  if (drawable_src->bpp < 3)
    {
      g_message ("Not an RGB image.");
      return -1;
    }
  if ((extract[extract_idx].extract_fun == extract_alpha ||
       extract[extract_idx].extract_fun == extract_rgba) &&
      (!gimp_drawable_has_alpha (drawable_ID)))
    {
      g_message ("No alpha channel available.");
      return -1;
    }

  width  = drawable_src->width;
  height = drawable_src->height;

  tile_height = gimp_tile_height ();
  gimp_pixel_rgn_init (&pixel_rgn_src, drawable_src, 0, 0, width, height,
                       FALSE, FALSE);

  /* allocate a buffer for retrieving information from the src pixel region  */
  src = g_new (guchar, tile_height * width * drawable_src->bpp);

  /* Create all new gray images */
  num_layers = extract[extract_idx].num_images;
  if (num_layers > MAX_EXTRACT_IMAGES)
    num_layers = MAX_EXTRACT_IMAGES;

  for (j = 0; j < num_layers; j++)
    {
      /* Build a filename like <imagename>-<channel>.<extension> */
      gchar   *fname;
      gchar   *extension;
      gdouble  xres, yres;

      fname = gimp_image_get_filename (image_ID);

      if (fname)
        {
          extension = fname + strlen (fname) - 1;

          while (extension >= fname)
            {
              if (*extension == '.') break;
              extension--;
            }
          if (extension >= fname)
            {
              *(extension++) = '\0';

              if (decovals.as_layers)
                filename = g_strdup_printf ("%s-%s.%s", fname,
                                            gettext (extract[extract_idx].type),
                                            extension);
              else
                filename = g_strdup_printf ("%s-%s.%s", fname,
                                            gettext (extract[extract_idx].channel_name[j]),
                                            extension);
            }
          else
            {
              if (decovals.as_layers)
                filename = g_strdup_printf ("%s-%s", fname,
                                            gettext (extract[extract_idx].type));
              else
                filename = g_strdup_printf ("%s-%s", fname,
                                            gettext (extract[extract_idx].channel_name[j]));
            }
        }
      else
        {
          filename = g_strdup (gettext (extract[extract_idx].channel_name[j]));
        }

      gimp_image_get_resolution (image_ID, &xres, &yres);

      if (decovals.as_layers)
        {
          layername = gettext (extract[extract_idx].channel_name[j]);

          if (j == 0)
            image_ID_dst[j] = create_new_image (filename, layername,
                                                width, height, GIMP_GRAY,
                                                xres, yres,
                                                layer_ID_dst + j,
                                                drawable_dst + j,
                                                pixel_rgn_dst + j);
          else
            layer_ID_dst[j] = create_new_layer (image_ID_dst[0], j, layername,
                                                width, height, GIMP_GRAY,
                                                drawable_dst + j,
                                                pixel_rgn_dst + j);
        }
      else
        {
          image_ID_dst[j] = create_new_image (filename, NULL,
                                              width, height, GIMP_GRAY,
                                              xres, yres,
                                              layer_ID_dst + j,
                                              drawable_dst + j,
                                              pixel_rgn_dst + j);
        }

      g_free (filename);
      g_free (fname);
      dst[j] = g_new (guchar, tile_height * width);
    }

  i = 0;
  while (i < height)
    {
      /* Get source pixel region */
      scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i);
      gimp_pixel_rgn_get_rect (&pixel_rgn_src, src, 0, i, width, scan_lines);

      /* Extract the channel information */
      extract[extract_idx].extract_fun (src, drawable_src->bpp, scan_lines*width,
					dst);

      /* Transfer the registration color */
      if (decovals.use_registration)
        transfer_registration_color (src, drawable_src->bpp, scan_lines*width,
                                     dst, extract[extract_idx].num_images);

      /* Set destination pixel regions */
      for (j = 0; j < num_layers; j++)
	gimp_pixel_rgn_set_rect (&(pixel_rgn_dst[j]), dst[j], 0, i, width,
				 scan_lines);
      i += scan_lines;

      gimp_progress_update ((gdouble) i / (gdouble) height);
    }

  g_free (src);

  for (j = 0; j < num_layers; j++)
    {
      gimp_drawable_detach (drawable_dst[j]);
      gimp_drawable_update (layer_ID_dst[j], 0, 0,
                            gimp_drawable_width (layer_ID_dst[j]),
                            gimp_drawable_height (layer_ID_dst[j]));
      gimp_layer_add_alpha (layer_ID_dst[j]);
      g_free (dst[j]);
    }

  gimp_drawable_detach (drawable_src);

  *nlayers = num_layers;

  return (decovals.as_layers ? 1 : num_layers);
}
Exemplo n.º 7
0
static gint32
load_image (const gchar  *filename,
            gboolean      interactive,
            GError      **error)
{
  gint32 status = -1;
  EXRLoader *loader;
  int width;
  int height;
  gboolean has_alpha;
  GimpImageBaseType image_type;
  GimpPrecision image_precision;
  gint32 image = -1;
  GimpImageType layer_type;
  int layer;
  const Babl *format;
  GeglBuffer *buffer = NULL;
  int bpp;
  int tile_height;
  gchar *pixels = NULL;
  int begin;
  int end;
  int num;

  loader = exr_loader_new (filename);
  if (!loader)
    {
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("Error opening file '%s' for reading"),
                   gimp_filename_to_utf8 (filename));
      goto out;
    }

  width = exr_loader_get_width (loader);
  height = exr_loader_get_height (loader);
  if ((width < 1) || (height < 1))
    {
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("Error querying image dimensions from '%s'"),
                   gimp_filename_to_utf8 (filename));
      goto out;
    }

  has_alpha = exr_loader_has_alpha (loader) ? TRUE : FALSE;

  switch (exr_loader_get_precision (loader))
    {
    case PREC_UINT:
      image_precision = GIMP_PRECISION_U32;
      break;
    case PREC_HALF:
      image_precision = GIMP_PRECISION_HALF;
      break;
    case PREC_FLOAT:
      image_precision = GIMP_PRECISION_FLOAT;
      break;
    default:
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("Error querying image precision from '%s'"),
                   gimp_filename_to_utf8 (filename));
      goto out;
    }

  switch (exr_loader_get_image_type (loader))
    {
    case IMAGE_TYPE_RGB:
      image_type = GIMP_RGB;
      layer_type = has_alpha ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE;
      break;
    case IMAGE_TYPE_GRAY:
      image_type = GIMP_GRAY;
      layer_type = has_alpha ? GIMP_GRAYA_IMAGE : GIMP_GRAY_IMAGE;
      break;
    default:
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("Error querying image type from '%s'"),
                   gimp_filename_to_utf8 (filename));
      goto out;
    }

  gimp_progress_init_printf (_("Opening '%s'"),
                             gimp_filename_to_utf8 (filename));

  image = gimp_image_new_with_precision (width, height,
                                         image_type, image_precision);
  if (image == -1)
    {
      g_set_error (error, 0, 0,
                   _("Could not create new image for '%s': %s"),
                   gimp_filename_to_utf8 (filename), gimp_get_pdb_error ());
      goto out;
    }

  gimp_image_set_filename (image, filename);

  layer = gimp_layer_new (image, _("Background"), width, height,
                          layer_type, 100, GIMP_NORMAL_MODE);
  gimp_image_insert_layer (image, layer, -1, 0);

  buffer = gimp_drawable_get_buffer (layer);
  format = gimp_drawable_get_format (layer);
  bpp = babl_format_get_bytes_per_pixel (format);

  tile_height = gimp_tile_height ();
  pixels = g_new0 (gchar, tile_height * width * bpp);

  for (begin = 0; begin < height; begin += tile_height)
    {
      int retval;
      int i;
      end = MIN (begin + tile_height, height);
      num = end - begin;

      for (i = 0; i < num; i++)
        {
          retval = exr_loader_read_pixel_row (loader,
                                              pixels + (i * width * bpp),
                                              bpp, begin + i);
          if (retval < 0)
            {
              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                           _("Error reading pixel data from '%s'"),
                           gimp_filename_to_utf8 (filename));
              goto out;
            }
        }

      gegl_buffer_set (buffer, GEGL_RECTANGLE (0, begin, width, num),
                       0, NULL, pixels, GEGL_AUTO_ROWSTRIDE);

      gimp_progress_update ((gdouble) begin / (gdouble) height);
    }

  gimp_progress_update (1.0);

  status = image;

 out:
  if (buffer)
    g_object_unref (buffer);

  if ((status != image) && (image != -1))
    {
      /* This should clean up any associated layers too. */
      gimp_image_delete (image);
    }

  if (pixels)
    g_free (pixels);

  if (loader)
    exr_loader_unref (loader);

  return status;
}
Exemplo n.º 8
0
gint32
xjpg_load_layer (const char    *filename,
                 gint32         image_id,
                 int            image_type,
                 char          *layer_name,
                 gdouble        layer_opacity,
                 GimpLayerModeEffects     layer_mode
	    )
{
  GimpPixelRgn l_pixel_rgn;
  GimpDrawable *l_drawable;
  gint32     l_layer_id;
  GimpImageType  l_layer_type;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr jerr;
  FILE *infile;
  guchar *l_buf;
  guchar **l_rowbuf;
  int l_tile_height;
  int l_scanlines;
  int l_idx, l_start, l_end;

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

  l_layer_type = GIMP_GRAY_IMAGE;

  if ((infile = g_fopen (filename, "rb")) == NULL)
  {
      g_warning ("can't open \"%s\"\n", filename);
      return -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);

      g_printerr ("XJT: JPEG load error\n");
      return -1;
  }

  /* 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);

  /* 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.
   */

  /* 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 */
  l_tile_height = gimp_tile_height ();
  l_buf = g_new (guchar, l_tile_height * cinfo.output_width * cinfo.output_components);
  l_rowbuf = g_new (guchar*, l_tile_height);

  for (l_idx = 0; l_idx < l_tile_height; l_idx++)
  {
    l_rowbuf[l_idx] = l_buf + cinfo.output_width * cinfo.output_components * l_idx;
  }

  /* Check jpeg file for layer type */
  switch (cinfo.output_components)
    {
    case 1:
      l_layer_type = GIMP_GRAY_IMAGE;
      break;
    case 3:
      l_layer_type = GIMP_RGB_IMAGE;
      break;
    default:
      g_printerr ("XJT: cant load layer %s (type is not GRAY and not RGB)\n", filename);
      fclose (infile);
      return -1;
    }


  l_layer_id = gimp_layer_new (image_id, layer_name,
			     cinfo.output_width,
			     cinfo.output_height,
			     l_layer_type,
			     layer_opacity,
			     layer_mode);
  if(l_layer_id < 0)
  {
      g_printerr ("XJT: cant create new layer\n");
      fclose (infile);
      return -1;
  }

  l_drawable = gimp_drawable_get (l_layer_id);
  gimp_pixel_rgn_init (&l_pixel_rgn, l_drawable, 0, 0, l_drawable->width, l_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)
  {
      l_start = cinfo.output_scanline;
      l_end = cinfo.output_scanline + l_tile_height;
      l_end = MIN (l_end, cinfo.output_height);
      l_scanlines = l_end - l_start;

      for (l_idx = 0; l_idx < l_scanlines; l_idx++)
      {
	jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &l_rowbuf[l_idx], 1);
      }

      gimp_pixel_rgn_set_rect (&l_pixel_rgn, l_buf, 0, l_start, l_drawable->width, l_scanlines);

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

  /* 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 (l_rowbuf);
  g_free (l_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).
   */

  return (l_layer_id);

}	/* end xjpg_load_layer */
Exemplo n.º 9
0
gint
xjpg_save_drawable (const char     *filename,
                    gint32          image_ID,
                    gint32          drawable_ID,
                    gint            save_mode,
                    t_JpegSaveVals *jsvals)
{
  GimpPixelRgn pixel_rgn;
  GimpDrawable *drawable;
  GimpImageType drawable_type;
  struct jpeg_compress_struct cinfo;
  struct my_error_mgr jerr;
  FILE * volatile outfile;
  guchar *temp, *t;
  guchar *data;
  guchar *src, *s;
  int has_alpha;
  int rowstride, yend;
  int i, j;
  int alpha_offset;
  guchar alpha_byte;
  guchar volatile l_alpha_sum;

  alpha_offset = 0;
  has_alpha = 0;
  src = NULL;
  temp = NULL;
  data = NULL;
  l_alpha_sum = 0xff;

  drawable = gimp_drawable_get (drawable_ID);
  drawable_type = gimp_drawable_type (drawable_ID);
  switch (drawable_type)
  {
    case GIMP_RGB_IMAGE:
    case GIMP_GRAY_IMAGE:
      if(save_mode == JSVM_ALPHA)
        return FALSE;              /* there is no alpha to save */
      break;
    case GIMP_RGBA_IMAGE:
    case GIMP_GRAYA_IMAGE:
      break;

    case GIMP_INDEXED_IMAGE:
      /*g_message ("jpeg: cannot operate on indexed color images");*/
      return FALSE;
      break;
    default:
      /*g_message ("jpeg: cannot operate on unknown image types");*/
      return FALSE;
      break;
  }



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


  /* Step 1: allocate and initialize JPEG compression object */

  /* We have to set up the error handler first, in case the initialization
   * step fails.  (Unlikely, but it could happen if you are out of memory.)
   * This routine fills in the contents of struct jerr, and returns jerr's
   * address which we place into the link field in cinfo.
   */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  outfile = NULL;
  /* 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_compress (&cinfo);
      if (outfile)
	fclose (outfile);
      if (drawable)
	gimp_drawable_detach (drawable);

      return FALSE;
    }

  /* Now we can initialize the JPEG compression object. */
  jpeg_create_compress (&cinfo);

  /* Step 2: specify data destination (eg, a file) */
  /* Note: steps 2 and 3 can be done in either order. */

  /* Here we use the library-supplied code to send compressed data to a
   * stdio stream.  You can also write your own code to do something else.
   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
   * requires it in order to write binary files.
   */
  if ((outfile = g_fopen (filename, "wb")) == NULL)
    {
      g_message ("can't open %s\n", filename);
      return FALSE;
    }
  jpeg_stdio_dest (&cinfo, outfile);

  /* Get the input image and a pointer to its data.
   */
  switch (drawable_type)
  {
    case GIMP_RGB_IMAGE:
    case GIMP_GRAY_IMAGE:
      /* # of color components per pixel */
      cinfo.input_components = drawable->bpp;
      has_alpha = 0;
      alpha_offset = 0;
      break;
    case GIMP_RGBA_IMAGE:
    case GIMP_GRAYA_IMAGE:
      if(save_mode == JSVM_ALPHA)
      {
 	cinfo.input_components = 1;
      }
      else
      {
        /* # of color components per pixel (minus the GIMP alpha channel) */
	cinfo.input_components = drawable->bpp - 1;
      }
      alpha_offset = drawable->bpp -1;
      has_alpha = 1;
      break;
    default:
      return FALSE;
      break;
  }

  /* Step 3: set parameters for compression */

  /* First we supply a description of the input image.
   * Four fields of the cinfo struct must be filled in:
   */
  /* image width and height, in pixels */
  cinfo.image_width = drawable->width;
  cinfo.image_height = drawable->height;
  /* colorspace of input image */
  cinfo.in_color_space = ( (save_mode != JSVM_ALPHA) &&
                          (drawable_type == GIMP_RGB_IMAGE ||
			   drawable_type == GIMP_RGBA_IMAGE))
    ? JCS_RGB : JCS_GRAYSCALE;
  /* Now use the library's routine to set default compression parameters.
   * (You must set at least cinfo.in_color_space before calling this,
   * since the defaults depend on the source color space.)
   */
  jpeg_set_defaults (&cinfo);
  /* Now you can set any non-default parameters you wish to.
   * Here we just illustrate the use of quality (quantization table) scaling:
   */
  jpeg_set_quality (&cinfo, (int) (jsvals->quality * 100), TRUE /* limit to baseline-JPEG values */);
  cinfo.smoothing_factor = (int) (jsvals->smoothing * 100);
  cinfo.optimize_coding = jsvals->optimize;

  /* Step 4: Start compressor */

  /* TRUE ensures that we will write a complete interchange-JPEG file.
   * Pass TRUE unless you are very sure of what you're doing.
   */
  jpeg_start_compress (&cinfo, TRUE);

  /* Step 5: while (scan lines remain to be written) */
  /*           jpeg_write_scanlines(...); */

  /* Here we use the library's state variable cinfo.next_scanline as the
   * loop counter, so that we don't have to keep track ourselves.
   * To keep things simple, we pass one scanline per call; you can pass
   * more if you wish, though.
   */
  /* JSAMPLEs per row in image_buffer */
  rowstride = drawable->bpp * drawable->width;
  temp = (guchar *) g_malloc (cinfo.image_width * cinfo.input_components);
  data = (guchar *) g_malloc (rowstride * gimp_tile_height ());
  src = data;

  while (cinfo.next_scanline < cinfo.image_height)
  {
      if ((cinfo.next_scanline % gimp_tile_height ()) == 0)
      {
	  yend = cinfo.next_scanline + gimp_tile_height ();
	  yend = MIN (yend, cinfo.image_height);
	  gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, cinfo.next_scanline, cinfo.image_width,
				   (yend - cinfo.next_scanline));
	  src = data;
      }

      t = temp;
      s = src;
      i = cinfo.image_width;

      switch(save_mode)
      {
	case JSVM_DRAWABLE:
	    if(jsvals->clr_transparent)
	    {
	      /* save drawable (clear pixels where alpha is full transparent) */
	      while (i--)
	      {
	          alpha_byte = s[cinfo.input_components];
		  for (j = 0; j < cinfo.input_components; j++)
		  {
		     if(alpha_byte != 0) { *t++ = *s++;   }
		     else                { *t++ = 0; s++; }
		  }
		  if (has_alpha)  /* ignore alpha channel */
		  {
		    s++;
		  }
	      }
	    }
	    else
	    {
	      /* save the drawable as it is (ignore alpha channel) */
	      while (i--)
	      {
		  for (j = 0; j < cinfo.input_components; j++)
		  {
                    *t++ = *s++;
		  }
		  if (has_alpha)  /* ignore alpha channel */
		  {
		    s++;
		  }
	      }
	    }
	    break;
        case JSVM_ALPHA:
	    /* save the drawable's alpha cahnnel */
	    while (i--)
	    {
		s += alpha_offset;
		l_alpha_sum &= (*s);  /* check all alpha bytes for full opacity */
                *t++ = *s++;
	    }
	    break;
      }

      src += rowstride;
      jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &temp, 1);

      if ((cinfo.next_scanline % 5) == 0)
	gimp_progress_update ((double) cinfo.next_scanline / (double) cinfo.image_height);
  }
  gimp_progress_update (1.0);

  /* Step 6: Finish compression */
  jpeg_finish_compress (&cinfo);
  /* After finish_compress, we can close the output file. */
  fclose (outfile);

  if((save_mode == JSVM_ALPHA) && (l_alpha_sum == 0xff))
  {
    /* all bytes in the alpha channel are set to 0xff
     * == full opaque image. We can remove the file
     * to save diskspace
     */
    g_remove(filename);
  }

  /* Step 7: release JPEG compression object */

  /* This is an important step since it will release a good deal of memory. */
  jpeg_destroy_compress (&cinfo);
  /* free the temporary buffer */
  g_free (temp);
  g_free (data);

  gimp_drawable_detach (drawable);

  return TRUE;
}	/* end xjpg_save_drawable */
Exemplo n.º 10
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;
}
Exemplo n.º 11
0
void ptRun(const gchar*     Name,
           gint       NrParameters,
           const GimpParam* Parameter,
           gint *nreturn_vals,
           GimpParam **return_vals) {
  printf("(%s,%d) '%s'\n",__FILE__,__LINE__,__PRETTY_FUNCTION__);
  printf("Name         : '%s'\n",Name);
  printf("NrParameters : %d\n",NrParameters);
  if (!strcmp(Name,"photivoSendToGimp")) {
    printf("RunMode      : %d\n",Parameter[0].data.d_int32);
    printf("FileName1    : '%s'\n",Parameter[1].data.d_string);
    printf("FileName2    : '%s'\n",Parameter[2].data.d_string);

    QFile GimpFile(Parameter[1].data.d_string);
    bool result = GimpFile.open(QIODevice::ReadOnly | QIODevice::Text);
    assert(result);

    QTextStream In(&GimpFile);

    QString ImageFileName = In.readLine();
    QString ExifFileName  = In.readLine();
    QString ICCFileName   = In.readLine();

    // Read image
    FILE *InputFile = fopen(ImageFileName.toLocal8Bit().data(),"rb");
    if (!InputFile) {
      ptLogError(1,ImageFileName.toLocal8Bit().data());
      return; // ptError_FileOpen;
    }

    short    Colors;
    unsigned short Width;
    unsigned short Height;
    unsigned short BitsPerColor;
    char     Buffer[128];

    // Extremely naive. Probably just enough for testcases.
    char *s = fgets(Buffer,127,InputFile);
    assert ( s );
    int n = sscanf(Buffer,"P%hd",&Colors);
    assert ( 1 == n );
    assert(Colors == 6 );
    do {
      s = fgets(Buffer,127,InputFile);
      assert ( s );
    } while (Buffer[0] == '#');
    sscanf(Buffer,"%hd %hd",&Width,&Height);
    s = fgets(Buffer,127,InputFile);
    assert ( s );
    sscanf(Buffer,"%hd",&BitsPerColor);
    assert(BitsPerColor == 0xffff);

    Colors = 3;

    unsigned short (* ImageForGimp)[3] =
      (unsigned short (*)[3]) CALLOC2(Width*Height,sizeof(*ImageForGimp));
    ptMemoryError(ImageForGimp,__FILE__,__LINE__);

    unsigned short*  PpmRow = (unsigned short *) CALLOC2(Width*Height,sizeof(*PpmRow));
    ptMemoryError(PpmRow,__FILE__,__LINE__);

    for (unsigned short Row=0; Row<Height; Row++) {
      size_t RV = fread(PpmRow,Colors*2,Width,InputFile);
      if (RV != (size_t) Width) {
        printf("ReadPpm error. Expected %d bytes. Got %d\n",Width,(int)RV);
        exit(EXIT_FAILURE);
      }
      if (htons(0x55aa) != 0x55aa) {
        swab((char *)PpmRow,(char *)PpmRow,Width*Colors*2);
      }
      for (unsigned short Col=0; Col<Width; Col++) {
        for (short c=0;c<3;c++) {
          ImageForGimp[Row*Width+Col][c] = PpmRow[Col*Colors+c];
        }
      }
    }

    FREE2(PpmRow);
    FCLOSE(InputFile);

    QFile ExifFile(ExifFileName);
    result = ExifFile.open(QIODevice::ReadOnly);
    assert(result);
    qint64 FileSize = ExifFile.size();
    QDataStream ExifIn(&ExifFile);
    char* ExifBuffer = (char *) MALLOC2(FileSize);
    ptMemoryError(ExifBuffer,__FILE__,__LINE__);
    unsigned ExifBufferLength = ExifIn.readRawData(ExifBuffer,FileSize);
    ExifFile.close();

    QFile ICCFile(ICCFileName);
    result = ICCFile.open(QIODevice::ReadOnly);
    assert(result);
    qint64 FileSize2 = ICCFile.size();
    QDataStream ICCIn(&ICCFile);
    char* ICCBuffer = (char *) MALLOC2(FileSize2);
    ptMemoryError(ICCBuffer,__FILE__,__LINE__);
    unsigned ICCBufferLength = ICCIn.readRawData(ICCBuffer,FileSize2);
    ICCFile.close();

    // And now copy to gimp.
    gint32 GimpImage = gimp_image_new(Width,
                                      Height,
                                      GIMP_RGB);
    assert (GimpImage != -1);
    gint32 GimpLayer = gimp_layer_new(GimpImage,
                                      "BG",
                                      Width,
                                      Height,
                                      GIMP_RGB_IMAGE,
                                      100.0,
                                      GIMP_NORMAL_MODE);
#if GIMP_MINOR_VERSION<=6
    gimp_image_add_layer(GimpImage,GimpLayer,0);
#else
    gimp_image_insert_layer(GimpImage,GimpLayer,0,0);
#endif
    GimpDrawable* Drawable = gimp_drawable_get(GimpLayer);
    GimpPixelRgn PixelRegion;
    gimp_pixel_rgn_init(&PixelRegion,
                        Drawable,
                        0,
                        0,
                        Drawable->width,
                        Drawable->height,
                        true,
                        false);
    unsigned short TileHeight = gimp_tile_height();
    for (unsigned short Row=0; Row<Height; Row+=TileHeight) {
      unsigned short NrRows = MIN(Height-Row, (int)TileHeight);
      guint8* Buffer = g_new(guint8,TileHeight*Width*3);
      for (unsigned short i=0; i<NrRows; i++) {
        for (unsigned short j=0; j<Width; j++) {
          for (short c=0;c<3;c++) {
            Buffer[3*(i*Width+j)+c] =
              ImageForGimp[(Row+i)*Width+j][c]>>8;
          }
        }
      }
      gimp_pixel_rgn_set_rect(&PixelRegion,
                              Buffer,
                              0,
                              Row,
                              Width,
                              NrRows);
      g_free(Buffer);
    }
    gimp_drawable_flush(Drawable);
    gimp_drawable_detach(Drawable);
    FREE2(ImageForGimp);
    GimpParasite* GimpExifData = gimp_parasite_new("exif-data",
                                                   GIMP_PARASITE_PERSISTENT,
                                                   ExifBufferLength,
                                                   ExifBuffer);
    gimp_image_parasite_attach(GimpImage,GimpExifData);
    gimp_parasite_free(GimpExifData);
    FREE2(ExifBuffer);

    GimpParasite* GimpICCData = gimp_parasite_new("icc-profile",
                                                   GIMP_PARASITE_PERSISTENT,
                                                   ICCBufferLength,
                                                   ICCBuffer);
    gimp_image_parasite_attach(GimpImage,GimpICCData);
    gimp_parasite_free(GimpICCData);
    FREE2(ICCBuffer);

    static GimpParam Values[2];
    *nreturn_vals = 2;
    *return_vals = Values;
    Values[0].type = GIMP_PDB_STATUS;
    Values[0].data.d_status = GIMP_PDB_SUCCESS;
    Values[1].type = GIMP_PDB_IMAGE;
    Values[1].data.d_image = GimpImage;

    QFile::remove(ImageFileName);
    QFile::remove(ExifFileName);
    QFile::remove(ICCFileName);
    QFile::remove(Parameter[1].data.d_string);

  }
Exemplo n.º 12
0
static void
rotate_drawable (GimpDrawable *drawable)
{
  GimpPixelRgn  srcPR, destPR;
  gint          width, height;
  gint          longside;
  gint          bytes;
  gint          row, col;
  gint          offsetx, offsety;
  gboolean      was_lock_alpha = FALSE;
  guchar       *buffer;
  guchar       *src_row, *dest_row;

  /* initialize */

  row = 0;

  /* Get the size of the input drawable. */
  width = drawable->width;
  height = drawable->height;
  bytes = drawable->bpp;

  if (gimp_layer_get_lock_alpha (drawable->drawable_id))
    {
      was_lock_alpha = TRUE;
      gimp_layer_set_lock_alpha (drawable->drawable_id, FALSE);
    }

  if (rotvals.angle == 2)  /* we're rotating by 180° */
    {
      gimp_tile_cache_ntiles (2 * (width / gimp_tile_width() + 1));

      gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height,
                           FALSE, FALSE);
      gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height,
                           TRUE, TRUE);

      src_row  = (guchar *) g_malloc (width * bytes);
      dest_row = (guchar *) g_malloc (width * bytes);

      for (row = 0; row < height; row++)
        {
          gimp_pixel_rgn_get_row (&srcPR, src_row, 0, row, width);
          for (col = 0; col < width; col++)
            {
              memcpy (dest_row + col * bytes,
                      src_row + (width - 1 - col) * bytes,
                      bytes);
            }
          gimp_pixel_rgn_set_row (&destPR, dest_row, 0, (height - row - 1),
                                  width);

          if ((row % 5) == 0)
            gimp_progress_update ((double) row / (double) height);
        }

      g_free (src_row);
      g_free (dest_row);

      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id, 0, 0, width, height);

    }
  else                     /* we're rotating by 90° or 270° */
    {
      (width > height) ? (longside = width) : (longside = height);

      gimp_layer_resize (drawable->drawable_id, longside, longside, 0, 0);
      drawable = gimp_drawable_get (drawable->drawable_id);
      gimp_drawable_flush (drawable);

      gimp_tile_cache_ntiles ((longside / gimp_tile_width () + 1) +
                              (longside / gimp_tile_height () + 1));

      gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, longside, longside,
                           FALSE, FALSE);
      gimp_pixel_rgn_init (&destPR, drawable, 0, 0, longside, longside,
                           TRUE, TRUE);

      buffer = g_malloc (longside * bytes);

      if (rotvals.angle == 1)     /* we're rotating by 90° */
        {
          for (row = 0; row < height; row++)
            {
              gimp_pixel_rgn_get_row (&srcPR, buffer, 0, row, width);
              gimp_pixel_rgn_set_col (&destPR, buffer, (height - row - 1), 0,
                                      width);

              if ((row % 5) == 0)
                gimp_progress_update ((double) row / (double) height);
            }
        }
      else                        /* we're rotating by 270° */
        {
          for (col = 0; col < width; col++)
            {
              gimp_pixel_rgn_get_col (&srcPR, buffer, col, 0, height);
              gimp_pixel_rgn_set_row (&destPR, buffer, 0, (width - col - 1),
                                      height);

              if ((col % 5) == 0)
                gimp_progress_update ((double) col / (double) width);
            }
        }

      g_free (buffer);

      gimp_progress_update (1.0);

      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id, 0, 0, height, width);

      gimp_layer_resize (drawable->drawable_id, height, width, 0, 0);
      drawable = gimp_drawable_get (drawable->drawable_id);
      gimp_drawable_flush (drawable);
      gimp_drawable_update (drawable->drawable_id, 0, 0, height, width);
    }

  gimp_drawable_offsets (drawable->drawable_id, &offsetx, &offsety);
  rotate_compute_offsets (&offsetx, &offsety,
                          gimp_image_width (image_ID),
                          gimp_image_height (image_ID),
                          width, height);
  gimp_layer_set_offsets (drawable->drawable_id, offsetx, offsety);

  if (was_lock_alpha)
    gimp_layer_set_lock_alpha (drawable->drawable_id, TRUE);

  return;
}
static void
run (const gchar *name,          /* name of plugin */
     gint nparams,               /* number of in-paramters */
     const GimpParam * param,    /* in-parameters */
     gint *nreturn_vals,         /* number of out-parameters */
     GimpParam ** return_vals)   /* out-parameters */
{
  const gchar *l_env;
  gint32       image_id = -1;
  gboolean doProgress;
  gboolean doFlush;
  GapLastvalAnimatedCallInfo  animCallInfo;


  /* Get the runmode from the in-parameters */
  GimpRunMode run_mode = param[0].data.d_int32;

  /* status variable, use it to check for errors in invocation usualy only
     during non-interactive calling */
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;

  /* always return at least the status to the caller. */
  static GimpParam values[2];

  INIT_I18N();

  l_env = g_getenv("GAP_DEBUG");
  if(l_env != NULL)
  {
    if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1;
  }

  if(gap_debug)
  {
    printf("\n\nDEBUG: run %s\n", name);
  }



  if(strcmp(name, GAP_DETAIL_TRACKING_XML_ALIGNER_PLUG_IN_NAME) == 0)
  {
    runXmlAlign(name, nparams, param, nreturn_vals, return_vals);
    return;
  }

  if(strcmp(name, GAP_EXACT_ALIGNER_PLUG_IN_NAME) == 0)
  {
    runExactAlign(name, nparams, param, nreturn_vals, return_vals);
    return;
  }


  doProgress = FALSE;
  doFlush = FALSE;

  /* initialize the return of the status */
  values[0].type = GIMP_PDB_STATUS;
  values[0].data.d_status = status;
  values[1].type = GIMP_PDB_DRAWABLE;
  values[1].data.d_drawable = -1;
  *nreturn_vals = 2;
  *return_vals = values;

  /* init default values and Possibly retrieve data from a previous interactive run */
  gap_detail_tracking_get_values(&fiVals);

  /* get image and drawable */
  image_id = param[1].data.d_int32;


  /* how are we running today? */
  switch (run_mode)
  {
    case GIMP_RUN_INTERACTIVE:
      /* detail tracking primary feature is intended to work without dialog interaction
       * when ivoked by menu or keyboard shortcut using PLUG_IN_NAME.
       * This plug in also registers with a 2nd variant PLUG_IN_NAME_CFG
       * where the user can configure the options (for one gimp session)
       */
      if(strcmp(name, PLUG_IN_NAME_CFG) ==0)
      {
        gboolean dialogOk;

        if (fiVals.coordsRelToFrame1)
        {
          /* default offsets for handle at center */
          fiVals.offsX = gimp_image_width(image_id) / 2.0;
          fiVals.offsY = gimp_image_height(image_id) / 2.0;
        }


        dialogOk = gap_detail_tracking_dialog(&fiVals);
        if( dialogOk != TRUE)
        {
          status = GIMP_PDB_CALLING_ERROR;
        }

      }
      doProgress = TRUE;
      doFlush =  TRUE;
      break;

    case GIMP_RUN_NONINTERACTIVE:
      /* check to see if invoked with the correct number of parameters */
      if (nparams == global_number_in_args)
      {
          fiVals.refShapeRadius               = param[3].data.d_int32;
          fiVals.targetMoveRadius             = param[4].data.d_int32;
          fiVals.loacteColodiffThreshold      = param[5].data.d_float;
          fiVals.coordsRelToFrame1            = (param[6].data.d_int32 == 0) ? FALSE : TRUE;
          fiVals.offsX                        = param[7].data.d_int32;
          fiVals.offsY                        = param[8].data.d_int32;
          fiVals.offsRotate                   = param[9].data.d_float;
          fiVals.enableScaling                = (param[10].data.d_int32 == 0) ? FALSE : TRUE;
          fiVals.bgLayerIsReference           = (param[11].data.d_int32 == 0) ? FALSE : TRUE;
          fiVals.removeMidlayers              = (param[12].data.d_int32 == 0) ? FALSE : TRUE;

          fiVals.moveLogFile[0] = '\0';
          if(param[13].data.d_string != NULL)
          {
            g_snprintf(fiVals.moveLogFile, sizeof(fiVals.moveLogFile) -1, "%s", param[13].data.d_string);
          }

      }
      else
      {
        status = GIMP_PDB_CALLING_ERROR;
      }

      break;

    case GIMP_RUN_WITH_LAST_VALS:
      animCallInfo.animatedCallInProgress = FALSE;
      gimp_get_data(GAP_LASTVAL_KEY_ANIMATED_CALL_INFO, &animCallInfo);

      if(animCallInfo.animatedCallInProgress != TRUE)
      {
        doProgress = TRUE;
        doFlush =  TRUE;
      }
      break;

    default:
      break;
  }

  if (status == GIMP_PDB_SUCCESS)
  {
    gulong cache_ntiles;
    gulong regionTileWidth;
    gulong regionTileHeight;

    gimp_image_undo_group_start (image_id);

    /* this plug in repeatedly accesses the same tiles in the same pixel regionsarea
     * therefore tile caching is essential for performance reason
     * therefore calculate optimal tile cache size (but limit to 300 tiles that should be enogh
     * in most practical use cases)
     */
    regionTileWidth = 1 + (2 * (fiVals.targetMoveRadius + fiVals.refShapeRadius))/ gimp_tile_width() ;
    regionTileHeight = 1 + (2 * (fiVals.targetMoveRadius + fiVals.refShapeRadius))/ gimp_tile_height() ;

    /* processing may track 2 details in different regions of same size */
    cache_ntiles = (regionTileWidth * regionTileHeight) * 2;

    gimp_tile_cache_ntiles (MAX(300, cache_ntiles));

    /* Run the main function */
    values[1].data.d_drawable =
          gap_track_detail_on_top_layers(image_id, doProgress, &fiVals);

    gimp_image_undo_group_end (image_id);

    if (values[1].data.d_drawable < 0)
    {
       status = GIMP_PDB_CALLING_ERROR;
    }

    /* If run mode is interactive, flush displays, else (script) don't
     * do it, as the screen updates would make the scripts slow
     */
    if (doFlush)
    {
      gimp_displays_flush ();
    }


  }
  values[0].data.d_status = status;

}       /* end run */
Exemplo n.º 14
0
gint32
load_thumbnail_image (const gchar  *filename,
                      gint         *width,
                      gint         *height,
                      GError      **error)
{
  gint32 volatile  image_ID;
  ExifData        *exif_data;
  GimpPixelRgn     pixel_rgn;
  GimpDrawable    *drawable;
  gint32           layer_ID;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr           jerr;
  guchar          *buf;
  guchar         **rowbuf;
  gint             image_type;
  gint             layer_type;
  gint             tile_height;
  gint             scanlines;
  gint             i, start, end;
  gint             orientation;
  my_src_ptr       src;
  FILE            *infile;

  image_ID = -1;
  exif_data = jpeg_exif_data_new_from_file (filename, NULL);

  if (! ((exif_data) && (exif_data->data) && (exif_data->size > 0)))
    return -1;

  orientation = jpeg_exif_get_orientation (exif_data);

  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit     = my_error_exit;
  jerr.pub.output_message = my_output_message;

  gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
                             gimp_filename_to_utf8 (filename));

  /* 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 (image_ID != -1)
        gimp_image_delete (image_ID);

      if (exif_data)
        {
          exif_data_unref (exif_data);
          exif_data = NULL;
        }

      return -1;
    }

  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress (&cinfo);

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

  if (cinfo.src == NULL)
    cinfo.src = (struct jpeg_source_mgr *)(*cinfo.mem->alloc_small)
      ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
       sizeof (my_source_mgr));

  src = (my_src_ptr) cinfo.src;

  src->pub.init_source       = init_source;
  src->pub.fill_input_buffer = fill_input_buffer;
  src->pub.skip_input_data   = skip_input_data;
  src->pub.resync_to_restart = jpeg_resync_to_restart;
  src->pub.term_source       = term_source;

  src->pub.bytes_in_buffer   = exif_data->size;
  src->pub.next_input_byte   = exif_data->data;

  src->buffer = exif_data->data;
  src->size = exif_data->size;

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

  jpeg_read_header (&cinfo, TRUE);

  /* 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.
   */

  /* 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.
   */
  switch (cinfo.output_components)
    {
    case 1:
      image_type = GIMP_GRAY;
      layer_type = GIMP_GRAY_IMAGE;
      break;

    case 3:
      image_type = GIMP_RGB;
      layer_type = GIMP_RGB_IMAGE;
      break;

    case 4:
      if (cinfo.out_color_space == JCS_CMYK)
        {
          image_type = GIMP_RGB;
          layer_type = GIMP_RGB_IMAGE;
          break;
        }
      /*fallthrough*/

    default:
      g_message ("Don't know how to load JPEG images "
                 "with %d color channels, using colorspace %d (%d).",
                 cinfo.output_components, cinfo.out_color_space,
                 cinfo.jpeg_color_space);

      if (exif_data)
        {
          exif_data_unref (exif_data);
          exif_data = NULL;
        }

      return -1;
      break;
    }

  image_ID = gimp_image_new (cinfo.output_width, cinfo.output_height,
                             image_type);

  gimp_image_undo_disable (image_ID);
  gimp_image_set_filename (image_ID, filename);

  jpeg_load_resolution (image_ID, &cinfo);

  layer_ID = gimp_layer_new (image_ID, _("Background"),
                             cinfo.output_width,
                             cinfo.output_height,
                             layer_type, 100, GIMP_NORMAL_MODE);

  drawable_global = 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, cinfo.output_height);
      scanlines = end - start;

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

      if (cinfo.out_color_space == JCS_CMYK)
        jpeg_load_cmyk_to_rgb (buf, drawable->width * scanlines, NULL);

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

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

  /* 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);

  /* At this point you may want to check to see whether any
   * corrupt-data warnings occurred (test whether
   * jerr.num_warnings is nonzero).
   */
  gimp_image_insert_layer (image_ID, layer_ID, -1, 0);


  /* NOW to get the dimensions of the actual image to return the
   * calling app
   */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;
  jerr.pub.output_message = my_output_message;

  if ((infile = g_fopen (filename, "rb")) == NULL)
    {
      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
                   _("Could not open '%s' for reading: %s"),
                   gimp_filename_to_utf8 (filename), g_strerror (errno));

      if (exif_data)
        {
          exif_data_unref (exif_data);
          exif_data = NULL;
        }

      return -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 (image_ID != -1)
        gimp_image_delete (image_ID);

      if (exif_data)
        {
          exif_data_unref (exif_data);
          exif_data = NULL;
        }

      return -1;
    }

  /* 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);

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

  jpeg_read_header (&cinfo, TRUE);

  jpeg_start_decompress (&cinfo);

  *width  = cinfo.output_width;
  *height = cinfo.output_height;

  /* Step 4: Release JPEG decompression object */

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

  fclose (infile);

  if (exif_data)
    {
      exif_data_unref (exif_data);
      exif_data = NULL;
    }

  jpeg_exif_rotate (image_ID, orientation);

  return image_ID;
}
Exemplo n.º 15
0
static gint
save_image (char   *filename,
	    gint32  image_ID,
	    gint32  drawable_ID)
{
  GPixelRgn pixel_rgn;
  TileDrawable *drawable;
  GDrawableType drawable_type;
  struct jpeg_compress_struct cinfo;
  struct my_error_mgr jerr;
  FILE *outfile;
  guchar *temp, *t;
  guchar *data;
  guchar *src, *s;
  char *name;
  int has_alpha;
  GimpExportReturnType export = GIMP_EXPORT_CANCEL;
  gint32 e_image_ID = -1;
  gint32 e_drawable_ID = -1;
  GPrecisionType precision;

  int rowstride, yend;
  int i, j;

  drawable = gimp_drawable_get (drawable_ID);
  drawable_type = gimp_drawable_type (drawable_ID);
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);

  name = malloc (strlen (filename) + 11);

  sprintf (name, "%s %s:",_("Saving"), filename);
  gimp_progress_init (name);
  free (name);

  /* Step 1: allocate and initialize JPEG compression object */

  /* We have to set up the error handler first, in case the initialization
   * step fails.  (Unlikely, but it could happen if you are out of memory.)
   * This routine fills in the contents of struct jerr, and returns jerr's
   * address which we place into the link field in cinfo.
   */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  outfile = NULL;
  /* 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_compress (&cinfo);
      if (outfile)
	fclose (outfile);
      if (drawable)
	gimp_drawable_detach (drawable);

      return FALSE;
    }

  /* Now we can initialize the JPEG compression object. */
  jpeg_create_compress (&cinfo);

  /* Step 2: specify data destination (eg, a file) */
  /* Note: steps 2 and 3 can be done in either order. */

  /* Here we use the library-supplied code to send compressed data to a
   * stdio stream.  You can also write your own code to do something else.
   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
   * requires it in order to write binary files.
   */
  if ((outfile = fopen (filename, "wb")) == NULL)
    {
      fprintf (stderr, "can't open %s\n", filename);
      return FALSE;
    }
  jpeg_stdio_dest (&cinfo, outfile);

  /* Get the input image and a pointer to its data.
   */
  cinfo.input_components = gimp_drawable_num_channels(drawable_ID);
  has_alpha = gimp_drawable_has_alpha(drawable_ID);
  if(has_alpha)
    --cinfo.input_components;

  /* Step 3: set parameters for compression */

  /* First we supply a description of the input image.
   * Four fields of the cinfo struct must be filled in:
   */
  /* image width and height, in pixels */
  cinfo.image_width = drawable->width;
  cinfo.image_height = drawable->height;
  /* colorspace of input image */
  cinfo.in_color_space = gimp_drawable_color(drawable_ID) 
    ? JCS_RGB : JCS_GRAYSCALE;

  /* Now use the library's routine to set default compression parameters.
   * (You must set at least cinfo.in_color_space before calling this,
   * since the defaults depend on the source color space.)
   */
  jpeg_set_defaults (&cinfo);
  /* Now you can set any non-default parameters you wish to.
   * Here we just illustrate the use of quality (quantization table) scaling:
   */
  jpeg_set_quality (&cinfo, (int) (jsvals.quality * 100), TRUE /* limit to baseline-JPEG values */);
  cinfo.smoothing_factor = (int) (jsvals.smoothing * 100);
  cinfo.optimize_coding = jsvals.optimize;

  /* Step 4: Start compressor */

  /* TRUE ensures that we will write a complete interchange-JPEG file.
   * Pass TRUE unless you are very sure of what you're doing.
   */
  jpeg_start_compress (&cinfo, TRUE);

  // Step 4a: write icc profile
  {
    char *buffer = NULL;
    int size = 0;

    if (gimp_image_has_icc_profile (image_ID, ICC_IMAGE_PROFILE)) { 
      buffer = gimp_image_get_icc_profile_by_mem (image_ID, &size, ICC_IMAGE_PROFILE);
      if (buffer) {
        write_icc_profile (&cinfo, buffer, size);
        printf ("%s:%d %s() embedded icc profile\n",__FILE__,__LINE__,__func__);
      }
    }
  }

  /* Step 5: while (scan lines remain to be written) */
  /*           jpeg_write_scanlines(...); */

  /* Here we use the library's state variable cinfo.next_scanline as the
   * loop counter, so that we don't have to keep track ourselves.
   * To keep things simple, we pass one scanline per call; you can pass
   * more if you wish, though.
   */
  /* JSAMPLEs per row in image_buffer */
  rowstride = drawable->bpp * drawable->width;
  temp = (guchar *) malloc (cinfo.image_width * cinfo.input_components * 4);
  data = (guchar *) malloc (rowstride * gimp_tile_height ());

        export = gimp_export_image (&image_ID, &drawable_ID, "Jpeg",
Exemplo n.º 16
0
/* This function is nearly identical to the function 'tile_cache_insert'
 *  in the file 'tile_cache.c' which is part of the main gimp application.
 */
static void
gimp_tile_cache_insert (GimpTile *tile)
{
  GList *list;

  if (!tile_hash_table)
    {
      tile_hash_table = g_hash_table_new (g_direct_hash, NULL);
      max_tile_size = gimp_tile_width () * gimp_tile_height () * 4;
    }

  /* First check and see if the tile is already
   *  in the cache. In that case we will simply place
   *  it at the end of the tile list to indicate that
   *  it was the most recently accessed tile.
   */
  list = g_hash_table_lookup (tile_hash_table, tile);

  if (list)
    {
      /* The tile was already in the cache. Place it at
       *  the end of the tile list.
       */

      /* If the tile is already at the end of the list, we are done */
      if (list == tile_list_tail)
        return;

      /* At this point we have at least two elements in our list */
      g_assert (tile_list_head != tile_list_tail);

      tile_list_head = g_list_remove_link (tile_list_head, list);

      tile_list_tail = g_list_last (g_list_concat (tile_list_tail, list));
    }
  else
    {
      /* The tile was not in the cache. First check and see
       *  if there is room in the cache. If not then we'll have
       *  to make room first. Note: it might be the case that the
       *  cache is smaller than the size of a tile in which case
       *  it won't be possible to put it in the cache.
       */

      if ((cur_cache_size + max_tile_size) > max_cache_size)
        {
          while (tile_list_head &&
                 (cur_cache_size +
                  max_cache_size * FREE_QUANTUM) > max_cache_size)
            {
              gimp_tile_cache_flush ((GimpTile *) tile_list_head->data);
            }

          if ((cur_cache_size + max_tile_size) > max_cache_size)
            return;
        }

      /* Place the tile at the end of the tile list.
       */
      tile_list_tail = g_list_append (tile_list_tail, tile);

      if (! tile_list_head)
        tile_list_head = tile_list_tail;

      tile_list_tail = g_list_last (tile_list_tail);

      /* Add the tiles list node to the tile hash table.
       */
      g_hash_table_insert (tile_hash_table, tile, tile_list_tail);

      /* Note the increase in the number of bytes the cache
       *  is referencing.
       */
      cur_cache_size += max_tile_size;

      /* Reference the tile so that it won't be returned to
       *  the main gimp application immediately.
       */
      tile->ref_count++;
    }
}
Exemplo n.º 17
0
gboolean
save_image (const gchar  *filename,
            gint32        image_ID,
            gint32        drawable_ID,
            gint32        orig_image_ID,
            gboolean      preview,
            GError      **error)
{
  GimpImageType  drawable_type;
  GeglBuffer    *buffer = NULL;
  const Babl    *format;
  GimpParasite  *parasite;
  static struct jpeg_compress_struct cinfo;
  static struct my_error_mgr         jerr;
  JpegSubsampling             subsampling;
  FILE     * volatile outfile;
  guchar   *data;
  guchar   *src;
  gboolean  has_alpha;
  gint      rowstride, yend;

  drawable_type = gimp_drawable_type (drawable_ID);
  buffer = gimp_drawable_get_buffer (drawable_ID);

  if (! preview)
    gimp_progress_init_printf (_("Saving '%s'"),
                               gimp_filename_to_utf8 (filename));

  /* Step 1: allocate and initialize JPEG compression object */

  /* We have to set up the error handler first, in case the initialization
   * step fails.  (Unlikely, but it could happen if you are out of memory.)
   * This routine fills in the contents of struct jerr, and returns jerr's
   * address which we place into the link field in cinfo.
   */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  outfile = NULL;
  /* 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_compress (&cinfo);
      if (outfile)
        fclose (outfile);
      if (buffer)
        g_object_unref (buffer);

      return FALSE;
    }

  /* Now we can initialize the JPEG compression object. */
  jpeg_create_compress (&cinfo);

  /* Step 2: specify data destination (eg, a file) */
  /* Note: steps 2 and 3 can be done in either order. */

  /* Here we use the library-supplied code to send compressed data to a
   * stdio stream.  You can also write your own code to do something else.
   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
   * requires it in order to write binary files.
   */
  if ((outfile = g_fopen (filename, "wb")) == NULL)
    {
      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
                   _("Could not open '%s' for writing: %s"),
                   gimp_filename_to_utf8 (filename), g_strerror (errno));
      return FALSE;
    }

  jpeg_stdio_dest (&cinfo, outfile);

  /* Get the input image and a pointer to its data.
   */
  switch (drawable_type)
    {
    case GIMP_RGB_IMAGE:
      /* # of color components per pixel */
      cinfo.input_components = 3;
      has_alpha = FALSE;
      format = babl_format ("R'G'B' u8");
      break;

    case GIMP_GRAY_IMAGE:
      /* # of color components per pixel */
      cinfo.input_components = 1;
      has_alpha = FALSE;
      format = babl_format ("Y' u8");
      break;

    case GIMP_RGBA_IMAGE:
      /* # of color components per pixel (minus the GIMP alpha channel) */
      cinfo.input_components = 4 - 1;
      has_alpha = TRUE;
      format = babl_format ("R'G'B' u8");
      break;

    case GIMP_GRAYA_IMAGE:
      /* # of color components per pixel (minus the GIMP alpha channel) */
      cinfo.input_components = 2 - 1;
      has_alpha = TRUE;
      format = babl_format ("Y' u8");
      break;

    case GIMP_INDEXED_IMAGE:
    default:
      return FALSE;
    }

  /* Step 3: set parameters for compression */

  /* First we supply a description of the input image.
   * Four fields of the cinfo struct must be filled in:
   */
  /* image width and height, in pixels */
  cinfo.image_width  = gegl_buffer_get_width (buffer);
  cinfo.image_height = gegl_buffer_get_height (buffer);
  /* colorspace of input image */
  cinfo.in_color_space = (drawable_type == GIMP_RGB_IMAGE ||
                          drawable_type == GIMP_RGBA_IMAGE)
    ? JCS_RGB : JCS_GRAYSCALE;
  /* Now use the library's routine to set default compression parameters.
   * (You must set at least cinfo.in_color_space before calling this,
   * since the defaults depend on the source color space.)
   */
  jpeg_set_defaults (&cinfo);

  jpeg_set_quality (&cinfo, (gint) (jsvals.quality + 0.5), jsvals.baseline);

  if (jsvals.use_orig_quality && num_quant_tables > 0)
    {
      guint **quant_tables;
      gint    t;

      /* override tables generated by jpeg_set_quality() with custom tables */
      quant_tables = jpeg_restore_original_tables (image_ID, num_quant_tables);
      if (quant_tables)
        {
          for (t = 0; t < num_quant_tables; t++)
            {
              jpeg_add_quant_table (&cinfo, t, quant_tables[t],
                                    100, jsvals.baseline);
              g_free (quant_tables[t]);
            }
          g_free (quant_tables);
        }
    }

  if (arithc_supported)
    {
      cinfo.arith_code = jsvals.arithmetic_coding;
      if (!jsvals.arithmetic_coding)
        cinfo.optimize_coding = jsvals.optimize;
    }
  else
    cinfo.optimize_coding = jsvals.optimize;

  subsampling = (gimp_drawable_is_rgb (drawable_ID) ?
                 jsvals.subsmp : JPEG_SUBSAMPLING_1x1_1x1_1x1);

  /*  smoothing is not supported with nonstandard sampling ratios  */
  if (subsampling != JPEG_SUBSAMPLING_2x1_1x1_1x1 &&
      subsampling != JPEG_SUBSAMPLING_1x2_1x1_1x1)
    {
      cinfo.smoothing_factor = (gint) (jsvals.smoothing * 100);
    }

  if (jsvals.progressive)
    {
      jpeg_simple_progression (&cinfo);
    }

  switch (subsampling)
    {
    case JPEG_SUBSAMPLING_2x2_1x1_1x1:
    default:
      cinfo.comp_info[0].h_samp_factor = 2;
      cinfo.comp_info[0].v_samp_factor = 2;
      cinfo.comp_info[1].h_samp_factor = 1;
      cinfo.comp_info[1].v_samp_factor = 1;
      cinfo.comp_info[2].h_samp_factor = 1;
      cinfo.comp_info[2].v_samp_factor = 1;
      break;

    case JPEG_SUBSAMPLING_2x1_1x1_1x1:
      cinfo.comp_info[0].h_samp_factor = 2;
      cinfo.comp_info[0].v_samp_factor = 1;
      cinfo.comp_info[1].h_samp_factor = 1;
      cinfo.comp_info[1].v_samp_factor = 1;
      cinfo.comp_info[2].h_samp_factor = 1;
      cinfo.comp_info[2].v_samp_factor = 1;
      break;

    case JPEG_SUBSAMPLING_1x1_1x1_1x1:
      cinfo.comp_info[0].h_samp_factor = 1;
      cinfo.comp_info[0].v_samp_factor = 1;
      cinfo.comp_info[1].h_samp_factor = 1;
      cinfo.comp_info[1].v_samp_factor = 1;
      cinfo.comp_info[2].h_samp_factor = 1;
      cinfo.comp_info[2].v_samp_factor = 1;
      break;

    case JPEG_SUBSAMPLING_1x2_1x1_1x1:
      cinfo.comp_info[0].h_samp_factor = 1;
      cinfo.comp_info[0].v_samp_factor = 2;
      cinfo.comp_info[1].h_samp_factor = 1;
      cinfo.comp_info[1].v_samp_factor = 1;
      cinfo.comp_info[2].h_samp_factor = 1;
      cinfo.comp_info[2].v_samp_factor = 1;
      break;
    }

  cinfo.restart_interval = 0;
  cinfo.restart_in_rows = jsvals.restart;

  switch (jsvals.dct)
    {
    case 0:
    default:
      cinfo.dct_method = JDCT_ISLOW;
      break;

    case 1:
      cinfo.dct_method = JDCT_IFAST;
      break;

    case 2:
      cinfo.dct_method = JDCT_FLOAT;
      break;
    }

  {
    gdouble xresolution;
    gdouble yresolution;

    gimp_image_get_resolution (orig_image_ID, &xresolution, &yresolution);

    if (xresolution > 1e-5 && yresolution > 1e-5)
      {
        gdouble factor;

        factor = gimp_unit_get_factor (gimp_image_get_unit (orig_image_ID));

        if (factor == 2.54 /* cm */ ||
            factor == 25.4 /* mm */)
          {
            cinfo.density_unit = 2;  /* dots per cm */

            xresolution /= 2.54;
            yresolution /= 2.54;
          }
        else
          {
            cinfo.density_unit = 1;  /* dots per inch */
          }

        cinfo.X_density = xresolution;
        cinfo.Y_density = yresolution;
      }
  }

  /* Step 4: Start compressor */

  /* TRUE ensures that we will write a complete interchange-JPEG file.
   * Pass TRUE unless you are very sure of what you're doing.
   */
  jpeg_start_compress (&cinfo, TRUE);

  /* Step 4.1: Write the comment out - pw */
  if (image_comment && *image_comment)
    {
#ifdef GIMP_UNSTABLE
      g_print ("jpeg-save: saving image comment (%d bytes)\n",
               (int) strlen (image_comment));
#endif
      jpeg_write_marker (&cinfo, JPEG_COM,
                         (guchar *) image_comment, strlen (image_comment));
    }

  /* Step 4.2: store the color profile if there is one */
  parasite = gimp_image_get_parasite (orig_image_ID, "icc-profile");
  if (parasite)
    {
      jpeg_icc_write_profile (&cinfo,
                              gimp_parasite_data (parasite),
                              gimp_parasite_data_size (parasite));
      gimp_parasite_free (parasite);
    }

  /* Step 5: while (scan lines remain to be written) */
  /*           jpeg_write_scanlines(...); */

  /* Here we use the library's state variable cinfo.next_scanline as the
   * loop counter, so that we don't have to keep track ourselves.
   * To keep things simple, we pass one scanline per call; you can pass
   * more if you wish, though.
   */
  /* JSAMPLEs per row in image_buffer */
  rowstride = cinfo.input_components * cinfo.image_width;
  data = g_new (guchar, rowstride * gimp_tile_height ());

  /* fault if cinfo.next_scanline isn't initially a multiple of
   * gimp_tile_height */
  src = NULL;

  /*
   * sg - if we preview, we want this to happen in the background -- do
   * not duplicate code in the future; for now, it's OK
   */

  if (preview)
    {
      PreviewPersistent *pp = g_new (PreviewPersistent, 1);

      /* pass all the information we need */
      pp->cinfo       = cinfo;
      pp->tile_height = gimp_tile_height();
      pp->data        = data;
      pp->outfile     = outfile;
      pp->has_alpha   = has_alpha;
      pp->rowstride   = rowstride;
      pp->data        = data;
      pp->buffer      = buffer;
      pp->format      = format;
      pp->src         = NULL;
      pp->file_name   = filename;
      pp->abort_me    = FALSE;

      g_warn_if_fail (prev_p == NULL);
      prev_p = pp;

      pp->cinfo.err = jpeg_std_error(&(pp->jerr));
      pp->jerr.error_exit = background_error_exit;

      gtk_label_set_text (GTK_LABEL (preview_size),
                          _("Calculating file size..."));

      pp->source_id = g_idle_add ((GSourceFunc) background_jpeg_save, pp);

      /* background_jpeg_save() will cleanup as needed */
      return TRUE;
    }

  while (cinfo.next_scanline < cinfo.image_height)
    {
      if ((cinfo.next_scanline % gimp_tile_height ()) == 0)
        {
          yend = cinfo.next_scanline + gimp_tile_height ();
          yend = MIN (yend, cinfo.image_height);
          gegl_buffer_get (buffer,
                           GEGL_RECTANGLE (0, cinfo.next_scanline,
                                           cinfo.image_width,
                                           (yend - cinfo.next_scanline)),
                           1.0,
                           format,
                           data,
                           GEGL_AUTO_ROWSTRIDE,
                           GEGL_ABYSS_NONE);
          src = data;
        }

      jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &src, 1);
      src += rowstride;

      if ((cinfo.next_scanline % 32) == 0)
        gimp_progress_update ((gdouble) cinfo.next_scanline /
                              (gdouble) cinfo.image_height);
    }

  /* Step 6: Finish compression */
  jpeg_finish_compress (&cinfo);
  /* After finish_compress, we can close the output file. */
  fclose (outfile);

  /* Step 7: release JPEG compression object */

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

  /* free the temporary buffer */
  g_free (data);

  /* And we're done! */
  gimp_progress_update (1.0);

  g_object_unref (buffer);

  return TRUE;
}
Exemplo n.º 18
0
guchar *p_drawable_encode_jpeg(GDrawable *drawable, gint32 jpeg_interlaced, gint32 *JPEG_size, 
			       gint32 jpeg_quality, gint32 odd_even, gint32 use_YUV411, 
			       void *app0_buffer, gint32 app0_length)
{
  GPixelRgn pixel_rgn;
  GDrawableType drawable_type;
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;
  
  guchar *temp, *t;
  guchar *data;
  guchar *src, *s;
  int has_alpha;
  int rowstride, yend;
  int i, j, y;
  guchar *JPEG_data;
  size_t *JPEG_buf_remain;
  size_t totalsize = 0;

  drawable_type = gimp_drawable_type (drawable->id);
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);

  /* Step 1: allocate and initialize JPEG compression object */

  /* We have to set up the error handler first, in case the initialization
   * step fails.  (Unlikely, but it could happen if you are out of memory.)
   * This routine fills in the contents of struct jerr, and returns jerr's
   * address which we place into the link field in cinfo.
   */
  cinfo.err = jpeg_std_error(&jerr);

  /* Now we can initialize the JPEG compression object. */
  jpeg_create_compress (&cinfo);

  /* Step 2: specify data destination (eg, a file) */
  /* Note: steps 2 and 3 can be done in either order. */

  /* We use our own jpeg destination mgr */
  JPEG_data = (guchar *)g_malloc(OUTPUT_BUF_SIZE * sizeof(guchar));

  /* Install my memory destination manager (instead of stdio_dest) */
  jpeg_memio_dest (&cinfo, JPEG_data, &JPEG_buf_remain);

  if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Cleared the initilization !\n");

  /* Get the input image and a pointer to its data.
   */
  switch (drawable_type)
    {
    case RGB_IMAGE:
    case GRAY_IMAGE:
      /* # of color components per pixel */
      cinfo.input_components = drawable->bpp;
      has_alpha = 0;
      break;
    case RGBA_IMAGE:
    case GRAYA_IMAGE:
      gimp_message ("jpeg: image contains a-channel info which will be lost");
      /* # of color components per pixel (minus the GIMP alpha channel) */
      cinfo.input_components = drawable->bpp - 1;
      has_alpha = 1;
      break;
    case INDEXED_IMAGE:
      gimp_message ("jpeg: cannot operate on indexed color images");
      return FALSE;
      break;
    default:
      gimp_message ("jpeg: cannot operate on unknown image types");
      return FALSE;
      break;
    }

  /* Step 3: set parameters for compression */

  /* First we supply a description of the input image.
   * Four fields of the cinfo struct must be filled in:
   */
  /* image width and height, in pixels */
  cinfo.image_width = drawable->width;
  cinfo.image_height = drawable->height;
  /* colorspace of input image */
  cinfo.in_color_space = (drawable_type == RGB_IMAGE ||
			  drawable_type == RGBA_IMAGE)
    ? JCS_RGB : JCS_GRAYSCALE;
  /* Now use the library's routine to set default compression parameters.
   * (You must set at least cinfo.in_color_space before calling this,
   * since the defaults depend on the source color space.)
   */
  jpeg_set_defaults (&cinfo);
  jpeg_set_quality (&cinfo, (int) (jpeg_quality), TRUE);

  /* Smoothing is not possible for nonstandard sampling rates */
  /*  cinfo.smoothing_factor = (int) (50); */
  /* I wonder if this is slower: */ 
  /* cinfo.optimize_coding = 1; */

  /* Are these the evil AVI destroyers ? */
  cinfo.write_Adobe_marker = FALSE;
  cinfo.write_JFIF_header = FALSE;

  /* That's the only allowed encoding in a movtar */
  if (!use_YUV411)
    {
      cinfo.comp_info[0].h_samp_factor = 2;
      cinfo.comp_info[0].v_samp_factor = 1;
      cinfo.comp_info[1].h_samp_factor = 1;
      cinfo.comp_info[1].v_samp_factor = 1;
      cinfo.comp_info[2].h_samp_factor = 1;
      cinfo.comp_info[2].v_samp_factor = 1;
    }
  else
    if (gap_debug) fprintf(stderr, "Using YUV 4:1:1 encoding !");

  cinfo.restart_interval = 0;
  cinfo.restart_in_rows = FALSE; 
  /* could be _ISLOW or _FLOAT, too, but this is fastest */
  cinfo.dct_method = JDCT_ISLOW; 
  if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Cleared parameter setting !\n");

  if (jpeg_interlaced)
    {
      cinfo.image_height = drawable->height/2;
      
      rowstride = drawable->bpp * drawable->width;
      temp = (guchar *) g_malloc (cinfo.image_width * cinfo.input_components);
      data = (guchar *) g_malloc (rowstride * gimp_tile_height ());
  
      for (y = (odd_even) ? 1 : 0; (odd_even) ? (y >= 0) : (y <= 1); (odd_even) ? (y--) : (y++))
	{
	  if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: interlaced picture, now coding %s lines\n",
				  y ? "odd" : "even");
	  
	  jpeg_start_compress (&cinfo, TRUE);

	  /* Step 4.1: Write the app0 marker out */
	  if(app0_buffer) 
	    jpeg_write_marker(&cinfo,
			  JPEG_APP0,
			      app0_buffer,
			      app0_length);      
	  
	  while (cinfo.next_scanline < cinfo.image_height)
	    {
	      if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Line %d !", cinfo.next_scanline); 
	      gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, 2 * cinfo.next_scanline + y, 
				       cinfo.image_width, 1);
	      
	      /* Get rid of all the bad stuff (tm) (= get the right pixel order for JPEG encoding) */
	      t = temp;
	      s = data;
	      i = cinfo.image_width;
	      
	      while (i--)
		{
		  for (j = 0; j < cinfo.input_components; j++)
		    *t++ = *s++;
		  if (has_alpha)  /* ignore alpha channel */
		    s++;
		}
	      
	      src += 2*rowstride;
	      jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &temp, 1);
	    }
      
	  jpeg_finish_compress(&cinfo);
	  totalsize += (OUTPUT_BUF_SIZE - *JPEG_buf_remain);
	  //JPEG_data = (guchar *)realloc(JPEG_data, sizeof(guchar)* *JPEG_size);
	}
      /* fprintf(stderr, "2 fields written.\n"); */
    }
  else
    {
      /* Step 4: Start compressor */

      /* TRUE ensures that we will write a complete interchange-JPEG file.
       * Pass TRUE unless you are very sure of what you're doing.
       */
      if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: non-interlaced picture.\n"); 
      jpeg_start_compress (&cinfo, TRUE);

      /* Step 4.1: Write the app0 marker out */
      if(app0_buffer) 
	jpeg_write_marker(&cinfo,
			  JPEG_APP0,
			  app0_buffer,
			  app0_length);      
      
      /* Step 5: while (scan lines remain to be written) */
      /*           jpeg_write_scanlines(...); */
      
      /* Here we use the library's state variable cinfo.next_scanline as the
       * loop counter, so that we don't have to keep track ourselves.
       * To keep things simple, we pass one scanline per call; you can pass
       * more if you wish, though.
       */
      /* JSAMPLEs per row in image_buffer */
      rowstride = drawable->bpp * drawable->width;
      temp = (guchar *) g_malloc (cinfo.image_width * cinfo.input_components);
      data = (guchar *) g_malloc (rowstride * gimp_tile_height ());

      /* fault if cinfo.next_scanline isn't initially a multiple of
       * gimp_tile_height */
      src = NULL;

      while (cinfo.next_scanline < cinfo.image_height)
	{
	  if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Line %d !", cinfo.next_scanline); 
	  if ((cinfo.next_scanline % gimp_tile_height ()) == 0)
	    {
	      yend = cinfo.next_scanline + gimp_tile_height ();
	      yend = MIN (yend, cinfo.image_height);
	      gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, cinfo.next_scanline, cinfo.image_width,
				       (yend - cinfo.next_scanline));
	      src = data;
	    }
	  
	  t = temp;
	  s = src;
	  i = cinfo.image_width;
	  
	  while (i--)
	    {
	      for (j = 0; j < cinfo.input_components; j++)
		*t++ = *s++;
	      if (has_alpha)  /* ignore alpha channel */
		s++;
	    }
	  
	  src += rowstride;
	  jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &temp, 1);
	}
      
      /* Step 6: Finish compression */
      jpeg_finish_compress (&cinfo);
      totalsize += (OUTPUT_BUF_SIZE - *JPEG_buf_remain);
      // JPEG_data = (guchar *)realloc(JPEG_data, sizeof(guchar)* *JPEG_size);
    }

  /* Step 7: release JPEG compression object */
  /* This is an important step since it will release a good deal of memory. */
  jpeg_destroy_compress (&cinfo);

  /* free the temporary buffer */
  g_free (temp);
  g_free (data);

  *JPEG_size = totalsize;
  return JPEG_data;
}	
Exemplo n.º 19
0
gint32
load_image (const gchar  *filename,
            GimpRunMode   runmode,
            gboolean      preview,
            gboolean     *resolution_loaded,
            GError      **error)
{
  gint32 volatile  image_ID;
  gint32           layer_ID;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr           jerr;
  jpeg_saved_marker_ptr         marker;
  FILE            *infile;
  guchar          *buf;
  guchar         **rowbuf;
  GimpImageBaseType image_type;
  GimpImageType    layer_type;
  GeglBuffer      *buffer = NULL;
  const Babl      *format;
  gint             tile_height;
  gint             scanlines;
  gint             i, start, end;
  cmsHTRANSFORM    cmyk_transform = NULL;

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

  if (!preview)
    {
      jerr.pub.output_message = my_output_message;

      gimp_progress_init_printf (_("Opening '%s'"),
                                 gimp_filename_to_utf8 (filename));
    }

  if ((infile = g_fopen (filename, "rb")) == NULL)
    {
      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
                   _("Could not open '%s' for reading: %s"),
                   gimp_filename_to_utf8 (filename), g_strerror (errno));
      return -1;
    }

  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 && !preview)
        gimp_image_delete (image_ID);

      if (preview)
        destroy_preview ();

      if (buffer)
        g_object_unref (buffer);

      return -1;
    }

  /* 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);

  if (! preview)
    {
      /* - step 2.1: tell the lib to save the comments */
      jpeg_save_markers (&cinfo, JPEG_COM, 0xffff);

      /* - step 2.2: tell the lib to save APP1 data (Exif or XMP) */
      jpeg_save_markers (&cinfo, JPEG_APP0 + 1, 0xffff);

      /* - step 2.3: tell the lib to save APP2 data (ICC profiles) */
      jpeg_save_markers (&cinfo, JPEG_APP0 + 2, 0xffff);
    }

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

  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.
   */

  /* 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.
   */

  /* 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;

  switch (cinfo.output_components)
    {
    case 1:
      image_type = GIMP_GRAY;
      layer_type = GIMP_GRAY_IMAGE;
      break;

    case 3:
      image_type = GIMP_RGB;
      layer_type = GIMP_RGB_IMAGE;
      break;

    case 4:
      if (cinfo.out_color_space == JCS_CMYK)
        {
          image_type = GIMP_RGB;
          layer_type = GIMP_RGB_IMAGE;
          break;
        }
      /*fallthrough*/

    default:
      g_message ("Don't know how to load JPEG images "
                 "with %d color channels, using colorspace %d (%d).",
                 cinfo.output_components, cinfo.out_color_space,
                 cinfo.jpeg_color_space);
      return -1;
      break;
    }

  if (preview)
    {
      image_ID = preview_image_ID;
    }
  else
    {
      image_ID = gimp_image_new_with_precision (cinfo.output_width,
                                                cinfo.output_height,
                                                image_type,
                                                GIMP_PRECISION_U8_GAMMA);

      gimp_image_undo_disable (image_ID);
      gimp_image_set_filename (image_ID, filename);
    }

  if (preview)
    {
      preview_layer_ID = gimp_layer_new (preview_image_ID, _("JPEG preview"),
                                         cinfo.output_width,
                                         cinfo.output_height,
                                         layer_type, 100, GIMP_NORMAL_MODE);
      layer_ID = preview_layer_ID;
    }
  else
    {
      layer_ID = gimp_layer_new (image_ID, _("Background"),
                                 cinfo.output_width,
                                 cinfo.output_height,
                                 layer_type, 100, GIMP_NORMAL_MODE);
    }

  if (! preview)
    {
      GString  *comment_buffer = NULL;
      guint8   *profile        = NULL;
      guint     profile_size   = 0;

      /* Step 5.0: save the original JPEG settings in a parasite */
      jpeg_detect_original_settings (&cinfo, image_ID);

      /* Step 5.1: check for comments, or Exif metadata in APP1 markers */
      for (marker = cinfo.marker_list; marker; marker = marker->next)
        {
          const gchar *data = (const gchar *) marker->data;
          gsize        len  = marker->data_length;

          if (marker->marker == JPEG_COM)
            {
#ifdef GIMP_UNSTABLE
              g_print ("jpeg-load: found image comment (%d bytes)\n",
                       marker->data_length);
#endif

              if (! comment_buffer)
                {
                  comment_buffer = g_string_new_len (data, len);
                }
              else
                {
                  /* concatenate multiple comments, separate them with LF */
                  g_string_append_c (comment_buffer, '\n');
                  g_string_append_len (comment_buffer, data, len);
                }
            }
          else if ((marker->marker == JPEG_APP0 + 1)
                   && (len > sizeof (JPEG_APP_HEADER_EXIF) + 8)
                   && ! strcmp (JPEG_APP_HEADER_EXIF, data))
            {
#ifdef GIMP_UNSTABLE
              g_print ("jpeg-load: found Exif block (%d bytes)\n",
                       (gint) (len - sizeof (JPEG_APP_HEADER_EXIF)));
#endif
            }
        }

      if (jpeg_load_resolution (image_ID, &cinfo))
        {
          if (resolution_loaded)
            *resolution_loaded = TRUE;
        }

      /* if we found any comments, then make a parasite for them */
      if (comment_buffer && comment_buffer->len)
        {
          GimpParasite *parasite;

          jpeg_load_sanitize_comment (comment_buffer->str);
          parasite = gimp_parasite_new ("gimp-comment",
                                        GIMP_PARASITE_PERSISTENT,
                                        strlen (comment_buffer->str) + 1,
                                        comment_buffer->str);
          gimp_image_attach_parasite (image_ID, parasite);
          gimp_parasite_free (parasite);

          g_string_free (comment_buffer, TRUE);
        }

      /* Step 5.3: check for an embedded ICC profile in APP2 markers */
      jpeg_icc_read_profile (&cinfo, &profile, &profile_size);

      if (cinfo.out_color_space == JCS_CMYK)
        {
          cmyk_transform = jpeg_load_cmyk_transform (profile, profile_size);
        }
      else if (profile) /* don't attach the profile if we are transforming */
        {
          GimpParasite *parasite;

          parasite = gimp_parasite_new ("icc-profile",
                                        GIMP_PARASITE_PERSISTENT |
                                        GIMP_PARASITE_UNDOABLE,
                                        profile_size, profile);
          gimp_image_attach_parasite (image_ID, parasite);
          gimp_parasite_free (parasite);
        }

      g_free (profile);

      /* Do not attach the "jpeg-save-options" parasite to the image
       * because this conflicts with the global defaults (bug #75398).
       */
    }

  /* 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.
   */

  buffer = gimp_drawable_get_buffer (layer_ID);
  format = babl_format (image_type == GIMP_RGB ? "R'G'B' u8" : "Y' u8");

  while (cinfo.output_scanline < cinfo.output_height)
    {
      start = cinfo.output_scanline;
      end   = cinfo.output_scanline + tile_height;
      end   = MIN (end, cinfo.output_height);

      scanlines = end - start;

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

      if (cinfo.out_color_space == JCS_CMYK)
        jpeg_load_cmyk_to_rgb (buf, cinfo.output_width * scanlines,
                               cmyk_transform);

      gegl_buffer_set (buffer,
                       GEGL_RECTANGLE (0, start, cinfo.output_width, scanlines),
                       0,
                       format,
                       buf,
                       GEGL_AUTO_ROWSTRIDE);

      if (! preview && (cinfo.output_scanline % 32) == 0)
        gimp_progress_update ((gdouble) cinfo.output_scanline /
                              (gdouble) cinfo.output_height);
    }

  /* Step 7: Finish decompression */

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

  if (cmyk_transform)
    cmsDeleteTransform (cmyk_transform);

  /* Step 8: Release JPEG decompression object */

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

  g_object_unref (buffer);

  /* 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).
   */

  /* Detach from the drawable and add it to the image.
   */
  if (! preview)
    {
      gimp_progress_update (1.0);
    }

  gimp_image_insert_layer (image_ID, layer_ID, -1, 0);

  return image_ID;
}
Exemplo n.º 20
0
gint
xjpg_load_layer_alpha (const char *filename,
                       gint32      image_id,
                       gint32      layer_id)
{
  GimpPixelRgn l_pixel_rgn;
  GimpDrawable *l_drawable;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr jerr;
  FILE *infile;
  guchar *l_buf;
  guchar *l_dstbuf;
  guchar **l_rowbuf;
  int l_tile_height;
  int l_scanlines;
  int l_idx, l_start, l_end;
  int l_alpha_offset;
  guchar *l_buf_ptr;
  guchar *l_dstbuf_ptr;

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

  /* add alpha channel */
  gimp_layer_add_alpha (layer_id);

  if ((infile = g_fopen (filename, "rb")) == NULL)
  {
      /* No alpha found, thats OK, use full opaque alpha channel
       * (there is no need not store alpha channels on full opaque channels)
       * (fixme: if filename exists but is not readable
       *         we should return -1 to indicate an error
       */
      return 0;  /* OK */
  }

  /* 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);

      g_printerr ("XJT: JPEG alpha load error\n");
      return -1;
  }

  /* 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);

  /* 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.
   */

  /* 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 (for read in jpeg lines) */
  l_tile_height = gimp_tile_height ();
  l_buf = g_new (guchar, l_tile_height * cinfo.output_width * cinfo.output_components);
  l_rowbuf = g_new (guchar*, l_tile_height);

  for (l_idx = 0; l_idx < l_tile_height; l_idx++)
  {
    l_rowbuf[l_idx] = l_buf + cinfo.output_width * cinfo.output_components * l_idx;
  }

  l_drawable = gimp_drawable_get (layer_id);
  if(l_drawable == NULL)
  {
    g_printerr ("XJT: gimp_drawable_get failed on layer id %d\n", (int)layer_id);
    fclose(infile);
    return -1;
  }

  /* Check if jpeg file can be used as alpha channel
   */
  if((cinfo.output_components != 1) ||
     (cinfo.output_width  != l_drawable->width) ||
     (cinfo.output_height != l_drawable->height))
  {
     g_printerr ("XJT: cant load %s as alpha channel\n", filename);
     fclose (infile);
     return -1;
  }

  /* buffer to read in the layer and merge with the alpha from jpeg file */
  l_dstbuf = g_new (guchar, l_tile_height * l_drawable->width * l_drawable->bpp);

  gimp_pixel_rgn_init (&l_pixel_rgn, l_drawable, 0, 0, l_drawable->width, l_drawable->height, TRUE, FALSE);
  l_alpha_offset = l_drawable->bpp -1;

  /* 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)
  {
      l_start = cinfo.output_scanline;
      l_end = cinfo.output_scanline + l_tile_height;
      l_end = MIN (l_end, cinfo.output_height);
      l_scanlines = l_end - l_start;

      for (l_idx = 0; l_idx < l_scanlines; l_idx++)
      {
	jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &l_rowbuf[l_idx], 1);
      }

      gimp_pixel_rgn_get_rect (&l_pixel_rgn, l_dstbuf, 0, l_start, l_drawable->width, l_scanlines);

      /* copy the loaded jpeg data (from buf) to the layers alpha channel data */
      l_idx = l_tile_height * l_drawable->width;
      l_buf_ptr = l_buf;
      l_dstbuf_ptr = l_dstbuf;
      while(l_idx--)
      {
         l_dstbuf_ptr  += l_alpha_offset;
         *l_dstbuf_ptr++ = *l_buf_ptr++;
      }

      gimp_pixel_rgn_set_rect (&l_pixel_rgn, l_dstbuf, 0, l_start, l_drawable->width, l_scanlines);

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

  /* 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 (l_rowbuf);
  g_free (l_buf);
  g_free (l_dstbuf);

  /* 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).
   */


  return (0);  /* OK */

}	/* xjpg_load_layer_alpha */
Exemplo n.º 21
0
static void run (const gchar *name, gint nparams, const GimpParam  *param, gint *nreturn_vals, GimpParam **return_vals)
{
	static GimpParam   values[1];
	GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
	GimpDrawable      *drawable;
	GimpRunMode        run_mode;

	// create working directory
	char* home = getenv("HOME");
	char dir[PATH_MAX + 1];
	strcpy ( dir, home );
	strcat ( dir, "/.gimp-octave" );
	mkdir( dir, S_IRWXU );

	run_mode = (GimpRunMode)param[0].data.d_int32;

	*return_vals  = values;
	*nreturn_vals = 1;

	values[0].type          = GIMP_PDB_STATUS;
	values[0].data.d_status = status;

	/*
	* Get drawable information...
	*/
	drawable = gimp_drawable_get (param[2].data.d_drawable);
	gimp_tile_cache_ntiles (2 * MAX (drawable->width  / gimp_tile_width () + 1 ,
					 drawable->height / gimp_tile_height () + 1));

	switch (run_mode)
	{
		case GIMP_RUN_INTERACTIVE:
			gimp_get_data (PLUG_IN_PROC, &octave_params);
			/* Reset default values show preview unmodified */

			/* initialize pixel regions and buffer */
			if (! octave_dialog (drawable))
			return;
			break;

		case GIMP_RUN_NONINTERACTIVE:
			if (nparams != 6)
			{
				status = GIMP_PDB_CALLING_ERROR;
			}
			else
			{
				reset_default();
			}
			break;

		case GIMP_RUN_WITH_LAST_VALS:
			gimp_get_data (PLUG_IN_PROC, &octave_params);
			break;

		default:
			break;
	}

	if (status == GIMP_PDB_SUCCESS)
	{
		drawable = gimp_drawable_get (param[2].data.d_drawable);

		/* here we go */
		octave (drawable);

		gimp_displays_flush ();

		/* set data for next use of filter */
		if (run_mode == GIMP_RUN_INTERACTIVE)
			gimp_set_data (PLUG_IN_PROC, &octave_params, sizeof (OctaveParams));

		gimp_drawable_detach(drawable);
		values[0].data.d_status = status;
	}
}