GimpPDBStatusType file_vtf_save_image (const gchar *fname, gint32 image, gint32 run_mode, GError **error) { SaveInfo info; info.version = 4; info.format = Vtf::FormatDXT5; info.layer = 0; info.mipmap = TRUE; info.lowres = TRUE; info.crc = TRUE; if (run_mode == GIMP_RUN_INTERACTIVE) if (!file_vtf_save_dialog (&info)) return GIMP_PDB_CANCEL; gimp_progress_init_printf ("Saving '%s'", gimp_filename_to_utf8 (fname)); std::auto_ptr<Vtf::File> vtf (new Vtf::File); try { Vtf::HiresImageResource* vres = new Vtf::HiresImageResource; // vres->setup (info.format, info.width, info.height, info); vres->check (); vtf->addResource (vres); vtf->save (fname, info.version); } catch (std::exception& e) { } gimp_progress_update (1.0); return GIMP_PDB_SUCCESS; }
static void load_changed_cb (WebKitWebView *view, WebKitLoadEvent event, gpointer user_data) { if (event == WEBKIT_LOAD_FINISHED) { if (! webpagevals.error) { gimp_progress_init_printf (_("Transferring webpage image for '%s'"), webpagevals.url); g_timeout_add (100, load_finished_idle, view); return; } gtk_main_quit (); } }
gint32 file_vtf_load_image (const gchar *fname, GError **error) { gimp_progress_init_printf ("Opening '%s'", gimp_filename_to_utf8 (fname)); gint32 image = -1; std::auto_ptr<Vtf::File> vtf (new Vtf::File); try { vtf->load(fname); Vtf::HiresImageResource* vres = (Vtf::HiresImageResource*) vtf->findResource (Vtf::Resource::TypeHires); if (!vres) throw Vtf::Exception ("Cound not find high-resolution image"); image = gimp_image_new (vres->width (), vres->height (), GIMP_RGB); gimp_image_set_filename (image, fname); guint16 i, frame_count = vres->frameCount (); for (i = 0; i < frame_count; i++) { if (!file_vtf_load_layer (vres, image, i)) { g_set_error (error, 0, 0, "Unsupported format %s", Vtf::formatToString (vres->format())); gimp_image_delete (image); image = -1; break; } } gimp_progress_update (1.0); } catch (std::exception& e) { g_set_error (error, 0, 0, e.what ()); } return image; }
gint32 file_vtf_load_thumbnail_image (const gchar *fname, gint *width, gint *height, GError **error) { gint32 image = -1; gimp_progress_init_printf ("Opening thumbnail for '%s'", gimp_filename_to_utf8 (fname)); Vtf::File *vtf = new Vtf::File; try { vtf->load(fname); Vtf::HiresImageResource* vres = (Vtf::HiresImageResource*) vtf->findResource(Vtf::Resource::TypeHires); if (!vres) throw Vtf::Exception ("Cound not find high-resolution image"); *width = static_cast<gint> (vres->width ()); *height = static_cast<gint> (vres->height ()); image = gimp_image_new (*width, *height, GIMP_RGB); if (!file_vtf_load_layer (vres, image, 0)) { g_set_error (error, 0, 0, "Unsupported format %s", Vtf::formatToString(vres->format())); gimp_image_delete (image); image = -1; } gimp_progress_update (1.0); } catch (std::exception& e) { g_set_error (error, 0, 0, e.what()); } delete vtf; return image; }
gboolean uri_backend_load_image (const gchar *uri, const gchar *tmpname, GimpRunMode run_mode, GError **error) { gint pid; gint p[2]; if (pipe (p) != 0) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "pipe() failed: %s", g_strerror (errno)); return FALSE; } /* open a process group, so killing the plug-in will kill wget too */ setpgid (0, 0); if ((pid = fork()) < 0) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "fork() failed: %s", g_strerror (errno)); return FALSE; } else if (pid == 0) { gchar timeout_str[16]; close (p[0]); close (2); dup (p[1]); close (p[1]); /* produce deterministic output */ g_setenv ("LANGUAGE", "C", TRUE); g_setenv ("LC_ALL", "C", TRUE); g_setenv ("LANG", "C", TRUE); g_snprintf (timeout_str, sizeof (timeout_str), "%d", TIMEOUT); execlp ("wget", "wget", "-v", "-e", "server-response=off", "--progress=dot", "-T", timeout_str, uri, "-O", tmpname, NULL); _exit (127); } else { FILE *input; gchar buf[BUFSIZE]; gboolean seen_resolve = FALSE; gboolean seen_ftp = FALSE; gboolean connected = FALSE; gboolean redirect = FALSE; gboolean file_found = FALSE; gchar sizestr[37]; gchar *endptr; guint64 size = 0; gint i, j; gchar dot; guint64 kilobytes = 0; gboolean finished = FALSE; gboolean debug = FALSE; gchar *memsize; gchar *message; gchar *timeout_msg; #define DEBUG(x) if (debug) g_printerr (x) close (p[1]); input = fdopen (p[0], "r"); /* hardcoded and not-really-foolproof scanning of wget putput */ wget_begin: /* Eat any Location lines */ if (redirect && fgets (buf, sizeof (buf), input) == NULL) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("wget exited abnormally on URI '%s'"), uri); return FALSE; } redirect = FALSE; if (fgets (buf, sizeof (buf), input) == NULL) { /* no message here because failing on the first line means * that wget was not found */ return FALSE; } DEBUG (buf); /* The second line is the local copy of the file */ if (fgets (buf, sizeof (buf), input) == NULL) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("wget exited abnormally on URI '%s'"), uri); return FALSE; } /* with an ftp url wget has a "=> `filename.foo" */ else if ( !seen_ftp && strstr (buf, "=> `")) { seen_ftp = TRUE; } DEBUG (buf); /* The third line is "Connecting to..." */ timeout_msg = g_strdup_printf (ngettext ("(timeout is %d second)", "(timeout is %d seconds)", TIMEOUT), TIMEOUT); gimp_progress_init_printf ("%s %s", _("Connecting to server"), timeout_msg); read_connect: if (fgets (buf, sizeof (buf), input) == NULL) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("wget exited abnormally on URI '%s'"), uri); return FALSE; } else if (strstr (buf, "connected")) { connected = TRUE; } /* newer wgets have a "Resolving foo" line, so eat it */ else if (!seen_resolve && strstr (buf, "Resolving")) { seen_resolve = TRUE; goto read_connect; } DEBUG (buf); /* The fourth line is either the network request or an error */ gimp_progress_set_text_printf ("%s %s", _("Opening URI"), timeout_msg); if (fgets (buf, sizeof (buf), input) == NULL) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("wget exited abnormally on URI '%s'"), uri); return FALSE; } else if (! connected) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("A network error occurred: %s"), buf); DEBUG (buf); return FALSE; } /* on successful ftp login wget prints a "Logged in" message */ else if ( seen_ftp && !strstr(buf, "Logged in!")) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("A network error occurred: %s"), buf); DEBUG (buf); return FALSE; } else if (strstr (buf, "302 Found")) { DEBUG (buf); connected = FALSE; seen_resolve = FALSE; redirect = TRUE; goto wget_begin; } DEBUG (buf); /* for an ftp session wget has extra output*/ ftp_session: if (seen_ftp) { if (fgets (buf, sizeof (buf), input) == NULL) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("A network error occurred: %s"), buf); DEBUG (buf); return FALSE; } /* if there is no size output file does not exist on server */ else if (strstr (buf, "==> SIZE") && strstr (buf, "... done")) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("wget exited abnormally on URI '%s'"), uri); DEBUG (buf); return FALSE; } /* while no PASV line we eat other messages */ else if (!strstr (buf, "==> PASV")) { DEBUG (buf); goto ftp_session; } } /* The fifth line is either the length of the file or an error */ if (fgets (buf, sizeof (buf), input) == NULL) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("wget exited abnormally on URI '%s'"), uri); return FALSE; } else if (strstr (buf, "Length")) { file_found = TRUE; } else { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("A network error occurred: %s"), buf); DEBUG (buf); return FALSE; } DEBUG (buf); if (sscanf (buf, "Length: %37s", sizestr) != 1) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Could not parse wget's file length message"); return FALSE; } /* strip away commas */ for (i = 0, j = 0; i < sizeof (sizestr); i++, j++) { if (sizestr[i] == ',') i++; sizestr[j] = sizestr[i]; if (sizestr[j] == '\0') break; } if (*sizestr != '\0') { size = g_ascii_strtoull (sizestr, &endptr, 10); if (*endptr != '\0' || size == G_MAXUINT64) size = 0; } /* on http sessions wget has "Saving to: ..." */ if (!seen_ftp) { if (fgets (buf, sizeof (buf), input) == NULL) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("wget exited abnormally on URI '%s'"), uri); return FALSE; } } /* Start the actual download... */ if (size > 0) { memsize = g_format_size_for_display (size); message = g_strdup_printf (_("Downloading %s of image data"), memsize); } else { message = g_strdup (_("Downloading unknown amount of image data")); memsize = NULL; } gimp_progress_set_text_printf ("%s %s", message, timeout_msg); g_free (message); g_free (memsize); /* Switch to byte parsing wget's output... */ while (TRUE) { dot = fgetc (input); if (feof (input)) break; if (debug) { fputc (dot, stderr); fflush (stderr); } if (dot == '.') /* one kilobyte */ { kilobytes++; if (size > 0) { gimp_progress_update ((gdouble) (kilobytes * 1024) / (gdouble) size); } else { memsize = g_format_size_for_display (kilobytes * 1024); gimp_progress_set_text_printf (_("Downloaded %s of image data"), memsize); gimp_progress_pulse (); g_free (memsize); } } else if (dot == ':') /* the time string contains a ':' */ { fgets (buf, sizeof (buf), input); DEBUG (buf); if (! strstr (buf, "error")) { finished = TRUE; gimp_progress_update (1.0); } break; } } if (! finished) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "wget exited before finishing downloading URI\n'%s'", uri); return FALSE; } } return TRUE; }
static gint32 load_image (PopplerDocument *doc, const gchar *filename, GimpRunMode run_mode, GimpPageSelectorTarget target, guint32 resolution, PdfSelectedPages *pages) { gint32 image_ID = 0; gint32 *images = NULL; gint i; gdouble scale; gdouble doc_progress = 0; if (target == GIMP_PAGE_SELECTOR_TARGET_IMAGES) images = g_new0 (gint32, pages->n_pages); gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); scale = resolution / gimp_unit_get_factor (GIMP_UNIT_POINT); /* read the file */ for (i = 0; i < pages->n_pages; i++) { PopplerPage *page; gchar *page_label; gdouble page_width; gdouble page_height; GdkPixbuf *buf; gint width; gint height; page = poppler_document_get_page (doc, pages->pages[i]); poppler_page_get_size (page, &page_width, &page_height); width = page_width * scale; height = page_height * scale; g_object_get (G_OBJECT (page), "label", &page_label, NULL); if (! image_ID) { gchar *name; image_ID = gimp_image_new (width, height, GIMP_RGB); gimp_image_undo_disable (image_ID); if (target == GIMP_PAGE_SELECTOR_TARGET_IMAGES) name = g_strdup_printf (_("%s-%s"), filename, page_label); else name = g_strdup_printf (_("%s-pages"), filename); gimp_image_set_filename (image_ID, name); g_free (name); gimp_image_set_resolution (image_ID, resolution, resolution); } buf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); poppler_page_render_to_pixbuf (page, 0, 0, width, height, scale, 0, buf); layer_from_pixbuf (image_ID, page_label, i, buf, doc_progress, 1.0 / pages->n_pages); g_free (page_label); g_object_unref (buf); doc_progress = (double) (i + 1) / pages->n_pages; gimp_progress_update (doc_progress); if (target == GIMP_PAGE_SELECTOR_TARGET_IMAGES) { images[i] = image_ID; gimp_image_undo_enable (image_ID); gimp_image_clean_all (image_ID); image_ID = 0; } } if (image_ID) { gimp_image_undo_enable (image_ID); gimp_image_clean_all (image_ID); } if (target == GIMP_PAGE_SELECTOR_TARGET_IMAGES) { if (run_mode != GIMP_RUN_NONINTERACTIVE) { /* Display images in reverse order. The last will be * displayed by GIMP itself */ for (i = pages->n_pages - 1; i > 0; i--) gimp_display_new (images[i]); } image_ID = images[0]; g_free (images); } return image_ID; }
static gint32 load_image (const gchar *filename, gboolean thumbnail, GError **error) { FILE *fd; guchar buf[16]; guchar c; CMap localColorMap; gint grayScale; gboolean useGlobalColormap; gint bitPixel; gint imageCount = 0; gchar version[4]; gint32 image_ID = -1; fd = g_fopen (filename, "rb"); if (! fd) { 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; } gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); if (! ReadOK (fd, buf, 6)) { g_message ("Error reading magic number"); return -1; } if (strncmp ((gchar *) buf, "GIF", 3) != 0) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s", _("This is not a GIF file")); return -1; } strncpy (version, (gchar *) buf + 3, 3); version[3] = '\0'; if ((strcmp (version, "87a") != 0) && (strcmp (version, "89a") != 0)) { g_message ("Bad version number, not '87a' or '89a'"); return -1; } if (! ReadOK (fd, buf, 7)) { g_message ("Failed to read screen descriptor"); return -1; } GifScreen.Width = LM_to_uint (buf[0], buf[1]); GifScreen.Height = LM_to_uint (buf[2], buf[3]); GifScreen.BitPixel = 2 << (buf[4] & 0x07); GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1); GifScreen.Background = buf[5]; GifScreen.AspectRatio = buf[6]; if (BitSet (buf[4], LOCALCOLORMAP)) { /* Global Colormap */ if (! ReadColorMap (fd, GifScreen.BitPixel, GifScreen.ColorMap, &GifScreen.GrayScale)) { g_message ("Error reading global colormap"); return -1; } } if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) { g_message (_("Non-square pixels. Image might look squashed.")); } highest_used_index = 0; while (TRUE) { if (! ReadOK (fd, &c, 1)) { g_message ("EOF / read error on image data"); return image_ID; /* will be -1 if failed on first image! */ } if (c == ';') { /* GIF terminator */ return image_ID; } if (c == '!') { /* Extension */ if (! ReadOK (fd, &c, 1)) { g_message ("EOF / read error on extension function code"); return image_ID; /* will be -1 if failed on first image! */ } DoExtension (fd, c); continue; } if (c != ',') { /* Not a valid start character */ g_printerr ("GIF: bogus character 0x%02x, ignoring.\n", (int) c); continue; } ++imageCount; if (! ReadOK (fd, buf, 9)) { g_message ("Couldn't read left/top/width/height"); return image_ID; /* will be -1 if failed on first image! */ } useGlobalColormap = !BitSet (buf[8], LOCALCOLORMAP); bitPixel = 1 << ((buf[8] & 0x07) + 1); if (! useGlobalColormap) { if (! ReadColorMap (fd, bitPixel, localColorMap, &grayScale)) { g_message ("Error reading local colormap"); return image_ID; /* will be -1 if failed on first image! */ } image_ID = ReadImage (fd, filename, LM_to_uint (buf[4], buf[5]), LM_to_uint (buf[6], buf[7]), localColorMap, bitPixel, grayScale, BitSet (buf[8], INTERLACE), imageCount, (guint) LM_to_uint (buf[0], buf[1]), (guint) LM_to_uint (buf[2], buf[3]), GifScreen.Width, GifScreen.Height); } else { image_ID = ReadImage (fd, filename, LM_to_uint (buf[4], buf[5]), LM_to_uint (buf[6], buf[7]), GifScreen.ColorMap, GifScreen.BitPixel, GifScreen.GrayScale, BitSet (buf[8], INTERLACE), imageCount, (guint) LM_to_uint (buf[0], buf[1]), (guint) LM_to_uint (buf[2], buf[3]), GifScreen.Width, GifScreen.Height); } if (comment_parasite != NULL) { if (! thumbnail) gimp_image_attach_parasite (image_ID, comment_parasite); gimp_parasite_free (comment_parasite); comment_parasite = NULL; } /* If we are loading a thumbnail, we stop after the first frame. */ if (thumbnail) break; } return image_ID; }
static gint32 webpage_capture (void) { gint32 image = -1; gchar *scheme; GtkWidget *window; GtkWidget *view; WebKitWebSettings *settings; char *ua_old; char *ua; if (webpagevals.pixbuf) { g_object_unref (webpagevals.pixbuf); webpagevals.pixbuf = NULL; } if (webpagevals.error) { g_error_free (webpagevals.error); webpagevals.error = NULL; } if ((!webpagevals.url) || (strlen (webpagevals.url) == 0)) { g_set_error (&webpagevals.error, 0, 0, _("No URL was specified")); return -1; } scheme = g_uri_parse_scheme (webpagevals.url); if (!scheme) { char *url; /* If we were not given a well-formed URL, make one. */ url = g_strconcat ("http://", webpagevals.url, NULL); g_free (webpagevals.url); webpagevals.url = url; g_free (scheme); } if (webpagevals.width < 32) { g_warning ("Width '%d' is too small. Clamped to 32.", webpagevals.width); webpagevals.width = 32; } else if (webpagevals.width > 8192) { g_warning ("Width '%d' is too large. Clamped to 8192.", webpagevals.width); webpagevals.width = 8192; } window = gtk_offscreen_window_new (); gtk_widget_show (window); view = webkit_web_view_new (); gtk_widget_show (view); gtk_widget_set_size_request (view, webpagevals.width, -1); gtk_container_add (GTK_CONTAINER (window), view); /* Append "GIMP/<GIMP_VERSION>" to the user agent string */ settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view)); g_object_get (settings, "user-agent", &ua_old, NULL); ua = g_strdup_printf ("%s GIMP/%s", ua_old, GIMP_VERSION); g_object_set (settings, "user-agent", ua, NULL); g_free (ua_old); g_free (ua); /* Set font size */ g_object_set (settings, "default-font-size", webpagevals.font_size, NULL); g_signal_connect (view, "notify::progress", G_CALLBACK (notify_progress_cb), window); g_signal_connect (view, "load-error", G_CALLBACK (load_error_cb), window); g_signal_connect (view, "notify::load-status", G_CALLBACK (notify_load_status_cb), window); gimp_progress_init_printf (_("Downloading webpage '%s'"), webpagevals.url); webkit_web_view_open (WEBKIT_WEB_VIEW (view), webpagevals.url); gtk_main (); gtk_widget_destroy (window); gimp_progress_update (1.0); if (webpagevals.pixbuf) { gint width; gint height; gint32 layer; gimp_progress_init_printf (_("Transferring webpage image for '%s'"), webpagevals.url); width = gdk_pixbuf_get_width (webpagevals.pixbuf); height = gdk_pixbuf_get_height (webpagevals.pixbuf); image = gimp_image_new (width, height, GIMP_RGB); gimp_image_undo_disable (image); layer = gimp_layer_new_from_pixbuf (image, _("Webpage"), webpagevals.pixbuf, 100, GIMP_NORMAL_MODE, 0.0, 1.0); gimp_image_insert_layer (image, layer, -1, 0); gimp_image_undo_enable (image); g_object_unref (webpagevals.pixbuf); webpagevals.pixbuf = NULL; gimp_progress_update (1.0); } return image; }
static gboolean copy_uri (const gchar *src_uri, const gchar *dest_uri, const gchar *copying_format_str, const gchar *copied_format_str, GError **error) { GnomeVFSHandle *read_handle; GnomeVFSHandle *write_handle; GnomeVFSFileInfo *src_info; GnomeVFSFileSize file_size = 0; GnomeVFSFileSize bytes_read = 0; guchar buffer[BUFSIZE]; GnomeVFSResult result; gchar *memsize; GTimeVal last_time = { 0, 0 }; gimp_progress_init (_("Connecting to server")); src_info = gnome_vfs_file_info_new (); result = gnome_vfs_get_file_info (src_uri, src_info, 0); /* ignore errors here, they will be noticed below */ if (result == GNOME_VFS_OK && (src_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) { file_size = src_info->size; } gnome_vfs_file_info_unref (src_info); result = gnome_vfs_open (&read_handle, src_uri, GNOME_VFS_OPEN_READ); if (result != GNOME_VFS_OK) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Could not open '%s' for reading: %s"), src_uri, gnome_vfs_result_to_string (result)); return FALSE; } result = gnome_vfs_create (&write_handle, dest_uri, GNOME_VFS_OPEN_WRITE, FALSE, 0644); if (result != GNOME_VFS_OK) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Could not open '%s' for writing: %s"), dest_uri, gnome_vfs_result_to_string (result)); gnome_vfs_close (read_handle); return FALSE; } memsize = g_format_size_for_display (file_size); gimp_progress_init_printf (file_size > 0 ? copying_format_str : copied_format_str, memsize); g_free (memsize); while (TRUE) { GnomeVFSFileSize chunk_read; GnomeVFSFileSize chunk_written; GTimeVal now; result = gnome_vfs_read (read_handle, buffer, sizeof (buffer), &chunk_read); if (chunk_read == 0) { if (result != GNOME_VFS_ERROR_EOF) { memsize = g_format_size_for_display (sizeof (buffer)); g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Failed to read %s from '%s': %s"), memsize, src_uri, gnome_vfs_result_to_string (result)); g_free (memsize); gnome_vfs_close (read_handle); gnome_vfs_close (write_handle); return FALSE; } else { gimp_progress_update (1.0); break; } } bytes_read += chunk_read; /* update the progress only up to 10 times a second */ g_get_current_time (&now); if (((now.tv_sec - last_time.tv_sec) * 1000 + (now.tv_usec - last_time.tv_usec) / 1000) > 100) { if (file_size > 0) { gimp_progress_update ((gdouble) bytes_read / (gdouble) file_size); } else { memsize = g_format_size_for_display (bytes_read); gimp_progress_set_text_printf (copied_format_str, memsize); gimp_progress_pulse (); g_free (memsize); } last_time = now; } result = gnome_vfs_write (write_handle, buffer, chunk_read, &chunk_written); if (chunk_written < chunk_read) { memsize = g_format_size_for_display (chunk_read); g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Failed to write %s to '%s': %s"), memsize, dest_uri, gnome_vfs_result_to_string (result)); g_free (memsize); gnome_vfs_close (read_handle); gnome_vfs_close (write_handle); return FALSE; } } gnome_vfs_close (read_handle); gnome_vfs_close (write_handle); return TRUE; }
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; }
gint32 load_thumbnail_image (GFile *file, gint *width, gint *height, GimpImageType *type, GError **error) { gint32 volatile image_ID = -1; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; FILE *infile = NULL; gimp_progress_init_printf (_("Opening thumbnail for '%s'"), g_file_get_parse_name (file)); image_ID = gimp_image_metadata_load_thumbnail (file, error); if (image_ID < 1) return -1; 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 (g_file_get_path (file), "rb")) == NULL) { g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), _("Could not open '%s' for reading: %s"), g_file_get_parse_name (file), g_strerror (errno)); if (image_ID != -1) gimp_image_delete (image_ID); 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); 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; switch (cinfo.output_components) { case 1: *type = GIMP_GRAY_IMAGE; break; case 3: *type = GIMP_RGB_IMAGE; break; case 4: if (cinfo.out_color_space == JCS_CMYK) { *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); gimp_image_delete (image_ID); image_ID = -1; break; } /* 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); return image_ID; }
static GimpPDBStatusType plt_save(gchar *filename, gint32 image_id) { FILE *stream = 0; unsigned int i, j; uint8_t plt_version[8] = PLT_HEADER_VERSION; uint8_t plt_info[8] = {10, 0, 0, 0, 0, 0, 0, 0}; uint32_t plt_width = 0; uint32_t plt_height = 0; uint8_t *buffer; uint8_t *pixel; uint32_t num_px = 0; GimpImageBaseType img_basetype; gint img_num_layers; // num layers in image gint *img_layer_ids; // all layers in image gint32 layer_id; gint *plt_layer_ids; gint max_layer_id; gint32 detected_plt_layers = 0; gint x, y; gint num_channels; // Channels in image // Only get image data if it's valid if (!gimp_image_is_valid(image_id)) { g_message("Invalid image.\n"); return (GIMP_PDB_EXECUTION_ERROR); } plt_width = gimp_image_width(image_id); plt_height = gimp_image_height(image_id); img_basetype = gimp_image_base_type(image_id); gimp_progress_init_printf("Exporting %s", filename); gimp_progress_update(0.0); img_layer_ids = gimp_image_get_layers(image_id, &img_num_layers); if (img_num_layers < PLT_NUM_LAYERS) { g_message("Requires an image with at least 10 layers.\n"); g_free(img_layer_ids); return (GIMP_PDB_EXECUTION_ERROR); } max_layer_id = -1; for (i = 0; i < img_num_layers; i++) { if (img_layer_ids[i] > max_layer_id) { max_layer_id = img_layer_ids[i]; } } // Try to find the 10 plt layers by looking for matching layer names plt_layer_ids = g_malloc(sizeof(gint)*max_layer_id); for (i = 0; i < max_layer_id; i++) { plt_layer_ids[i] = -1; } for (i = 0; i < PLT_NUM_LAYERS; i++) { for (j = 0; j < img_num_layers; j++) { if (!g_ascii_strcasecmp(plt_layernames[i], gimp_item_get_name(img_layer_ids[j]))) { plt_layer_ids[img_layer_ids[j]] = i; detected_plt_layers++; break; } } } // If we can't find the layers by name, use the 10 topmost layers instead // (Interpreted as tattoo2, tattoo1, ... from the top) if (detected_plt_layers < PLT_NUM_LAYERS) { for (i = 0; i < PLT_NUM_LAYERS; i++) { plt_layer_ids[img_layer_ids[i]] = PLT_NUM_LAYERS-i-1; } } // Write image data to buffer num_px = plt_width * plt_height; buffer = (uint8_t*) g_malloc(sizeof(uint8_t)*2*num_px); switch(img_basetype) { case GIMP_GRAY: { // Gray Image // >= 1 channels: value (+ alpha). We ignore alpha though, so it // doesn't matter wether its present or not. for (i = 0; i < num_px; i++) { x = (gint)(i % plt_width); y = plt_height - (gint)(floor(i / plt_width)) - 1; layer_id = gimp_image_pick_correlate_layer(image_id, x, y); if ((layer_id >= 0) && (plt_layer_ids[layer_id] >= 0)) { pixel = gimp_drawable_get_pixel(layer_id, x, y, &num_channels); buffer[2*i] = pixel[0]; buffer[2*i+1] = plt_layer_ids[layer_id]; } else { buffer[2*i] = 255; buffer[2*i+1] = 0; } gimp_progress_update((float) i/ (float) num_px); } break; } case GIMP_RGB: { // RGB Image // >= 3 channels: r +g + b (+ alpha). We ignore alpha though, so it // doesn't matter wether its present or not. // We'll calculate gray value with (r+g+b)/3. for (i = 0; i < num_px; i++) { x = (gint)(i % plt_width); y = plt_height - (gint)(floor(i / plt_width)) - 1; layer_id = gimp_image_pick_correlate_layer(image_id, x, y); if ((layer_id >= 0) && (plt_layer_ids[layer_id] >= 0)) { pixel = gimp_drawable_get_pixel(layer_id, x, y, &num_channels); buffer[2*i] = pixel[0]; buffer[2*i+1] = plt_layer_ids[layer_id]; } else { buffer[2*i] = 255; buffer[2*i+1] = 0; } gimp_progress_update((float) i/ (float) num_px); } break; } case GIMP_INDEXED: // You're out of luck buddy default: { g_message("Image type has to be Grayscale or RGB.\n"); g_free(buffer); g_free(img_layer_ids); g_free(plt_layer_ids); return (GIMP_PDB_EXECUTION_ERROR); } } gimp_progress_update(1.0); stream = fopen(filename, "wb"); if (stream == 0) { g_message("Error opening %s\n", filename); g_free(buffer); g_free(img_layer_ids); g_free(plt_layer_ids); return (GIMP_PDB_EXECUTION_ERROR); } // Write header fwrite(plt_version, 1, 8, stream); fwrite(plt_info, 1, 8, stream); fwrite(&plt_width, 4, 1, stream); fwrite(&plt_height, 4, 1, stream); // Write image data fwrite(buffer, 1, 2*num_px, stream); fclose(stream); g_free(buffer); g_free(img_layer_ids); g_free(plt_layer_ids); return (GIMP_PDB_SUCCESS); }
static GimpPDBStatusType plt_load(gchar *filename, gint32 *image_id) { FILE *stream = 0; unsigned int i; // Using uint for guaranteed sizes across all systems // guint may or may not work (?) uint8_t plt_version[8]; uint32_t plt_width = 0; uint32_t plt_height = 0; uint8_t *buffer; uint8_t px_value = 0; uint8_t px_layer = 0; uint32_t num_px = 0; gint32 newImgID = -1; gint32 newLayerID = -1; gint32 plt_layer_ids[PLT_NUM_LAYERS]; guint8 pixel[2] = {0, 255}; // GRAYA image = 2 Channels: Value + Alpha stream = fopen(filename, "rb"); if(stream == 0) { g_message("Error opening file.\n"); return (GIMP_PDB_EXECUTION_ERROR); } gimp_progress_init_printf("Opening %s", filename); gimp_progress_update(0.0); // Read header: Version, should be 8x1 bytes = "PLT V1 " if (fread(plt_version, 1, 8, stream) < 8) { g_message("Invalid plt file: Unable to read version information.\n"); fclose(stream); return (GIMP_PDB_EXECUTION_ERROR); } if (g_ascii_strncasecmp(plt_version, PLT_HEADER_VERSION, 8) != 0) { g_message("Invalid plt file: Version mismatch.\n"); fclose(stream); return (GIMP_PDB_EXECUTION_ERROR); } // Read header: Next 8 bytes don't matter fseek(stream, 8, SEEK_CUR); // Read header: Width if (fread(&plt_width, 4, 1, stream) < 1) { g_message("Invalid plt file: Unable to read width.\n"); fclose(stream); return (GIMP_PDB_EXECUTION_ERROR); } // Read header: Height if (fread(&plt_height, 4, 1, stream) < 1) { g_message("Invalid plt file: Unable to read height.\n"); fclose(stream); return (GIMP_PDB_EXECUTION_ERROR); } // Create a new image newImgID = gimp_image_new(plt_width, plt_height, GIMP_GRAY); if(newImgID == -1) { g_message("Unable to allocate new image.\n"); fclose(stream); return (GIMP_PDB_EXECUTION_ERROR); } gimp_image_set_filename(newImgID, filename); // Create the 10 plt layers, add them to the new image and save their ID's for (i = 0; i < PLT_NUM_LAYERS; i++) { newLayerID = gimp_layer_new(newImgID, plt_layernames[i], plt_width, plt_height, GIMP_GRAYA_IMAGE, 100.0, GIMP_NORMAL_MODE); gimp_image_insert_layer(newImgID, newLayerID, 0, 0); plt_layer_ids[i] = newLayerID; } // Read image data // Expecting width*height (value, layer) tuples = 2*width*height bytes num_px = plt_width * plt_height; buffer = (uint8_t*) g_malloc(sizeof(uint8_t)*2*num_px); if (fread(buffer, 1, 2*num_px, stream) < (2*num_px)) { g_message("Image size mismatch.\n"); fclose(stream); g_free(buffer); gimp_image_delete(newImgID); return (GIMP_PDB_EXECUTION_ERROR); } for (i = 0; i < num_px; i++) { pixel[0] = buffer[2*i]; px_layer = buffer[2*i+1]; gimp_drawable_set_pixel(plt_layer_ids[px_layer], i % plt_width, plt_height - (int)(floor(i / plt_width)) - 1, 2, pixel); gimp_progress_update((float) i/ (float) num_px); } gimp_progress_update(1.0); gimp_image_set_active_layer(newImgID, plt_layer_ids[0]); fclose(stream); g_free(buffer); *image_id = newImgID; return (GIMP_PDB_SUCCESS); }
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; }
static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { GimpDrawable *drawable; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; /* assume the best! */ static GimpParam values[1]; INIT_I18N (); /* * Get the specified drawable, do standard initialization. */ if (strcmp (name, PLUG_IN_PROC[0]) == 0) rndm_type = RNDM_HURL; else if (strcmp (name, PLUG_IN_PROC[1]) == 0) rndm_type = RNDM_PICK; else if (strcmp (name, PLUG_IN_PROC[2]) == 0) rndm_type = RNDM_SLUR; run_mode = param[0].data.d_int32; drawable = gimp_drawable_get(param[2].data.d_drawable); *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; gr = g_rand_new (); /* * Make sure the drawable type is appropriate. */ if (gimp_drawable_is_rgb (drawable->drawable_id) || gimp_drawable_is_gray (drawable->drawable_id) || gimp_drawable_is_indexed (drawable->drawable_id)) { gimp_tile_cache_ntiles (2 * drawable->ntile_cols); switch (run_mode) { /* * If we're running interactively, pop up the dialog box. */ case GIMP_RUN_INTERACTIVE: gimp_get_data (PLUG_IN_PROC[rndm_type - 1], &pivals); if (! randomize_dialog (drawable)) /* return on Cancel */ return; break; /* * If we're not interactive (probably scripting), we * get the parameters from the param[] array, since * we don't use the dialog box. Make sure they all * parameters have legitimate values. */ case GIMP_RUN_NONINTERACTIVE: if (nparams != 7) { status = GIMP_PDB_CALLING_ERROR; } else { pivals.rndm_pct = (gdouble) param[3].data.d_float; pivals.rndm_rcount = (gdouble) param[4].data.d_float; pivals.randomize = (gboolean) param[5].data.d_int32; pivals.seed = (gint) param[6].data.d_int32; if (pivals.randomize) pivals.seed = g_random_int (); if ((rndm_type != RNDM_PICK && rndm_type != RNDM_SLUR && rndm_type != RNDM_HURL) || (pivals.rndm_pct < 1.0 || pivals.rndm_pct > 100.0) || (pivals.rndm_rcount < 1.0 || pivals.rndm_rcount > 100.0)) { status = GIMP_PDB_CALLING_ERROR; } } break; /* * If we're running with the last set of values, get those values. */ case GIMP_RUN_WITH_LAST_VALS: gimp_get_data (PLUG_IN_PROC[rndm_type - 1], &pivals); if (pivals.randomize) pivals.seed = g_random_int (); break; /* * Hopefully we never get here! */ default: break; } if (status == GIMP_PDB_SUCCESS) { gimp_progress_init_printf ("%s", gettext (RNDM_NAME[rndm_type - 1])); /* * Initialize the g_rand() function seed */ g_rand_set_seed (gr, pivals.seed); randomize (drawable, NULL); /* * If we ran interactively (even repeating) update the display. */ if (run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_displays_flush (); } /* * If we use the dialog popup, set the data for future use. */ if (run_mode == GIMP_RUN_INTERACTIVE) { gimp_set_data (PLUG_IN_PROC[rndm_type - 1], &pivals, sizeof (RandomizeVals)); } } } else { /* * If we got the wrong drawable type, we need to complain. */ status = GIMP_PDB_EXECUTION_ERROR; } /* * DONE! * Set the status where GIMP can see it, and let go * of the drawable. */ g_rand_free (gr); values[0].data.d_status = status; gimp_drawable_detach(drawable); }
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; }
static gboolean save_image (const gchar *filename, GeglBuffer *buffer, GError **error) { const Babl *format = babl_format ("R'G'B'A u8"); gint row, col, cols, rows, x, y; gint colcount, colspan, rowspan; gint *palloc; guchar *buf, *buf2; gchar *width, *height; FILE *fp; cols = gegl_buffer_get_width (buffer); rows = gegl_buffer_get_height (buffer); fp = g_fopen (filename, "w"); if (! fp) { 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; } palloc = g_new (int, rows * cols); if (gtmvals.fulldoc) { fprintf (fp, "<HTML>\n<HEAD><TITLE>%s</TITLE></HEAD>\n<BODY>\n", filename); fprintf (fp, "<H1>%s</H1>\n", filename); } fprintf (fp, "<TABLE BORDER=%d CELLPADDING=%d CELLSPACING=%d>\n", gtmvals.border, gtmvals.cellpadding, gtmvals.cellspacing); if (gtmvals.caption) fprintf (fp, "<CAPTION>%s</CAPTION>\n", gtmvals.captiontxt); gimp_progress_init_printf (_("Saving '%s'"), gimp_filename_to_utf8 (filename)); buf = g_new (guchar, babl_format_get_bytes_per_pixel (format)); buf2 = g_new (guchar, babl_format_get_bytes_per_pixel (format)); width = height = NULL; if (strcmp (gtmvals.clwidth, "") != 0) { width = g_strdup_printf (" WIDTH=\"%s\"", gtmvals.clwidth); } if (strcmp (gtmvals.clheight, "") != 0) { height = g_strdup_printf (" HEIGHT=\"%s\" ", gtmvals.clheight); } if (! width) width = g_strdup (" "); if (! height) height = g_strdup (" "); /* Initialize array to hold ROWSPAN and COLSPAN cell allocation table */ for (row = 0; row < rows; row++) for (col = 0; col < cols; col++) palloc[cols * row + col] = 1; colspan = 0; rowspan = 0; for (y = 0; y < rows; y++) { fprintf (fp," <TR>\n"); for (x = 0; x < cols; x++) { gegl_buffer_sample (buffer, x, y, NULL, buf, format, GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); /* Determine ROWSPAN and COLSPAN */ if (gtmvals.spantags) { col = x; row = y; colcount = 0; colspan = 0; rowspan = 0; gegl_buffer_sample (buffer, col, row, NULL, buf2, format, GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); while (color_comp (buf, buf2) && palloc[cols * row + col] == 1 && row < rows) { while (color_comp (buf, buf2) && palloc[cols * row + col] == 1 && col < cols) { colcount++; col++; gegl_buffer_sample (buffer, col, row, NULL, buf2, format, GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); } if (colcount != 0) { row++; rowspan++; } if (colcount < colspan || colspan == 0) colspan = colcount; col = x; colcount = 0; gegl_buffer_sample (buffer, col, row, NULL, buf2, format, GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); } if (colspan > 1 || rowspan > 1) { for (row = 0; row < rowspan; row++) for (col = 0; col < colspan; col++) palloc[cols * (row + y) + (col + x)] = 0; palloc[cols * y + x] = 2; } } if (palloc[cols * y + x] == 1) fprintf (fp, " <TD%s%sBGCOLOR=#%02x%02x%02x>", width, height, buf[0], buf[1], buf[2]); if (palloc[cols * y + x] == 2) fprintf (fp," <TD ROWSPAN=\"%d\" COLSPAN=\"%d\"%s%sBGCOLOR=#%02x%02x%02x>", rowspan, colspan, width, height, buf[0], buf[1], buf[2]); if (palloc[cols * y + x] != 0) { if (gtmvals.tdcomp) fprintf (fp, "%s</TD>\n", gtmvals.cellcontent); else fprintf (fp, "\n %s\n </TD>\n", gtmvals.cellcontent); } } fprintf (fp," </TR>\n"); gimp_progress_update ((double) y / (double) rows); } gimp_progress_update (1.0); if (gtmvals.fulldoc) fprintf (fp, "</TABLE></BODY></HTML>\n"); else fprintf (fp, "</TABLE>\n"); fclose (fp); g_free (width); g_free (height); g_free (palloc); return TRUE; }
/* Main file load function */ gint32 load_thumbnail_image (const gchar *filename, gint *width, gint *height, GError **load_error) { FILE *f; struct stat st; PSDimage img_a; gint32 image_id = -1; GError *error = NULL; /* ----- Open PSD file ----- */ if (g_stat (filename, &st) == -1) return -1; IFDBG(1) g_debug ("Open file %s", gimp_filename_to_utf8 (filename)); f = g_fopen (filename, "rb"); if (f == NULL) { g_set_error (load_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; } gimp_progress_init_printf (_("Opening thumbnail for '%s'"), gimp_filename_to_utf8 (filename)); /* ----- Read the PSD file Header block ----- */ IFDBG(2) g_debug ("Read header block"); if (read_header_block (&img_a, f, &error) < 0) goto load_error; gimp_progress_update (0.2); /* ----- Read the PSD file Colour Mode block ----- */ IFDBG(2) g_debug ("Read colour mode block"); if (read_color_mode_block (&img_a, f, &error) < 0) goto load_error; gimp_progress_update (0.4); /* ----- Read the PSD file Image Resource block ----- */ IFDBG(2) g_debug ("Read image resource block"); if (read_image_resource_block (&img_a, f, &error) < 0) goto load_error; gimp_progress_update (0.6); /* ----- Create GIMP image ----- */ IFDBG(2) g_debug ("Create GIMP image"); image_id = create_gimp_image (&img_a, filename); if (image_id < 0) goto load_error; /* ----- Add image resources ----- */ IFDBG(2) g_debug ("Add image resources"); if (add_image_resources (image_id, &img_a, f, &error) < 1) goto load_error; gimp_progress_update (1.0); gimp_image_clean_all (image_id); gimp_image_undo_enable (image_id); fclose (f); *width = img_a.columns; *height = img_a.rows; return image_id; /* ----- Process load errors ----- */ load_error: if (error) { g_set_error (load_error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Error loading PSD file: %s"), error->message); g_error_free (error); } /* Delete partially loaded image */ if (image_id > 0) gimp_image_delete (image_id); /* Close file if Open */ if (! (f == NULL)) fclose (f); return -1; }
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; }
GimpPDBStatusType ico_save_image (const gchar *filename, gint32 image, gint32 run_mode, GError **error) { FILE *fp; gint i; gint width, height; IcoSaveInfo info; IcoFileHeader header; IcoFileEntry *entries; gboolean saved; D(("*** Saving Microsoft icon file %s\n", filename)); ico_save_init (image, &info); if (run_mode == GIMP_RUN_INTERACTIVE) { /* Allow user to override default values */ if ( !ico_save_dialog (image, &info)) return GIMP_PDB_CANCEL; } gimp_progress_init_printf (_("Saving '%s'"), gimp_filename_to_utf8 (filename)); if (! (fp = g_fopen (filename, "wb"))) { 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 GIMP_PDB_EXECUTION_ERROR; } header.reserved = 0; header.resource_type = 1; header.icon_count = info.num_icons; if ( !ico_write_int16 (fp, &header.reserved, 1) || !ico_write_int16 (fp, &header.resource_type, 1) || !ico_write_int16 (fp, &header.icon_count, 1) ) { ico_save_info_free (&info); fclose (fp); return GIMP_PDB_EXECUTION_ERROR; } entries = g_new0 (IcoFileEntry, info.num_icons); if (fwrite (entries, sizeof (IcoFileEntry), info.num_icons, fp) <= 0) { ico_save_info_free (&info); g_free (entries); fclose (fp); return GIMP_PDB_EXECUTION_ERROR; } for (i = 0; i < info.num_icons; i++) { gimp_progress_update ((gdouble)i / (gdouble)info.num_icons); width = gimp_drawable_width (info.layers[i]); height = gimp_drawable_height (info.layers[i]); if (width <= 255 && height <= 255) { entries[i].width = width; entries[i].height = height; } else { entries[i].width = 0; entries[i].height = 0; } if ( info.depths[i] <= 8 ) entries[i].num_colors = 1 << info.depths[i]; else entries[i].num_colors = 0; entries[i].reserved = 0; entries[i].planes = 1; entries[i].bpp = info.depths[i]; entries[i].offset = ftell (fp); if (info.compress[i]) saved = ico_write_png (fp, info.layers[i], info.depths[i]); else saved = ico_write_icon (fp, info.layers[i], info.depths[i]); if (!saved) { ico_save_info_free (&info); fclose (fp); return GIMP_PDB_EXECUTION_ERROR; } entries[i].size = ftell (fp) - entries[i].offset; } for (i = 0; i < info.num_icons; i++) { entries[i].planes = GUINT16_TO_LE (entries[i].planes); entries[i].bpp = GUINT16_TO_LE (entries[i].bpp); entries[i].size = GUINT32_TO_LE (entries[i].size); entries[i].offset = GUINT32_TO_LE (entries[i].offset); } if (fseek (fp, sizeof(IcoFileHeader), SEEK_SET) < 0 || fwrite (entries, sizeof (IcoFileEntry), info.num_icons, fp) <= 0) { ico_save_info_free (&info); fclose (fp); return GIMP_PDB_EXECUTION_ERROR; } gimp_progress_update (1.0); ico_save_info_free (&info); fclose (fp); g_free (entries); return GIMP_PDB_SUCCESS; }
static gboolean lcms_image_apply_profile (gint32 image, cmsHPROFILE src_profile, cmsHPROFILE dest_profile, const gchar *filename, GimpColorRenderingIntent intent, gboolean bpc) { gint32 saved_selection = -1; gimp_image_undo_group_start (image); if (! lcms_image_set_profile (image, dest_profile, filename, FALSE)) { gimp_image_undo_group_end (image); return FALSE; } { gchar *src = lcms_icc_profile_get_desc (src_profile); gchar *dest = lcms_icc_profile_get_desc (dest_profile); /* ICC color profile conversion */ gimp_progress_init_printf (_("Converting from '%s' to '%s'"), src, dest); g_printerr ("lcms: converting from '%s' to '%s'\n", src, dest); g_free (dest); g_free (src); } if (! gimp_selection_is_empty (image)) { saved_selection = gimp_selection_save (image); gimp_selection_none (image); } switch (gimp_image_base_type (image)) { case GIMP_RGB: lcms_image_transform_rgb (image, src_profile, dest_profile, intent, bpc); break; case GIMP_GRAY: g_warning ("colorspace conversion not implemented for " "grayscale images"); break; case GIMP_INDEXED: lcms_image_transform_indexed (image, src_profile, dest_profile, intent, bpc); break; } if (saved_selection != -1) { gimp_image_select_item (image, GIMP_CHANNEL_OP_REPLACE, saved_selection); gimp_image_remove_channel (image, saved_selection); } gimp_progress_update (1.0); gimp_image_undo_group_end (image); return TRUE; }
static gint32 webpage_capture (void) { gchar *scheme; GtkWidget *window; GtkWidget *view; WebKitSettings *settings; char *ua; if ((!webpagevals.url) || (strlen (webpagevals.url) == 0)) { g_set_error (&webpagevals.error, 0, 0, _("No URL was specified")); return -1; } scheme = g_uri_parse_scheme (webpagevals.url); if (!scheme) { char *url; /* If we were not given a well-formed URL, make one. */ url = g_strconcat ("http://", webpagevals.url, NULL); g_free (webpagevals.url); webpagevals.url = url; g_free (scheme); } if (webpagevals.width < 32) { g_warning ("Width '%d' is too small. Clamped to 32.", webpagevals.width); webpagevals.width = 32; } else if (webpagevals.width > 8192) { g_warning ("Width '%d' is too large. Clamped to 8192.", webpagevals.width); webpagevals.width = 8192; } window = gtk_offscreen_window_new (); gtk_widget_show (window); view = webkit_web_view_new (); gtk_widget_show (view); gtk_widget_set_vexpand (view, TRUE); gtk_widget_set_size_request (view, webpagevals.width, -1); gtk_container_add (GTK_CONTAINER (window), view); /* Append "GIMP/<GIMP_VERSION>" to the user agent string */ settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view)); ua = g_strdup_printf ("%s GIMP/%s", webkit_settings_get_user_agent (settings), GIMP_VERSION); webkit_settings_set_user_agent (settings, ua); g_free (ua); /* Set font size */ webkit_settings_set_default_font_size (settings, webpagevals.font_size); g_signal_connect (view, "notify::estimated-load-progress", G_CALLBACK (notify_progress_cb), window); g_signal_connect (view, "load-failed", G_CALLBACK (load_failed_cb), window); g_signal_connect (view, "load-changed", G_CALLBACK (load_changed_cb), window); gimp_progress_init_printf (_("Downloading webpage '%s'"), webpagevals.url); webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), webpagevals.url); gtk_main (); gtk_widget_destroy (window); gimp_progress_update (1.0); return webpagevals.image; }
/* * 'load_image()' - Load a WMF image into a new image window. */ static gint32 load_image (const gchar *filename, GError **error) { gint32 image; gint32 layer; GimpDrawable *drawable; guchar *pixels; GimpPixelRgn pixel_rgn; guint width, height; guint rowstride; guint count = 0; guint done = 0; gpointer pr; pixels = wmf_load_file (filename, &width, &height, error); if (! pixels) return -1; rowstride = width * 4; gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); image = gimp_image_new (width, height, GIMP_RGB); gimp_image_set_filename (image, filename); gimp_image_set_resolution (image, load_vals.resolution, load_vals.resolution); layer = gimp_layer_new (image, _("Rendered WMF"), width, height, GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE); drawable = gimp_drawable_get (layer); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, TRUE, FALSE); for (pr = gimp_pixel_rgns_register (1, &pixel_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { const guchar *src = pixels + pixel_rgn.y * rowstride + pixel_rgn.x * 4; guchar *dest = pixel_rgn.data; gint y; for (y = 0; y < pixel_rgn.h; y++) { memcpy (dest, src, pixel_rgn.w * pixel_rgn.bpp); src += rowstride; dest += pixel_rgn.rowstride; } done += pixel_rgn.h * pixel_rgn.w; if (count++ % 16 == 0) gimp_progress_update ((gdouble) done / (width * height)); } g_free (pixels); gimp_drawable_detach (drawable); gimp_progress_update (1.0); /* Tell GIMP to display the image. */ gimp_image_insert_layer (image, layer, -1, 0); gimp_drawable_flush (drawable); return image; }
/* Save a WebP image to disk */ gboolean save_image(const gchar *filename, #ifdef WEBP_0_5 gint32 nLayers, gint32 *allLayers, #endif gint32 drawable_ID, WebPSaveParams *params, GError **error) { gboolean status = FALSE; FILE *outfile = NULL; #ifdef GIMP_2_9 /* Initialize GEGL */ gegl_init(NULL, NULL); #endif /* Begin displaying export progress */ gimp_progress_init_printf("Saving '%s'", gimp_filename_to_utf8(filename)); /* Attempt to open the output file */ if((outfile = g_fopen(filename, "wb+")) == NULL) { g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno), "Unable to open '%s' for writing", gimp_filename_to_utf8(filename)); return FALSE; } #ifdef WEBP_0_5 if (params->animation == TRUE) { status = save_animation(nLayers, allLayers, outfile, params, error); } else { #endif status = save_layer(drawable_ID, webp_file_writer, outfile, #ifdef WEBP_0_5 FALSE, NULL, 0, #endif params, error); #ifdef WEBP_0_5 } #endif /* Close the file */ if(outfile) { fclose(outfile); } return status; }