gboolean gimp_image_set_icc_profile (GimpImage *image, const guint8 *data, gsize length, GError **error) { GimpParasite *parasite = NULL; g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); g_return_val_if_fail (data == NULL || length != 0, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (data) { parasite = gimp_parasite_new (GIMP_ICC_PROFILE_PARASITE_NAME, GIMP_PARASITE_PERSISTENT | GIMP_PARASITE_UNDOABLE, length, data); if (! gimp_image_validate_icc_parasite (image, parasite, error)) { gimp_parasite_free (parasite); return FALSE; } } gimp_image_set_icc_parasite (image, parasite); if (parasite) gimp_parasite_free (parasite); return TRUE; }
void jpeg_exif_rotate_query (gint32 image_ID, gint orientation) { GimpParasite *parasite; gboolean query = load_interactive; if (orientation < 2 || orientation > 8) return; parasite = gimp_parasite_find (JPEG_EXIF_ROTATE_PARASITE); if (parasite) { if (strncmp (gimp_parasite_data (parasite), "yes", gimp_parasite_data_size (parasite)) == 0) { query = FALSE; } else if (strncmp (gimp_parasite_data (parasite), "no", gimp_parasite_data_size (parasite)) == 0) { gimp_parasite_free (parasite); return; } gimp_parasite_free (parasite); } if (query && ! jpeg_exif_rotate_query_dialog (image_ID)) return; jpeg_exif_rotate (image_ID, orientation); }
/* --------------------------------------------------- * gap_dvref_get_drawable_video_reference_via_parasite * --------------------------------------------------- * return Gap drawable video reference parasite if such a parasite is atached to the specified drawable_id * oterwise return NULL; */ GapDrawableVideoRef * gap_dvref_get_drawable_video_reference_via_parasite(gint32 drawable_id) { GapDrawableVideoRef *dvref; GimpParasite *l_parasite; dvref = NULL; l_parasite = gimp_drawable_parasite_find(drawable_id, GAP_DRAWABLE_VIDEOFILE_PARASITE_NAME); if(l_parasite) { if(gap_debug) { printf("gap_dvref_get_drawable_video_reference_via_parasite: size:%d data:%s\n" ,l_parasite->size ,(char *)l_parasite->data ); } dvref = g_new(GapDrawableVideoRef, 1); dvref->videofile = g_malloc0(l_parasite->size +1); memcpy(dvref->videofile, l_parasite->data, l_parasite->size); gimp_parasite_free(l_parasite); l_parasite = gimp_drawable_parasite_find(drawable_id, GAP_DRAWABLE_VIDEOPARAMS_PARASITE_NAME); if(l_parasite) { memcpy(&dvref->para, l_parasite->data, sizeof(GapDrawableVideoParasite)); gimp_parasite_free(l_parasite); if(gap_debug) { printf("gap_dvref_get_drawable_video_reference_via_parasite: dvref PARASITES OK\n"); gap_dvref_debug_print_GapDrawableVideoRef(dvref); } return (dvref); } } if(gap_debug) { printf("gap_dvref_get_drawable_video_reference_via_parasite: NO dvref parasites found.\n"); } return (NULL); } /* end gap_dvref_get_drawable_video_reference_via_parasite */
void gimp_text_layer_xcf_save_prepare (GimpTextLayer *layer) { GimpText *text; g_return_if_fail (GIMP_IS_TEXT_LAYER (layer)); /* If the layer has a text parasite already, it wasn't changed and we * can simply save the original parasite back which is still attached. */ if (layer->text_parasite) return; text = gimp_text_layer_get_text (layer); if (text) { GimpParasite *parasite = gimp_text_to_parasite (text); /* Don't push an undo because the parasite only exists temporarily * while the text layer is saved to XCF. */ gimp_item_parasite_attach (GIMP_ITEM (layer), parasite, FALSE); gimp_parasite_free (parasite); } }
static void save_defaults (void) { GimpParasite *parasite; gchar *def_str; def_str = g_strdup_printf ("%lf %lf %d %d %d %d %d %d %d %d %d %d %d %d %d", jsvals.quality, jsvals.smoothing, jsvals.optimize, jsvals.progressive, (gint) jsvals.subsmp, jsvals.baseline, jsvals.restart, jsvals.dct, jsvals.preview, jsvals.save_exif, jsvals.save_thumbnail, jsvals.save_xmp, jsvals.use_orig_quality, jsvals.save_iptc, jsvals.arithmetic_coding); parasite = gimp_parasite_new (JPEG_DEFAULTS_PARASITE, GIMP_PARASITE_PERSISTENT, strlen (def_str), def_str); gimp_attach_parasite (parasite); gimp_parasite_free (parasite); g_free (def_str); }
GimpImage * gimp_create_image (Gimp *gimp, gint width, gint height, GimpImageBaseType type, GimpPrecision precision, gboolean attach_comment) { GimpImage *image; g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); image = gimp_image_new (gimp, width, height, type, precision); if (attach_comment) { const gchar *comment; comment = gimp_template_get_comment (gimp->config->default_image); if (comment) { GimpParasite *parasite = gimp_parasite_new ("gimp-comment", GIMP_PARASITE_PERSISTENT, strlen (comment) + 1, comment); gimp_image_parasite_attach (image, parasite); gimp_parasite_free (parasite); } } return image; }
static void gimp_item_prop_undo_free (GimpUndo *undo, GimpUndoMode undo_mode) { GimpItemPropUndo *item_prop_undo = GIMP_ITEM_PROP_UNDO (undo); if (item_prop_undo->name) { g_free (item_prop_undo->name); item_prop_undo->name = NULL; } if (item_prop_undo->parasite_name) { g_free (item_prop_undo->parasite_name); item_prop_undo->parasite_name = NULL; } if (item_prop_undo->parasite) { gimp_parasite_free (item_prop_undo->parasite); item_prop_undo->parasite = NULL; } GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode); }
static gint32 create_image (GdkPixbuf *pixbuf, GdkRegion *shape, const gchar *name) { gint32 image; gint32 layer; gdouble xres, yres; gchar *comment; gint width, height; gboolean status; status = gimp_progress_init (_("Importing screenshot")); width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); image = gimp_image_new (width, height, GIMP_RGB); gimp_image_undo_disable (image); gimp_get_monitor_resolution (&xres, &yres); gimp_image_set_resolution (image, xres, yres); comment = gimp_get_default_comment (); if (comment) { GimpParasite *parasite; parasite = gimp_parasite_new ("gimp-comment", GIMP_PARASITE_PERSISTENT, strlen (comment) + 1, comment); gimp_image_parasite_attach (image, parasite); gimp_parasite_free (parasite); g_free (comment); } layer = gimp_layer_new_from_pixbuf (image, name ? name : _("Screenshot"), pixbuf, 100, GIMP_NORMAL_MODE, 0.0, 1.0); gimp_image_add_layer (image, layer, 0); if (shape && ! gdk_region_empty (shape)) { image_select_shape (image, shape); if (! gimp_selection_is_empty (image)) { gimp_layer_add_alpha (layer); gimp_edit_clear (layer); gimp_selection_none (image); } } gimp_image_undo_enable (image); return image; }
static gboolean parasite_free (const gchar *key, GimpParasite *parasite, gpointer unused) { gimp_parasite_free (parasite); return TRUE; }
/* ---------------------------------------------------- * p_drop_image_cache * ---------------------------------------------------- * drop the image cache. */ static void p_drop_image_cache(void) { gint32 *images; gint nimages; gint l_idi; if(gap_debug) { printf("p_drop_image_cache START pid:%d\n", (int) gap_base_getpid()); } images = gimp_image_list(&nimages); for(l_idi=0; l_idi < nimages; l_idi++) { GimpParasite *l_parasite; l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_CACHE_PARASITE); if(gap_debug) { printf("FrameFetcher: CHECK (image_id:%d) name:%s pid:%d\n" , (int)images[l_idi] , gimp_image_get_filename(images[l_idi]) , (int)gap_base_getpid() ); } if(l_parasite) { if(gap_debug) { printf("FrameFetcher: DELETE (image_id:%d) name:%s pid:%d\n" , (int)images[l_idi] , gimp_image_get_filename(images[l_idi]) , (int)gap_base_getpid() ); } /* delete image from the duplicates cache */ gap_image_delete_immediate(images[l_idi]); gimp_parasite_free(l_parasite); } } if(images) { g_free(images); } if(gap_debug) { printf("p_drop_image_cache END pid:%d\n", (int)gap_base_getpid()); } } /* end p_drop_image_cache */
/* -------------------------------------- * gap_dvref_assign_videoref_parasites * -------------------------------------- * if gpp->drawable_vref contains vaild video reference * then * assign video reference parasites to the specified drawable_id (typically this is a layer.) * (one parasite contains only the videfilename and has variable length, * the other contains framenumber and other information that was used to fetch * the frame from the videofile). * * the video reference is typically set on successful fetch * from a video file. (and reset on all other types of frame fetches) * + TODO: query gimprc parameter that can configures using persitent drawable_videoref_parasites. * (default shall be temporary parasites) */ void gap_dvref_assign_videoref_parasites(GapDrawableVideoRef *dvref, gint32 drawable_id) { GimpParasite *l_parasite; if(gap_debug) { printf("gap_assign_drawable_videoref_parasite: START\n"); gap_dvref_debug_print_GapDrawableVideoRef(dvref); } if(dvref->videofile == NULL) { /* no viedo reference available for the current frame */ return; } l_parasite = gimp_parasite_new(GAP_DRAWABLE_VIDEOFILE_PARASITE_NAME ,0 /* GIMP_PARASITE_PERSISTENT 0 for non persistent */ ,1 + strlen(dvref->videofile) ,dvref->videofile /* parasite data */ ); if(l_parasite) { gimp_drawable_parasite_attach(drawable_id, l_parasite); gimp_parasite_free(l_parasite); } l_parasite = gimp_parasite_new(GAP_DRAWABLE_VIDEOPARAMS_PARASITE_NAME ,0 /* GIMP_PARASITE_PERSISTENT */ ,sizeof(GapDrawableVideoParasite) ,&dvref->para /* parasite data */ ); if(l_parasite) { gimp_drawable_parasite_attach(drawable_id, l_parasite); gimp_parasite_free(l_parasite); } } /* end gap_dvref_assign_videoref_parasites */
/* ------------------------------------------------- * gap_frame_fetch_delete_list_of_duplicated_images * ------------------------------------------------- * deletes all duplicate imageas that wre created by the specified ffetch_user_id * (if ffetch_user_id -1 is specified delte all duplicated images) */ void gap_frame_fetch_delete_list_of_duplicated_images(gint32 ffetch_user_id) { gint32 *images; gint nimages; gint l_idi; images = gimp_image_list(&nimages); for(l_idi=0; l_idi < nimages; l_idi++) { GimpParasite *l_parasite; l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_DUP_CACHE_PARASITE); if(gap_debug) { printf("FrameFetcher: check (image_id:%d) name:%s pid:%d\n" , (int)images[l_idi] , gimp_image_get_filename(images[l_idi]) , (int)gap_base_getpid() ); } if(l_parasite) { gint32 *ffetch_user_id_ptr; ffetch_user_id_ptr = (gint32 *) l_parasite->data; if((*ffetch_user_id_ptr == ffetch_user_id) || (ffetch_user_id < 0)) { if(gap_debug) { printf("FrameFetcher: DELETE duplicate %s (image_id:%d) user_id:%d (%d) name:%s pid:%d\n" , gimp_image_get_filename(images[l_idi]) , (int)images[l_idi] , (int)ffetch_user_id , (int)*ffetch_user_id_ptr , gimp_image_get_filename(images[l_idi]) , (int)gap_base_getpid() ); } /* delete image from the duplicates cache */ gap_image_delete_immediate(images[l_idi]); } gimp_parasite_free(l_parasite); } } if(images) { g_free(images); } } /* end gap_frame_fetch_delete_list_of_duplicated_images */
static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[2]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; GimpExportReturn export = GIMP_EXPORT_CANCEL; run_mode = param[0].data.d_int32; *nreturn_vals = 1; *return_vals = values; INIT_I18N (); values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; if (run_mode == GIMP_RUN_INTERACTIVE && strcmp (name, SAVE_PROC) == 0) { gint32 image_ID = param[1].data.d_int32; gint32 drawable_ID = param[2].data.d_int32; GimpParasite *parasite; gchar *x; GimpImageType drawable_type = gimp_drawable_type (drawable_ID); gimp_get_data (SAVE_PROC, &config); config.prefixed_name = "gimp_image"; config.comment = NULL; config.file_name = param[3].data.d_string; config.alpha = (drawable_type == GIMP_RGBA_IMAGE || drawable_type == GIMP_GRAYA_IMAGE || drawable_type == GIMP_INDEXEDA_IMAGE); parasite = gimp_image_parasite_find (image_ID, "gimp-comment"); if (parasite) { config.comment = g_strndup (gimp_parasite_data (parasite), gimp_parasite_data_size (parasite)); gimp_parasite_free (parasite); } x = config.comment; gimp_ui_init (PLUG_IN_BINARY, FALSE); export = gimp_export_image (&image_ID, &drawable_ID, "C Source",
/** * gimp_drawable_attach_new_parasite: * @drawable_ID: the ID of the #GimpDrawable to attach the #GimpParasite to. * @name: the name of the #GimpParasite to create and attach. * @flags: the flags set on the #GimpParasite. * @size: the size of the parasite data in bytes. * @data: a pointer to the data attached with the #GimpParasite. * * Convenience function that creates a parasite and attaches it * to GIMP. * * Deprecated: use gimp_image_parasite_attach() instead. * * Return value: TRUE on successful creation and attachment of * the new parasite. * * See Also: gimp_drawable_parasite_attach() */ gboolean gimp_drawable_attach_new_parasite (gint32 drawable_ID, const gchar *name, gint flags, gint size, gconstpointer data) { GimpParasite *parasite = gimp_parasite_new (name, flags, size, data); gboolean success; success = gimp_item_attach_parasite (drawable_ID, parasite); gimp_parasite_free (parasite); return success; }
/* ----------------------------------------- * p_add_image_to_list_of_duplicated_images * ----------------------------------------- * add specified image to the list of duplicated images. * this list contains temporary images of both fetched video frames * and merged duplicates of the cached original images. */ static void p_add_image_to_list_of_duplicated_images(gint32 image_id, gint32 ffetch_user_id) { GimpParasite *l_parasite; /* attach a parasite to mark the image as part of the gap image duplicates cache */ l_parasite = gimp_parasite_new(GAP_IMAGE_DUP_CACHE_PARASITE ,0 /* GIMP_PARASITE_PERSISTENT 0 for non persistent */ , sizeof(gint32) /* size of parasite data */ ,&ffetch_user_id /* parasite data */ ); if(l_parasite) { gimp_image_parasite_attach(image_id, l_parasite); gimp_parasite_free(l_parasite); } } /* end p_add_image_to_list_of_duplicated_images */
/* ------------------------------- * gap_frame_fetch_remove_parasite * ------------------------------- * removes the image parasite that marks the image as member * of the gap frame fetcher cache. */ void gap_frame_fetch_remove_parasite(gint32 image_id) { GimpParasite *l_parasite; l_parasite = gimp_image_parasite_find(image_id, GAP_IMAGE_CACHE_PARASITE); if(l_parasite) { gimp_image_parasite_detach(image_id, GAP_IMAGE_CACHE_PARASITE); if(gap_debug) { printf("FrameFetcher: removed parasite from (image_id:%d) pid:%d\n" , (int)image_id, (int)gap_base_getpid()); } gimp_parasite_free(l_parasite); } } /* end gap_frame_fetch_remove_parasite */
static cmsHPROFILE lcms_image_get_profile (GimpColorConfig *config, gint32 image, GError **error) { GimpParasite *parasite; cmsHPROFILE profile = NULL; g_return_val_if_fail (image != -1, NULL); parasite = gimp_image_get_parasite (image, "icc-profile"); if (parasite) { profile = gimp_lcms_profile_open_from_data (gimp_parasite_data (parasite), gimp_parasite_data_size (parasite), error); if (! profile) g_prefix_error (error, _("Error parsing 'icc-profile': ")); gimp_parasite_free (parasite); } else if (config->rgb_profile) { GFile *file = g_file_new_for_path (config->rgb_profile); profile = gimp_lcms_profile_open_from_file (file, error); if (profile && ! gimp_lcms_profile_is_rgb (profile)) { g_set_error (error, 0, 0, _("Color profile '%s' is not for RGB color space"), gimp_file_get_utf8_name (file)); cmsCloseProfile (profile); profile = NULL; } g_object_unref (file); } return profile; }
void gimp_parasite_list_remove (GimpParasiteList *list, const gchar *name) { g_return_if_fail (GIMP_IS_PARASITE_LIST (list)); if (list->table) { GimpParasite *parasite; parasite = (GimpParasite *) gimp_parasite_list_find (list, name); if (parasite) { g_hash_table_remove (list->table, name); g_signal_emit (list, parasite_list_signals[REMOVE], 0, parasite); gimp_parasite_free (parasite); } } }
static cmsHPROFILE lcms_image_get_profile (GimpColorConfig *config, gint32 image, guchar *checksum) { GimpParasite *parasite; cmsHPROFILE profile = NULL; g_return_val_if_fail (image != -1, NULL); parasite = gimp_image_get_parasite (image, "icc-profile"); if (parasite) { profile = cmsOpenProfileFromMem ((gpointer) gimp_parasite_data (parasite), gimp_parasite_data_size (parasite)); if (profile) { lcms_calculate_checksum (gimp_parasite_data (parasite), gimp_parasite_data_size (parasite), checksum); } else { g_message (_("Data attached as 'icc-profile' does not appear to " "be an ICC color profile")); } gimp_parasite_free (parasite); } else if (config->rgb_profile) { profile = lcms_load_profile (config->rgb_profile, checksum); } return profile; }
static void draw_info_header (GtkPrintContext *context, cairo_t *cr, PrintData *data) { PangoLayout *layout; PangoFontDescription *desc; gdouble text_height; gdouble text_width; gdouble fname_text_width; gint layout_height; gint layout_width; gchar date_buffer[100]; GDate *date; const gchar *name_str; GimpParasite *parasite; const gchar *end_ptr; gchar *filename; gdouble cr_width; cairo_save (cr); cr_width = gtk_print_context_get_width (context); cairo_rectangle (cr, 0, 0, cr_width, HEADER_HEIGHT); cairo_set_source_rgb (cr, 0.8, 0.8, 0.8); cairo_fill_preserve (cr); cairo_set_source_rgb (cr, 0, 0, 0); cairo_set_line_width (cr, 1); cairo_stroke (cr); layout = gtk_print_context_create_pango_layout (context); desc = pango_font_description_from_string ("sans 14"); pango_layout_set_font_description (layout, desc); pango_font_description_free (desc); pango_layout_set_width (layout, -1); pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); /* image name */ pango_layout_set_text (layout, gimp_image_get_name (data->image_id), -1); pango_layout_get_size (layout, &layout_width, &layout_height); text_height = (gdouble) layout_height / PANGO_SCALE; cairo_move_to (cr, 0.02 * cr_width, (HEADER_HEIGHT - text_height) / 5); pango_cairo_show_layout (cr, layout); /* user name */ name_str = g_get_real_name (); if (name_str && g_utf8_validate (name_str, -1, &end_ptr)) { pango_layout_set_text (layout, name_str, -1); pango_layout_get_size (layout, &layout_width, &layout_height); text_height = (gdouble) layout_height / PANGO_SCALE; text_width = (gdouble) layout_width / PANGO_SCALE; cairo_move_to (cr, 0.5 * cr_width - 0.5 * text_width, (HEADER_HEIGHT - text_height) / 5); pango_cairo_show_layout (cr, layout); } /* date */ date = g_date_new (); g_date_set_time_t (date, time (NULL)); g_date_strftime (date_buffer, 100, "%x", date); g_date_free (date); pango_layout_set_text (layout, date_buffer, -1); pango_layout_get_size (layout, &layout_width, &layout_height); text_height = (gdouble) layout_height / PANGO_SCALE; text_width = (gdouble) layout_width / PANGO_SCALE; cairo_move_to (cr, 0.98 * cr_width - text_width, (HEADER_HEIGHT - text_height) / 5); pango_cairo_show_layout (cr, layout); /* file name if any */ filename = gimp_image_get_filename (data->image_id); if (filename) { pango_layout_set_text (layout, gimp_filename_to_utf8 (filename), -1); g_free (filename); pango_layout_get_size (layout, &layout_width, &layout_height); text_height = (gdouble) layout_height / PANGO_SCALE; fname_text_width = (gdouble) layout_width / PANGO_SCALE; cairo_move_to (cr, 0.02 * cr_width, 4 * (HEADER_HEIGHT - text_height) / 5); pango_cairo_show_layout (cr, layout); } else { fname_text_width = 0; } /* image comment if it is short */ parasite = gimp_image_parasite_find (data->image_id, "gimp-comment"); if (parasite) { pango_layout_set_text (layout, gimp_parasite_data (parasite), -1); pango_layout_get_size (layout, &layout_width, &layout_height); text_height = (gdouble) layout_height / PANGO_SCALE; text_width = (gdouble) layout_width / PANGO_SCALE; if (fname_text_width + text_width < 0.8 * cr_width && text_height < 0.5 * HEADER_HEIGHT) { cairo_move_to (cr, 0.98 * cr_width - text_width, 4 * (HEADER_HEIGHT - text_height) / 5); pango_cairo_show_layout (cr, layout); } gimp_parasite_free (parasite); } g_object_unref (layout); cairo_restore (cr); }
/** * jpeg_detect_original_settings: * @cinfo: a pointer to a JPEG decompressor info. * @image_ID: the image to which the parasite should be attached. * * Analyze the image being decompressed (@cinfo) and extract the * sampling factors, quantization tables and overall image quality. * Store this information in a parasite and attach it to @image_ID. * * This function must be called after jpeg_read_header() so that * @cinfo contains the quantization tables and the sampling factors * for each component. * * Return Value: TRUE if a parasite has been attached to @image_ID. */ gboolean jpeg_detect_original_settings (struct jpeg_decompress_struct *cinfo, gint32 image_ID) { guint parasite_size; guchar *parasite_data; GimpParasite *parasite; guchar *dest; gint quality; gint num_quant_tables = 0; gint t; gint i; g_return_val_if_fail (cinfo != NULL, FALSE); if (cinfo->jpeg_color_space == JCS_UNKNOWN || cinfo->out_color_space == JCS_UNKNOWN) return FALSE; quality = jpeg_detect_quality (cinfo); /* no need to attach quantization tables if they are the ones from IJG */ if (quality <= 0) { for (t = 0; t < 4; t++) if (cinfo->quant_tbl_ptrs[t]) num_quant_tables++; } parasite_size = 4 + cinfo->num_components * 2 + num_quant_tables * 128; parasite_data = g_new (guchar, parasite_size); dest = parasite_data; *dest++ = CLAMP0255 (cinfo->jpeg_color_space); *dest++ = ABS (quality); *dest++ = CLAMP0255 (cinfo->num_components); *dest++ = num_quant_tables; for (i = 0; i < cinfo->num_components; i++) { *dest++ = CLAMP0255 (cinfo->comp_info[i].h_samp_factor); *dest++ = CLAMP0255 (cinfo->comp_info[i].v_samp_factor); } if (quality <= 0) { for (t = 0; t < 4; t++) if (cinfo->quant_tbl_ptrs[t]) for (i = 0; i < DCTSIZE2; i++) { guint16 c = cinfo->quant_tbl_ptrs[t]->quantval[i]; *dest++ = c / 256; *dest++ = c & 255; } } parasite = gimp_parasite_new ("jpeg-settings", GIMP_PARASITE_PERSISTENT, parasite_size, parasite_data); g_free (parasite_data); gimp_image_parasite_attach (image_ID, parasite); gimp_parasite_free (parasite); return TRUE; }
/** * jpeg_restore_original_settings: * @image_ID: the image that may contain original jpeg settings in a parasite. * @quality: where to store the original jpeg quality. * @subsmp: where to store the original subsampling type. * @num_quant_tables: where to store the number of quantization tables found. * * Retrieve the original JPEG settings (quality, type of subsampling * and number of quantization tables) from the parasite attached to * @image_ID. If the number of quantization tables is greater than * zero, then these tables can be retrieved from the parasite by * calling jpeg_restore_original_tables(). * * Return Value: TRUE if a valid parasite was attached to the image */ gboolean jpeg_restore_original_settings (gint32 image_ID, gint *quality, gint *subsmp, gint *num_quant_tables) { GimpParasite *parasite; const guchar *src; glong src_size; gint color_space; gint q; gint num_components; gint num_tables; guchar h[3]; guchar v[3]; g_return_val_if_fail (quality != NULL, FALSE); g_return_val_if_fail (subsmp != NULL, FALSE); g_return_val_if_fail (num_quant_tables != NULL, FALSE); parasite = gimp_image_parasite_find (image_ID, "jpeg-settings"); if (parasite) { src = gimp_parasite_data (parasite); src_size = gimp_parasite_data_size (parasite); if (src_size >= 4) { color_space = *src++; q = *src++; num_components = *src++; num_tables = *src++; if (src_size >= (4 + num_components * 2 + num_tables * 128) && q <= 100 && num_tables <= 4) { *quality = q; /* the current plug-in can only create grayscale or YCbCr JPEGs */ if (color_space == JCS_GRAYSCALE || color_space == JCS_YCbCr) *num_quant_tables = num_tables; else *num_quant_tables = -1; /* the current plug-in can only use subsampling for YCbCr (3) */ *subsmp = -1; if (num_components == 3) { h[0] = *src++; v[0] = *src++; h[1] = *src++; v[1] = *src++; h[2] = *src++; v[2] = *src++; if (h[1] == 1 && v[1] == 1 && h[2] == 1 && v[2] == 1) { if (h[0] == 1 && v[0] == 1) *subsmp = 2; else if (h[0] == 2 && v[0] == 1) *subsmp = 1; else if (h[0] == 1 && v[0] == 2) *subsmp = 3; else if (h[0] == 2 && v[0] == 2) *subsmp = 0; } } gimp_parasite_free (parasite); return TRUE; } } gimp_parasite_free (parasite); } *quality = -1; *subsmp = -1; *num_quant_tables = 0; return FALSE; }
static void gimp_item_prop_undo_pop (GimpUndo *undo, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { GimpItemPropUndo *item_prop_undo = GIMP_ITEM_PROP_UNDO (undo); GimpItem *item = GIMP_ITEM_UNDO (undo)->item; GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); switch (undo->undo_type) { case GIMP_UNDO_ITEM_REORDER: { GimpItem *parent; gint position; parent = gimp_item_get_parent (item); position = gimp_item_get_index (item); gimp_item_tree_reorder_item (gimp_item_get_tree (item), item, item_prop_undo->parent, item_prop_undo->position, FALSE, NULL); item_prop_undo->parent = parent; item_prop_undo->position = position; } break; case GIMP_UNDO_ITEM_RENAME: { gchar *name; name = g_strdup (gimp_object_get_name (item)); gimp_item_tree_rename_item (gimp_item_get_tree (item), item, item_prop_undo->name, FALSE, NULL); g_free (item_prop_undo->name); item_prop_undo->name = name; } break; case GIMP_UNDO_ITEM_DISPLACE: { gint offset_x; gint offset_y; gimp_item_get_offset (item, &offset_x, &offset_y); gimp_item_translate (item, item_prop_undo->offset_x - offset_x, item_prop_undo->offset_y - offset_y, FALSE); item_prop_undo->offset_x = offset_x; item_prop_undo->offset_y = offset_y; } break; case GIMP_UNDO_ITEM_VISIBILITY: { gboolean visible; visible = gimp_item_get_visible (item); gimp_item_set_visible (item, item_prop_undo->visible, FALSE); item_prop_undo->visible = visible; } break; case GIMP_UNDO_ITEM_LINKED: { gboolean linked; linked = gimp_item_get_linked (item); gimp_item_set_linked (item, item_prop_undo->linked, FALSE); item_prop_undo->linked = linked; } break; case GIMP_UNDO_ITEM_COLOR_TAG: { GimpColorTag color_tag; color_tag = gimp_item_get_color_tag (item); gimp_item_set_color_tag (item, item_prop_undo->color_tag, FALSE); item_prop_undo->color_tag = color_tag; } break; case GIMP_UNDO_ITEM_LOCK_CONTENT: { gboolean lock_content; lock_content = gimp_item_get_lock_content (item); gimp_item_set_lock_content (item, item_prop_undo->lock_content, FALSE); item_prop_undo->lock_content = lock_content; } break; case GIMP_UNDO_ITEM_LOCK_POSITION: { gboolean lock_position; lock_position = gimp_item_get_lock_position (item); gimp_item_set_lock_position (item, item_prop_undo->lock_position, FALSE); item_prop_undo->lock_position = lock_position; } break; case GIMP_UNDO_PARASITE_ATTACH: case GIMP_UNDO_PARASITE_REMOVE: { GimpParasite *parasite; parasite = item_prop_undo->parasite; item_prop_undo->parasite = gimp_parasite_copy (gimp_item_parasite_find (item, item_prop_undo->parasite_name)); if (parasite) gimp_item_parasite_attach (item, parasite, FALSE); else gimp_item_parasite_detach (item, item_prop_undo->parasite_name, FALSE); if (parasite) gimp_parasite_free (parasite); } break; default: g_assert_not_reached (); } }
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); }
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; }
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; }
static gboolean lcms_image_set_profile (gint32 image, cmsHPROFILE profile, const gchar *filename, gboolean undo_group) { g_return_val_if_fail (image != -1, FALSE); if (filename) { GimpParasite *parasite; GMappedFile *file; GError *error = NULL; file = g_mapped_file_new (filename, FALSE, &error); if (! file) { g_message ("%s", error->message); g_error_free (error); return FALSE; } /* check that this file is actually an ICC profile */ if (! profile) { profile = cmsOpenProfileFromMem (g_mapped_file_get_contents (file), g_mapped_file_get_length (file)); if (profile) { cmsCloseProfile (profile); } else { g_message (_("'%s' does not appear to be an ICC color profile"), gimp_filename_to_utf8 (filename)); return FALSE; } } if (undo_group) gimp_image_undo_group_start (image); parasite = gimp_parasite_new ("icc-profile", GIMP_PARASITE_PERSISTENT | GIMP_PARASITE_UNDOABLE, g_mapped_file_get_length (file), g_mapped_file_get_contents (file)); g_mapped_file_unref (file); gimp_image_attach_parasite (image, parasite); gimp_parasite_free (parasite); } else { if (undo_group) gimp_image_undo_group_start (image); gimp_image_detach_parasite (image, "icc-profile"); } gimp_image_detach_parasite (image, "icc-profile-name"); if (undo_group) gimp_image_undo_group_end (image); return TRUE; }
GPParam * plug_in_args_to_params (GimpValueArray *args, gboolean full_copy) { GPParam *params; gint length; gint i; g_return_val_if_fail (args != NULL, NULL); params = g_new0 (GPParam, gimp_value_array_length (args)); length = gimp_value_array_length (args); for (i = 0; i < length; i++) { GValue *value = gimp_value_array_index (args, i); params[i].type = gimp_pdb_compat_arg_type_from_gtype (G_VALUE_TYPE (value)); switch (params[i].type) { case GIMP_PDB_INT32: if (G_VALUE_HOLDS_INT (value)) params[i].data.d_int32 = g_value_get_int (value); else if (G_VALUE_HOLDS_UINT (value)) params[i].data.d_int32 = g_value_get_uint (value); else if (G_VALUE_HOLDS_ENUM (value)) params[i].data.d_int32 = g_value_get_enum (value); else if (G_VALUE_HOLDS_BOOLEAN (value)) params[i].data.d_int32 = g_value_get_boolean (value); else { g_printerr ("%s: unhandled GIMP_PDB_INT32 type: %s\n", G_STRFUNC, g_type_name (G_VALUE_TYPE (value))); g_return_val_if_reached (params); } break; case GIMP_PDB_INT16: params[i].data.d_int16 = g_value_get_int (value); break; case GIMP_PDB_INT8: params[i].data.d_int8 = g_value_get_uint (value); break; case GIMP_PDB_FLOAT: params[i].data.d_float = g_value_get_double (value); break; case GIMP_PDB_STRING: if (full_copy) params[i].data.d_string = g_value_dup_string (value); else params[i].data.d_string = (gchar *) g_value_get_string (value); break; case GIMP_PDB_INT32ARRAY: if (full_copy) params[i].data.d_int32array = gimp_value_dup_int32array (value); else params[i].data.d_int32array = (gint32 *) gimp_value_get_int32array (value); break; case GIMP_PDB_INT16ARRAY: if (full_copy) params[i].data.d_int16array = gimp_value_dup_int16array (value); else params[i].data.d_int16array = (gint16 *) gimp_value_get_int16array (value); break; case GIMP_PDB_INT8ARRAY: if (full_copy) params[i].data.d_int8array = gimp_value_dup_int8array (value); else params[i].data.d_int8array = (guint8 *) gimp_value_get_int8array (value); break; case GIMP_PDB_FLOATARRAY: if (full_copy) params[i].data.d_floatarray = gimp_value_dup_floatarray (value); else params[i].data.d_floatarray = (gdouble *) gimp_value_get_floatarray (value); break; case GIMP_PDB_STRINGARRAY: if (full_copy) params[i].data.d_stringarray = gimp_value_dup_stringarray (value); else params[i].data.d_stringarray = (gchar **) gimp_value_get_stringarray (value); break; case GIMP_PDB_COLOR: gimp_value_get_rgb (value, ¶ms[i].data.d_color); break; case GIMP_PDB_ITEM: params[i].data.d_item = g_value_get_int (value); break; case GIMP_PDB_DISPLAY: params[i].data.d_display = g_value_get_int (value); break; case GIMP_PDB_IMAGE: params[i].data.d_image = g_value_get_int (value); break; case GIMP_PDB_LAYER: params[i].data.d_layer = g_value_get_int (value); break; case GIMP_PDB_CHANNEL: params[i].data.d_channel = g_value_get_int (value); break; case GIMP_PDB_DRAWABLE: params[i].data.d_drawable = g_value_get_int (value); break; case GIMP_PDB_SELECTION: params[i].data.d_selection = g_value_get_int (value); break; case GIMP_PDB_COLORARRAY: if (full_copy) params[i].data.d_colorarray = gimp_value_dup_colorarray (value); else params[i].data.d_colorarray = (GimpRGB *) gimp_value_get_colorarray (value); break; case GIMP_PDB_VECTORS: params[i].data.d_vectors = g_value_get_int (value); break; case GIMP_PDB_PARASITE: { GimpParasite *parasite = (full_copy ? g_value_dup_boxed (value) : g_value_get_boxed (value)); if (parasite) { params[i].data.d_parasite.name = parasite->name; params[i].data.d_parasite.flags = parasite->flags; params[i].data.d_parasite.size = parasite->size; params[i].data.d_parasite.data = parasite->data; if (full_copy) { parasite->name = NULL; parasite->flags = 0; parasite->size = 0; parasite->data = NULL; gimp_parasite_free (parasite); } } else { params[i].data.d_parasite.name = NULL; params[i].data.d_parasite.flags = 0; params[i].data.d_parasite.size = 0; params[i].data.d_parasite.data = NULL; } } break; case GIMP_PDB_STATUS: params[i].data.d_status = g_value_get_enum (value); break; case GIMP_PDB_END: break; } } return params; }
static gboolean jpeg_exif_rotate_query_dialog (gint32 image_ID) { GtkWidget *dialog; GtkWidget *hbox; GtkWidget *vbox; GtkWidget *label; GtkWidget *toggle; GdkPixbuf *pixbuf; gint response; dialog = gimp_dialog_new (_("Rotate Image?"), PLUG_IN_BINARY, NULL, 0, NULL, NULL, _("_Keep Orientation"), GTK_RESPONSE_CANCEL, GIMP_STOCK_TOOL_ROTATE, GTK_RESPONSE_OK, NULL); gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); gimp_window_set_transient (GTK_WINDOW (dialog)); hbox = gtk_hbox_new (FALSE, 12); gtk_container_set_border_width (GTK_CONTAINER (hbox), 12); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); vbox = gtk_vbox_new (FALSE, 6); gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); gtk_widget_show (vbox); pixbuf = gimp_image_get_thumbnail (image_ID, THUMBNAIL_SIZE, THUMBNAIL_SIZE, GIMP_PIXBUF_SMALL_CHECKS); if (pixbuf) { GtkWidget *image; gchar *name; image = gtk_image_new_from_pixbuf (pixbuf); g_object_unref (pixbuf); gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0); gtk_widget_show (image); name = gimp_image_get_name (image_ID); label = gtk_label_new (name); gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE); gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC, -1); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_widget_show (label); g_free (name); } vbox = gtk_vbox_new (FALSE, 12); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); gtk_widget_show (vbox); label = g_object_new (GTK_TYPE_LABEL, "label", _("According to the EXIF data, " "this image is rotated."), "wrap", TRUE, "justify", GTK_JUSTIFY_LEFT, "xalign", 0.0, "yalign", 0.5, NULL); gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_LARGE, PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, -1); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_widget_show (label); label = g_object_new (GTK_TYPE_LABEL, "label", _("Would you like GIMP to rotate it " "into the standard orientation?"), "wrap", TRUE, "justify", GTK_JUSTIFY_LEFT, "xalign", 0.0, "yalign", 0.5, NULL); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_widget_show (label); toggle = gtk_check_button_new_with_mnemonic (_("_Don't ask me again")); gtk_box_pack_end (GTK_BOX (vbox), toggle, FALSE, FALSE, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), FALSE); gtk_widget_show (toggle); response = gimp_dialog_run (GIMP_DIALOG (dialog)); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle))) { GimpParasite *parasite; const gchar *str = (response == GTK_RESPONSE_OK) ? "yes" : "no"; parasite = gimp_parasite_new (JPEG_EXIF_ROTATE_PARASITE, GIMP_PARASITE_PERSISTENT, strlen (str), str); gimp_parasite_attach (parasite); gimp_parasite_free (parasite); } gtk_widget_destroy (dialog); return (response == GTK_RESPONSE_OK); }
static gboolean lcms_image_set_profile (gint32 image, cmsHPROFILE profile, GFile *file) { g_return_val_if_fail (image != -1, FALSE); if (file) { cmsHPROFILE file_profile; GimpParasite *parasite; guint8 *profile_data; gsize profile_length; GError *error = NULL; /* check that this file is actually an ICC profile */ file_profile = gimp_lcms_profile_open_from_file (file, &error); if (! file_profile) { g_message ("%s", error->message); g_clear_error (&error); return FALSE; } profile_data = gimp_lcms_profile_save_to_data (file_profile, &profile_length, &error); cmsCloseProfile (file_profile); if (! profile_data) { g_message ("%s", error->message); g_clear_error (&error); return FALSE; } gimp_image_undo_group_start (image); parasite = gimp_parasite_new ("icc-profile", GIMP_PARASITE_PERSISTENT | GIMP_PARASITE_UNDOABLE, profile_length, profile_data); g_free (profile_data); gimp_image_attach_parasite (image, parasite); gimp_parasite_free (parasite); } else { gimp_image_undo_group_start (image); gimp_image_detach_parasite (image, "icc-profile"); } gimp_image_detach_parasite (image, "icc-profile-name"); gimp_image_undo_group_end (image); return TRUE; }