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); }
GimpSymmetry * gimp_symmetry_from_parasite (const GimpParasite *parasite, GimpImage *image, GType type) { GimpSymmetry *symmetry; gchar *parasite_name; const gchar *str; GError *error = NULL; parasite_name = gimp_symmetry_parasite_name (type); g_return_val_if_fail (parasite != NULL, NULL); g_return_val_if_fail (strcmp (gimp_parasite_name (parasite), parasite_name) == 0, NULL); g_free (parasite_name); str = gimp_parasite_data (parasite); g_return_val_if_fail (str != NULL, NULL); symmetry = gimp_image_symmetry_new (image, type); if (! gimp_config_deserialize_string (GIMP_CONFIG (symmetry), str, gimp_parasite_data_size (parasite), NULL, &error)) { g_warning ("Failed to deserialize symmetry parasite: %s", error->message); g_error_free (error); } return symmetry; }
gboolean gimp_image_validate_icc_parasite (GimpImage *image, const GimpParasite *icc_parasite, gboolean *is_builtin, GError **error) { g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); g_return_val_if_fail (icc_parasite != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (strcmp (gimp_parasite_name (icc_parasite), GIMP_ICC_PROFILE_PARASITE_NAME) != 0) { g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, _("ICC profile validation failed: " "Parasite's name is not 'icc-profile'")); return FALSE; } if (gimp_parasite_flags (icc_parasite) != (GIMP_PARASITE_PERSISTENT | GIMP_PARASITE_UNDOABLE)) { g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, _("ICC profile validation failed: " "Parasite's flags are not (PERSISTENT | UNDOABLE)")); return FALSE; } return gimp_image_validate_icc_profile (image, gimp_parasite_data (icc_parasite), gimp_parasite_data_size (icc_parasite), is_builtin, error); }
GimpGrid * gimp_grid_from_parasite (const GimpParasite *parasite) { GimpGrid *grid; const gchar *str; GError *error = NULL; g_return_val_if_fail (parasite != NULL, NULL); g_return_val_if_fail (strcmp (gimp_parasite_name (parasite), gimp_grid_parasite_name ()) == 0, NULL); str = gimp_parasite_data (parasite); g_return_val_if_fail (str != NULL, NULL); grid = g_object_new (GIMP_TYPE_GRID, NULL); if (! gimp_config_deserialize_string (GIMP_CONFIG (grid), str, gimp_parasite_data_size (parasite), NULL, &error)) { g_warning ("Failed to deserialize grid parasite: %s", error->message); g_error_free (error); } return grid; }
gboolean gimp_image_validate_icc_profile (GimpImage *image, const GimpParasite *icc_profile, GError **error) { GimpColorProfile *profile; g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); g_return_val_if_fail (icc_profile != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (strcmp (gimp_parasite_name (icc_profile), GIMP_ICC_PROFILE_PARASITE_NAME) != 0) { g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, _("ICC profile validation failed: " "Parasite's name is not 'icc-profile'")); return FALSE; } if (gimp_parasite_flags (icc_profile) != (GIMP_PARASITE_PERSISTENT | GIMP_PARASITE_UNDOABLE)) { g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, _("ICC profile validation failed: " "Parasite's flags are not (PERSISTENT | UNDOABLE)")); return FALSE; } if (gimp_image_get_base_type (image) == GIMP_GRAY) { g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, _("ICC profile validation failed: " "Cannot attach a color profile to a GRAY image")); return FALSE; } profile = gimp_lcms_profile_open_from_data (gimp_parasite_data (icc_profile), gimp_parasite_data_size (icc_profile), error); if (! profile) { g_prefix_error (error, _("ICC profile validation failed: ")); return FALSE; } if (! gimp_lcms_profile_is_rgb (profile)) { g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, _("ICC profile validation failed: " "Color profile is not for RGB color space")); cmsCloseProfile (profile); return FALSE; } cmsCloseProfile (profile); return TRUE; }
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",
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; }
GimpColorProfile * gimp_image_get_color_profile (GimpImage *image) { const GimpParasite *parasite; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); parasite = gimp_image_get_icc_parasite (image); if (parasite) return gimp_color_profile_new_from_icc_profile (gimp_parasite_data (parasite), gimp_parasite_data_size (parasite), NULL); return NULL; }
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; }
static void parasite_serialize (const gchar *key, GimpParasite *parasite, GimpConfigWriter *writer) { if (! gimp_parasite_is_persistent (parasite)) return; gimp_config_writer_open (writer, parasite_symbol); gimp_config_writer_printf (writer, "\"%s\" %lu %lu", gimp_parasite_name (parasite), gimp_parasite_flags (parasite), gimp_parasite_data_size (parasite)); gimp_config_writer_data (writer, gimp_parasite_data_size (parasite), gimp_parasite_data (parasite)); gimp_config_writer_close (writer); gimp_config_writer_linefeed (writer); }
const guint8 * gimp_image_get_icc_profile (GimpImage *image, gsize *length) { const GimpParasite *parasite; g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); parasite = gimp_image_parasite_find (image, GIMP_ICC_PROFILE_PARASITE_NAME); if (parasite) { if (length) *length = gimp_parasite_data_size (parasite); return gimp_parasite_data (parasite); } if (length) *length = 0; return NULL; }
GimpColorProfile gimp_image_get_profile (GimpImage *image, GError **error) { GimpColorConfig *config; const GimpParasite *parasite; GimpColorProfile *profile = NULL; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); config = image->gimp->config->color_management; parasite = gimp_image_get_icc_profile (image); if (parasite) { return gimp_lcms_profile_open_from_data (gimp_parasite_data (parasite), gimp_parasite_data_size (parasite), error); } else if (config->rgb_profile) { profile = gimp_lcms_profile_open_from_file (config->rgb_profile, error); if (profile && ! gimp_lcms_profile_is_rgb (profile)) { g_set_error (error, GIMP_ERROR, GIMP_FAILED, _("Color profile '%s' is not for RGB color space"), gimp_filename_to_utf8 (config->rgb_profile)); cmsCloseProfile (profile); profile = NULL; } } return profile; }
void load_defaults (void) { GimpParasite *parasite; gchar *def_str; JpegSaveVals tmpvals; gint num_fields; gint subsampling; jsvals.quality = DEFAULT_QUALITY; jsvals.smoothing = DEFAULT_SMOOTHING; jsvals.optimize = DEFAULT_OPTIMIZE; jsvals.arithmetic_coding= DEFAULT_ARITHMETIC_CODING; jsvals.progressive = DEFAULT_PROGRESSIVE; jsvals.baseline = DEFAULT_BASELINE; jsvals.subsmp = DEFAULT_SUBSMP; jsvals.restart = DEFAULT_RESTART; jsvals.dct = DEFAULT_DCT; jsvals.preview = DEFAULT_PREVIEW; jsvals.save_exif = DEFAULT_EXIF; jsvals.save_thumbnail = DEFAULT_THUMBNAIL; jsvals.save_xmp = DEFAULT_XMP; jsvals.save_iptc = DEFAULT_IPTC; jsvals.use_orig_quality = DEFAULT_USE_ORIG_QUALITY; parasite = gimp_get_parasite (JPEG_DEFAULTS_PARASITE); if (! parasite) return; def_str = g_strndup (gimp_parasite_data (parasite), gimp_parasite_data_size (parasite)); gimp_parasite_free (parasite); num_fields = sscanf (def_str, "%lf %lf %d %d %d %d %d %d %d %d %d %d %d %d %d", &tmpvals.quality, &tmpvals.smoothing, &tmpvals.optimize, &tmpvals.progressive, &subsampling, &tmpvals.baseline, &tmpvals.restart, &tmpvals.dct, &tmpvals.preview, &tmpvals.save_exif, &tmpvals.save_thumbnail, &tmpvals.save_xmp, &tmpvals.use_orig_quality, &tmpvals.save_iptc, &tmpvals.arithmetic_coding); tmpvals.subsmp = subsampling; if (num_fields == 13 || num_fields == 14) { memcpy (&jsvals, &tmpvals, sizeof (tmpvals)); } g_free (def_str); }
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_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 run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[4]; gint32 image_ID; XMPModel *xmp_model; GimpPDBStatusType status = GIMP_PDB_SUCCESS; GimpParasite *parasite = NULL; *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; INIT_I18N(); if (! strcmp (name, EDITOR_PROC)) image_ID = param[1].data.d_image; else image_ID = param[0].data.d_image; xmp_model = xmp_model_new (); /* if there is already a metadata parasite, load it */ parasite = gimp_image_get_parasite (image_ID, METADATA_PARASITE); if (parasite) { GError *error = NULL; if (!! strncmp (gimp_parasite_data (parasite), METADATA_MARKER, METADATA_MARKER_LEN) || ! xmp_model_parse_buffer (xmp_model, (const gchar *) gimp_parasite_data (parasite) + METADATA_MARKER_LEN, gimp_parasite_data_size (parasite) - METADATA_MARKER_LEN, TRUE, &error)) { g_printerr ("\nMetadata parasite seems to be corrupt\n"); /* continue anyway, we will attach a clean parasite later */ } gimp_parasite_free (parasite); } /* If we have no metadata yet, try to find an XMP packet in the file * (but ignore errors if nothing is found). * * FIXME: This is a workaround until all file plug-ins do the right * thing when loading their files. */ if (xmp_model_is_empty (xmp_model) && !! strcmp (name, DECODE_XMP_PROC)) { const gchar *filename; GError *error = NULL; filename = gimp_image_get_filename (image_ID); if (filename != NULL) if (xmp_model_parse_file (xmp_model, filename, &error)) /* g_message ("XMP loaded from file '%s'\n", filename) */; } /* Now check what we are supposed to do */ if (! strcmp (name, DECODE_XMP_PROC)) { const gchar *buffer; GError *error = NULL; buffer = param[1].data.d_string; if (! xmp_model_parse_buffer (xmp_model, buffer, strlen (buffer), FALSE, &error)) status = GIMP_PDB_EXECUTION_ERROR; } else if (! strcmp (name, ENCODE_XMP_PROC)) { /* done below together with the parasite */ } else if (! strcmp (name, DECODE_EXIF_PROC)) { GError *error = NULL; if (! xmp_merge_from_exifbuffer (xmp_model, image_ID, &error)) { status = GIMP_PDB_EXECUTION_ERROR; g_printerr ("\nExif to XMP merge failed.\n"); } } else if (! strcmp (name, GET_PROC)) { g_printerr ("Not implemented yet (GET_PROC)\n"); /* FIXME */ status = GIMP_PDB_EXECUTION_ERROR; } else if (! strcmp (name, SET_PROC)) { g_printerr ("Not implemented yet (SET_PROC)\n"); /* FIXME */ status = GIMP_PDB_EXECUTION_ERROR; } else if (! strcmp (name, GET_SIMPLE_PROC)) { const gchar *schema_name; const gchar *property_name; const gchar *value; schema_name = param[1].data.d_string; property_name = param[2].data.d_string; value = xmp_model_get_scalar_property (xmp_model, schema_name, property_name); if (value) { *nreturn_vals = 2; values[1].type = GIMP_PDB_STRING; values[1].data.d_string = g_strdup (value); } else status = GIMP_PDB_EXECUTION_ERROR; } else if (! strcmp (name, SET_SIMPLE_PROC)) { const gchar *schema_name; const gchar *property_name; const gchar *property_value; schema_name = param[1].data.d_string; property_name = param[2].data.d_string; property_value = param[3].data.d_string; if (! xmp_model_set_scalar_property (xmp_model, schema_name, property_name, property_value)) status = GIMP_PDB_EXECUTION_ERROR; } else if (! strcmp (name, IMPORT_PROC)) { const gchar *filename; gchar *buffer; gsize buffer_length; GError *error = NULL; filename = param[1].data.d_string; if (! g_file_get_contents (filename, &buffer, &buffer_length, &error)) { g_error_free (error); status = GIMP_PDB_EXECUTION_ERROR; } else if (! xmp_model_parse_buffer (xmp_model, buffer, buffer_length, TRUE, &error)) { g_error_free (error); status = GIMP_PDB_EXECUTION_ERROR; } g_free (buffer); } else if (! strcmp (name, EXPORT_PROC)) { /* FIXME: this is easy to implement, but the first thing to do is */ /* to improve the code of export_dialog_response() in interface.c */ g_printerr ("Not implemented yet (EXPORT_PROC)\n"); status = GIMP_PDB_EXECUTION_ERROR; } else if (! strcmp (name, EDITOR_PROC)) { GimpRunMode run_mode; run_mode = param[0].data.d_int32; if (run_mode == GIMP_RUN_INTERACTIVE) { if (! metadata_dialog (image_ID, xmp_model)) status = GIMP_PDB_CANCEL; } g_printerr ("Not implemented yet (EDITOR_PROC)\n"); status = GIMP_PDB_EXECUTION_ERROR; } else { status = GIMP_PDB_CALLING_ERROR; } if (status == GIMP_PDB_SUCCESS) { GString *buffer; /* Generate the updated parasite and attach it to the image */ buffer = g_string_new (METADATA_MARKER); xmp_generate_packet (xmp_model, buffer); parasite = gimp_parasite_new (METADATA_PARASITE, GIMP_PARASITE_PERSISTENT, buffer->len, (gpointer) buffer->str); gimp_image_attach_parasite (image_ID, parasite); if (! strcmp (name, ENCODE_XMP_PROC)) { *nreturn_vals = 2; values[1].type = GIMP_PDB_STRING; values[1].data.d_string = g_strdup (buffer->str + METADATA_MARKER_LEN); } g_string_free (buffer, TRUE); } g_object_unref (xmp_model); values[0].data.d_status = status; }
GimpSymmetry * gimp_symmetry_from_parasite (const GimpParasite *parasite, GimpImage *image, GType type) { GimpSymmetry *symmetry; gchar *parasite_name; const gchar *str; GError *error = NULL; parasite_name = gimp_symmetry_parasite_name (type); g_return_val_if_fail (parasite != NULL, NULL); g_return_val_if_fail (strcmp (gimp_parasite_name (parasite), parasite_name) == 0, NULL); str = gimp_parasite_data (parasite); if (! str) { g_warning ("Empty symmetry parasite \"%s\"", parasite_name); return NULL; } symmetry = gimp_image_symmetry_new (image, type); g_object_set (symmetry, "version", -1, NULL); if (! gimp_config_deserialize_string (GIMP_CONFIG (symmetry), str, gimp_parasite_data_size (parasite), NULL, &error)) { g_printerr ("Failed to deserialize symmetry parasite: %s\n" "\t- parasite name: %s\n\t- parasite data: %s\n", error->message, parasite_name, str); g_error_free (error); g_object_unref (symmetry); symmetry = NULL; } g_free (parasite_name); if (symmetry) { gint version; g_object_get (symmetry, "version", &version, NULL); if (version == -1) { /* If version has not been updated, let's assume this parasite was * not representing symmetry settings. */ g_object_unref (symmetry); symmetry = NULL; } else if (GIMP_SYMMETRY_GET_CLASS (symmetry)->update_version (symmetry) && ! GIMP_SYMMETRY_GET_CLASS (symmetry)->update_version (symmetry)) { g_object_unref (symmetry); symmetry = NULL; } } return symmetry; }
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 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; gint32 image_ID; gint32 drawable_ID; GimpExportReturn export = GIMP_EXPORT_CANCEL; GError *error = NULL; INIT_I18N (); gegl_init (NULL, NULL); run_mode = param[0].data.d_int32; *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; if (strcmp (name, LOAD_PROC) == 0) { image_ID = load_image (g_file_new_for_uri (param[1].data.d_string), &error); if (image_ID != -1) { *nreturn_vals = 2; values[1].type = GIMP_PDB_IMAGE; values[1].data.d_image = image_ID; } else { status = GIMP_PDB_EXECUTION_ERROR; } } else if (strcmp (name, SAVE_PROC) == 0) { GFile *file; GimpParasite *parasite; gint32 orig_image_ID; image_ID = param[1].data.d_int32; drawable_ID = param[2].data.d_int32; file = g_file_new_for_uri (param[3].data.d_string); orig_image_ID = image_ID; switch (run_mode) { case GIMP_RUN_INTERACTIVE: case GIMP_RUN_WITH_LAST_VALS: gimp_ui_init (PLUG_IN_BINARY, FALSE); export = gimp_export_image (&image_ID, &drawable_ID, "PAT", GIMP_EXPORT_CAN_HANDLE_GRAY | GIMP_EXPORT_CAN_HANDLE_RGB | GIMP_EXPORT_CAN_HANDLE_INDEXED | GIMP_EXPORT_CAN_HANDLE_ALPHA); if (export == GIMP_EXPORT_CANCEL) { values[0].data.d_status = GIMP_PDB_CANCEL; return; } /* Possibly retrieve data */ gimp_get_data (SAVE_PROC, description); parasite = gimp_image_get_parasite (orig_image_ID, "gimp-pattern-name"); if (parasite) { strncpy (description, gimp_parasite_data (parasite), MIN (sizeof (description), gimp_parasite_data_size (parasite))); description[sizeof (description) - 1] = '\0'; gimp_parasite_free (parasite); } else { gchar *name = g_path_get_basename (gimp_file_get_utf8_name (file)); if (g_str_has_suffix (name, ".pat")) name[strlen (name) - 4] = '\0'; if (strlen (name)) { strncpy (description, name, sizeof (description)); description[sizeof (description) - 1] = '\0'; } g_free (name); } break; default: break; }