Update upstream
This commit is contained in:
@ -352,7 +352,8 @@ static struct
|
||||
gint delayTime;
|
||||
gint inputFlag;
|
||||
gint disposal;
|
||||
} Gif89 = { -1, -1, -1, 0 };
|
||||
gint num_loops;
|
||||
} Gif89 = { -1, -1, -1, 0, -1 };
|
||||
|
||||
static void read_error (const gchar *error_type,
|
||||
PikaImage *image,
|
||||
@ -399,9 +400,10 @@ load_image (GFile *file,
|
||||
gint grayScale;
|
||||
gboolean useGlobalColormap;
|
||||
gint bitPixel;
|
||||
gint imageCount = 0;
|
||||
PikaImage *image = NULL;
|
||||
gint imageCount = 0;
|
||||
PikaImage *image = NULL;
|
||||
gboolean status;
|
||||
gboolean saved_parasite = FALSE;
|
||||
|
||||
pika_progress_init_printf (_("Opening '%s'"),
|
||||
pika_file_get_utf8_name (file));
|
||||
@ -590,6 +592,25 @@ load_image (GFile *file,
|
||||
/* If we are loading a thumbnail, we stop after the first frame. */
|
||||
if (thumbnail)
|
||||
break;
|
||||
|
||||
/* If there is more than one frame, we add a parasite so that
|
||||
* we know to export as an animation on overwrite */
|
||||
if (Gif89.num_loops > -1 && ! saved_parasite)
|
||||
{
|
||||
PikaParasite *parasite;
|
||||
gchar *str;
|
||||
|
||||
str = g_strdup_printf ("%d", Gif89.num_loops);
|
||||
parasite = pika_parasite_new ("gif/animated",
|
||||
PIKA_PARASITE_PERSISTENT,
|
||||
strlen (str) + 1,
|
||||
(gpointer) str);
|
||||
g_free (str);
|
||||
|
||||
pika_image_attach_parasite (image, parasite);
|
||||
pika_parasite_free (parasite);
|
||||
saved_parasite = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
fclose (fd);
|
||||
@ -690,6 +711,15 @@ DoExtension (FILE *fd,
|
||||
#ifdef GIFDEBUG
|
||||
str = "Application Extension";
|
||||
#endif
|
||||
/* Animation block */
|
||||
if (GetDataBlock (fd, (guchar *) buf))
|
||||
{
|
||||
if (strncmp ((const gchar *) buf, "NETSCAPE2.0", 8) == 0)
|
||||
{
|
||||
if (GetDataBlock (fd, (guchar *) buf))
|
||||
Gif89.num_loops = (buf[0] << 8) | buf[1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xfe: /* Comment Extension */
|
||||
#ifdef GIFDEBUG
|
||||
|
@ -268,6 +268,7 @@ gif_save (PikaProcedure *procedure,
|
||||
PikaExportReturn export = PIKA_EXPORT_CANCEL;
|
||||
PikaImage *orig_image;
|
||||
PikaImage *sanitized_image = NULL;
|
||||
PikaParasite *parasite = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
gegl_init (NULL, NULL);
|
||||
@ -288,6 +289,34 @@ gif_save (PikaProcedure *procedure,
|
||||
*/
|
||||
sanitized_image = image;
|
||||
|
||||
/* If imported as an animation, set the animation configurations
|
||||
* when overwriting the file */
|
||||
parasite = pika_image_get_parasite (image, "gif/animated");
|
||||
if (parasite)
|
||||
{
|
||||
gint num_loops;
|
||||
gchar *parasite_data;
|
||||
guint32 parasite_size;
|
||||
|
||||
parasite_data = (gchar *) pika_parasite_get_data (parasite, ¶site_size);
|
||||
parasite_data = g_strndup (parasite_data, parasite_size);
|
||||
|
||||
if (sscanf (parasite_data, "%i", &num_loops) == 1)
|
||||
{
|
||||
gboolean loop = (num_loops == 0);
|
||||
|
||||
g_object_set (config,
|
||||
"as-animation", TRUE,
|
||||
"loop", loop,
|
||||
"number-of-repeats", num_loops,
|
||||
NULL);
|
||||
}
|
||||
|
||||
pika_image_detach_parasite (image, "gif/animated");
|
||||
g_free (parasite);
|
||||
g_free (parasite_data);
|
||||
}
|
||||
|
||||
if (run_mode == PIKA_RUN_INTERACTIVE)
|
||||
{
|
||||
if (! save_dialog (image, procedure, G_OBJECT (config)))
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#define LOAD_PROC "file-heif-load"
|
||||
#define LOAD_PROC_AV1 "file-heif-av1-load"
|
||||
#define LOAD_PROC_HEJ2 "file-heif-hej2-load"
|
||||
#define SAVE_PROC "file-heif-save"
|
||||
#define SAVE_PROC_AV1 "file-heif-av1-save"
|
||||
#define PLUG_IN_BINARY "file-heif"
|
||||
@ -103,6 +104,8 @@ static PikaValueArray * heif_av1_save (PikaProcedure *pro
|
||||
#endif
|
||||
|
||||
static PikaImage * load_image (GFile *file,
|
||||
PikaMetadata *metadata,
|
||||
PikaMetadataLoadFlags *flags,
|
||||
gboolean interactive,
|
||||
PikaPDBStatusType *status,
|
||||
GError **error);
|
||||
@ -172,6 +175,13 @@ heif_init_procedures (PikaPlugIn *plug_in)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LIBHEIF_HAVE_VERSION(1,17,0)
|
||||
if (heif_have_decoder_for_format (heif_compression_JPEG2000))
|
||||
{
|
||||
list = g_list_append (list, g_strdup (LOAD_PROC_HEJ2));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LIBHEIF_HAVE_VERSION(1,13,0)
|
||||
heif_deinit ();
|
||||
#endif
|
||||
@ -412,6 +422,33 @@ heif_create_procedure (PikaPlugIn *plug_in,
|
||||
pika_export_xmp (),
|
||||
G_PARAM_READWRITE);
|
||||
}
|
||||
#endif
|
||||
#if LIBHEIF_HAVE_VERSION(1,17,0)
|
||||
else if (! strcmp (name, LOAD_PROC_HEJ2))
|
||||
{
|
||||
procedure = pika_load_procedure_new (plug_in, name, PIKA_PDB_PROC_TYPE_PLUGIN,
|
||||
heif_load, NULL, NULL);
|
||||
|
||||
pika_procedure_set_menu_label (procedure, _("JPEG 2000 encapsulated in HEIF"));
|
||||
|
||||
pika_procedure_set_documentation (procedure,
|
||||
_("Loads HEJ2 images"),
|
||||
_("Load JPEG 2000 image encapsulated in HEIF (HEJ2)"),
|
||||
name);
|
||||
pika_procedure_set_attribution (procedure,
|
||||
"Daniel Novomesky <dnovomesky@gmail.com>",
|
||||
"Daniel Novomesky <dnovomesky@gmail.com>",
|
||||
"2023");
|
||||
|
||||
pika_file_procedure_set_handles_remote (PIKA_FILE_PROCEDURE (procedure), TRUE);
|
||||
pika_file_procedure_set_mime_types (PIKA_FILE_PROCEDURE (procedure),
|
||||
"image/hej2k");
|
||||
pika_file_procedure_set_extensions (PIKA_FILE_PROCEDURE (procedure),
|
||||
"hej2");
|
||||
|
||||
pika_file_procedure_set_magics (PIKA_FILE_PROCEDURE (procedure),
|
||||
"4,string,ftypj2ki");
|
||||
}
|
||||
#endif
|
||||
return procedure;
|
||||
}
|
||||
@ -442,7 +479,7 @@ heif_load (PikaProcedure *procedure,
|
||||
heif_init (NULL);
|
||||
#endif
|
||||
|
||||
image = load_image (file, interactive, &status, &error);
|
||||
image = load_image (file, metadata, flags, interactive, &status, &error);
|
||||
|
||||
#if LIBHEIF_HAVE_VERSION(1,13,0)
|
||||
heif_deinit ();
|
||||
@ -836,10 +873,12 @@ nclx_to_pika_profile (const struct heif_color_profile_nclx *nclx)
|
||||
#endif
|
||||
|
||||
PikaImage *
|
||||
load_image (GFile *file,
|
||||
gboolean interactive,
|
||||
PikaPDBStatusType *status,
|
||||
GError **error)
|
||||
load_image (GFile *file,
|
||||
PikaMetadata *metadata,
|
||||
PikaMetadataLoadFlags *flags,
|
||||
gboolean interactive,
|
||||
PikaPDBStatusType *status,
|
||||
GError **error)
|
||||
{
|
||||
GInputStream *input;
|
||||
goffset file_size;
|
||||
@ -1267,117 +1306,111 @@ load_image (GFile *file,
|
||||
|
||||
g_object_unref (buffer);
|
||||
|
||||
{
|
||||
size_t exif_data_size = 0;
|
||||
uint8_t *exif_data = NULL;
|
||||
size_t xmp_data_size = 0;
|
||||
uint8_t *xmp_data = NULL;
|
||||
gint n_metadata;
|
||||
heif_item_id metadata_id;
|
||||
if (metadata)
|
||||
{
|
||||
size_t exif_data_size = 0;
|
||||
uint8_t *exif_data = NULL;
|
||||
size_t xmp_data_size = 0;
|
||||
uint8_t *xmp_data = NULL;
|
||||
gint n_metadata;
|
||||
heif_item_id metadata_id;
|
||||
|
||||
n_metadata =
|
||||
heif_image_handle_get_list_of_metadata_block_IDs (handle,
|
||||
"Exif",
|
||||
&metadata_id, 1);
|
||||
if (n_metadata > 0)
|
||||
{
|
||||
exif_data_size = heif_image_handle_get_metadata_size (handle,
|
||||
metadata_id);
|
||||
exif_data = g_alloca (exif_data_size);
|
||||
n_metadata = heif_image_handle_get_list_of_metadata_block_IDs (handle, "Exif",
|
||||
&metadata_id, 1);
|
||||
if (n_metadata > 0)
|
||||
{
|
||||
exif_data_size = heif_image_handle_get_metadata_size (handle, metadata_id);
|
||||
|
||||
err = heif_image_handle_get_metadata (handle, metadata_id, exif_data);
|
||||
if (err.code != 0)
|
||||
{
|
||||
exif_data = NULL;
|
||||
exif_data_size = 0;
|
||||
}
|
||||
}
|
||||
exif_data = g_alloca (exif_data_size);
|
||||
|
||||
n_metadata =
|
||||
heif_image_handle_get_list_of_metadata_block_IDs (handle,
|
||||
"mime",
|
||||
&metadata_id, 1);
|
||||
if (n_metadata > 0)
|
||||
{
|
||||
if (g_strcmp0 (
|
||||
heif_image_handle_get_metadata_content_type (handle, metadata_id),
|
||||
"application/rdf+xml") == 0)
|
||||
{
|
||||
xmp_data_size = heif_image_handle_get_metadata_size (handle,
|
||||
metadata_id);
|
||||
xmp_data = g_alloca (xmp_data_size);
|
||||
err = heif_image_handle_get_metadata (handle, metadata_id, exif_data);
|
||||
if (err.code != 0)
|
||||
{
|
||||
exif_data = NULL;
|
||||
exif_data_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
err = heif_image_handle_get_metadata (handle, metadata_id, xmp_data);
|
||||
if (err.code != 0)
|
||||
{
|
||||
xmp_data = NULL;
|
||||
xmp_data_size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
n_metadata = heif_image_handle_get_list_of_metadata_block_IDs (handle, "mime",
|
||||
&metadata_id, 1);
|
||||
if (n_metadata > 0)
|
||||
{
|
||||
if (g_strcmp0 (heif_image_handle_get_metadata_content_type (handle, metadata_id), "application/rdf+xml")
|
||||
== 0)
|
||||
{
|
||||
xmp_data_size = heif_image_handle_get_metadata_size (handle, metadata_id);
|
||||
|
||||
if (exif_data || xmp_data)
|
||||
{
|
||||
PikaMetadata *metadata = pika_metadata_new ();
|
||||
PikaMetadataLoadFlags flags = PIKA_METADATA_LOAD_COMMENT | PIKA_METADATA_LOAD_RESOLUTION;
|
||||
xmp_data = g_alloca (xmp_data_size);
|
||||
|
||||
if (exif_data)
|
||||
{
|
||||
const guint8 tiffHeaderBE[4] = { 'M', 'M', 0, 42 };
|
||||
const guint8 tiffHeaderLE[4] = { 'I', 'I', 42, 0 };
|
||||
GExiv2Metadata *exif_metadata = GEXIV2_METADATA (metadata);
|
||||
const guint8 *tiffheader = exif_data;
|
||||
glong new_exif_size = exif_data_size;
|
||||
err = heif_image_handle_get_metadata (handle, metadata_id, xmp_data);
|
||||
if (err.code != 0)
|
||||
{
|
||||
xmp_data = NULL;
|
||||
xmp_data_size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (new_exif_size >= 4) /*Searching for TIFF Header*/
|
||||
{
|
||||
if (tiffheader[0] == tiffHeaderBE[0] && tiffheader[1] == tiffHeaderBE[1] &&
|
||||
tiffheader[2] == tiffHeaderBE[2] && tiffheader[3] == tiffHeaderBE[3])
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (tiffheader[0] == tiffHeaderLE[0] && tiffheader[1] == tiffHeaderLE[1] &&
|
||||
tiffheader[2] == tiffHeaderLE[2] && tiffheader[3] == tiffHeaderLE[3])
|
||||
{
|
||||
break;
|
||||
}
|
||||
new_exif_size--;
|
||||
tiffheader++;
|
||||
}
|
||||
if (exif_data || xmp_data)
|
||||
{
|
||||
gexiv2_metadata_clear (GEXIV2_METADATA (metadata));
|
||||
|
||||
if (new_exif_size > 4) /* TIFF header + some data found*/
|
||||
{
|
||||
if (! gexiv2_metadata_open_buf (exif_metadata, tiffheader, new_exif_size, error))
|
||||
{
|
||||
g_printerr ("%s: Failed to set EXIF metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||
g_clear_error (error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr ("%s: EXIF metadata not set\n", G_STRFUNC);
|
||||
}
|
||||
}
|
||||
if (exif_data)
|
||||
{
|
||||
const guint8 tiffHeaderBE[4] = { 'M', 'M', 0, 42 };
|
||||
const guint8 tiffHeaderLE[4] = { 'I', 'I', 42, 0 };
|
||||
GExiv2Metadata *exif_metadata = GEXIV2_METADATA (metadata);
|
||||
const guint8 *tiffheader = exif_data;
|
||||
glong new_exif_size = exif_data_size;
|
||||
|
||||
if (xmp_data)
|
||||
{
|
||||
if (!pika_metadata_set_from_xmp (metadata, xmp_data, xmp_data_size, error))
|
||||
{
|
||||
g_printerr ("%s: Failed to set XMP metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||
g_clear_error (error);
|
||||
}
|
||||
}
|
||||
while (new_exif_size >= 4) /*Searching for TIFF Header*/
|
||||
{
|
||||
if (tiffheader[0] == tiffHeaderBE[0] && tiffheader[1] == tiffHeaderBE[1] &&
|
||||
tiffheader[2] == tiffHeaderBE[2] && tiffheader[3] == tiffHeaderBE[3])
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (tiffheader[0] == tiffHeaderLE[0] && tiffheader[1] == tiffHeaderLE[1] &&
|
||||
tiffheader[2] == tiffHeaderLE[2] && tiffheader[3] == tiffHeaderLE[3])
|
||||
{
|
||||
break;
|
||||
}
|
||||
new_exif_size--;
|
||||
tiffheader++;
|
||||
}
|
||||
|
||||
gexiv2_metadata_try_set_orientation (GEXIV2_METADATA (metadata),
|
||||
GEXIV2_ORIENTATION_NORMAL, NULL);
|
||||
gexiv2_metadata_try_set_metadata_pixel_width (GEXIV2_METADATA (metadata),
|
||||
width, NULL);
|
||||
gexiv2_metadata_try_set_metadata_pixel_height (GEXIV2_METADATA (metadata),
|
||||
height, NULL);
|
||||
pika_image_metadata_load_finish (image, "image/heif",
|
||||
metadata, flags);
|
||||
}
|
||||
}
|
||||
if (new_exif_size > 4) /* TIFF header + some data found*/
|
||||
{
|
||||
if (! gexiv2_metadata_open_buf (exif_metadata, tiffheader, new_exif_size, error))
|
||||
{
|
||||
g_printerr ("%s: Failed to set EXIF metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||
g_clear_error (error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr ("%s: EXIF metadata not set\n", G_STRFUNC);
|
||||
}
|
||||
}
|
||||
|
||||
if (xmp_data)
|
||||
{
|
||||
if (! pika_metadata_set_from_xmp (metadata, xmp_data, xmp_data_size, error))
|
||||
{
|
||||
g_printerr ("%s: Failed to set XMP metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||
g_clear_error (error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gexiv2_metadata_try_set_orientation (GEXIV2_METADATA (metadata),
|
||||
GEXIV2_ORIENTATION_NORMAL, NULL);
|
||||
gexiv2_metadata_try_set_metadata_pixel_width (GEXIV2_METADATA (metadata), width, NULL);
|
||||
gexiv2_metadata_try_set_metadata_pixel_height (GEXIV2_METADATA (metadata),
|
||||
height, NULL);
|
||||
|
||||
*flags = PIKA_METADATA_LOAD_COMMENT | PIKA_METADATA_LOAD_RESOLUTION;
|
||||
}
|
||||
|
||||
if (profile)
|
||||
g_object_unref (profile);
|
||||
|
@ -230,10 +230,10 @@ load_image (GFile *file,
|
||||
{
|
||||
ILBM_Image *true_image = iff_image[i];
|
||||
/* Struct representing bitmap header properties */
|
||||
ILBM_BitMapHeader *bitMapHeader = true_image->bitMapHeader;
|
||||
ILBM_BitMapHeader *bitMapHeader;
|
||||
/* Struct containing the color palette */
|
||||
ILBM_ColorMap *colorMap = true_image->colorMap;
|
||||
ILBM_Viewport *camg = true_image->viewport;
|
||||
ILBM_ColorMap *colorMap;
|
||||
ILBM_Viewport *camg;
|
||||
IFF_UByte *bitplanes;
|
||||
PikaImageType image_type;
|
||||
guchar pika_cmap[768]; /* Max index is (2^nplanes) - 1 */
|
||||
@ -244,29 +244,38 @@ load_image (GFile *file,
|
||||
gint row_length;
|
||||
gint pixel_size = 1;
|
||||
gint y_height = 0;
|
||||
gint aspect_x = 0;
|
||||
gint aspect_y = 0;
|
||||
gboolean ehb_mode = FALSE;
|
||||
gboolean ham_mode = FALSE;
|
||||
|
||||
if (! true_image || ! bitMapHeader)
|
||||
if (! true_image)
|
||||
{
|
||||
g_message (_("Invalid or missing ILBM image"));
|
||||
return image;
|
||||
}
|
||||
if (! true_image->body)
|
||||
{
|
||||
g_message (_("ILBM contains no image data - likely a palette file"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
colorMap = true_image->colorMap;
|
||||
camg = true_image->viewport;
|
||||
|
||||
/* Convert ACBM files to ILBM format */
|
||||
if (ILBM_imageIsACBM (true_image))
|
||||
ILBM_convertACBMToILBM (true_image);
|
||||
|
||||
bitMapHeader = true_image->bitMapHeader;
|
||||
if (! bitMapHeader || ! true_image->body)
|
||||
{
|
||||
g_message (_("ILBM contains no image data - likely a palette file"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
width = bitMapHeader->w;
|
||||
height = bitMapHeader->h;
|
||||
nPlanes = bitMapHeader->nPlanes;
|
||||
row_length = (width + 15) / 16;
|
||||
pixel_size = nPlanes / 8;
|
||||
aspect_x = bitMapHeader->xAspect;
|
||||
aspect_y = bitMapHeader->yAspect;
|
||||
|
||||
/* Check for ILBM variants in CMAG chunk */
|
||||
if (camg)
|
||||
@ -329,8 +338,9 @@ load_image (GFile *file,
|
||||
|
||||
ILBM_unpackByteRun (true_image);
|
||||
|
||||
image = pika_image_new (width, height,
|
||||
pixel_size == 1 ? PIKA_INDEXED : PIKA_RGB);
|
||||
if (! image)
|
||||
image = pika_image_new (width, height,
|
||||
pixel_size == 1 ? PIKA_INDEXED : PIKA_RGB);
|
||||
|
||||
layer = pika_layer_new (image, _("Background"), width, height,
|
||||
image_type, 100,
|
||||
@ -341,6 +351,24 @@ load_image (GFile *file,
|
||||
|
||||
bitplanes = true_image->body->chunkData;
|
||||
|
||||
/* Setting resolution for non-square pixel aspect ratios */
|
||||
if (aspect_x != aspect_y && aspect_x > 0 && aspect_y > 0)
|
||||
{
|
||||
gdouble image_xres;
|
||||
gdouble image_yres;
|
||||
gfloat ratio = (gfloat) aspect_x / aspect_y;
|
||||
|
||||
g_message (_("Non-square pixels. Image might look squashed if "
|
||||
"Dot for Dot mode is enabled."));
|
||||
|
||||
pika_image_get_resolution (image, &image_xres, &image_yres);
|
||||
if (ratio < 1)
|
||||
image_xres = image_yres * (1 / ratio);
|
||||
else
|
||||
image_yres = image_xres * ratio;
|
||||
pika_image_set_resolution (image, image_xres, image_yres);
|
||||
}
|
||||
|
||||
/* Loading rows */
|
||||
for (gint j = 0; j < height; j++)
|
||||
{
|
||||
|
@ -396,9 +396,11 @@ create_cmyk_layer (PikaImage *image,
|
||||
}
|
||||
|
||||
static PikaImage *
|
||||
load_image (GFile *file,
|
||||
PikaRunMode runmode,
|
||||
GError **error)
|
||||
load_image (GFile *file,
|
||||
PikaRunMode runmode,
|
||||
PikaMetadata *metadata,
|
||||
PikaMetadataLoadFlags *flags,
|
||||
GError **error)
|
||||
{
|
||||
FILE *inputFile = g_fopen (g_file_peek_path (file), "rb");
|
||||
|
||||
@ -430,6 +432,7 @@ load_image (GFile *file,
|
||||
const Babl *type;
|
||||
PikaPrecision precision_linear;
|
||||
PikaPrecision precision_non_linear;
|
||||
uint32_t i;
|
||||
|
||||
if (!inputFile)
|
||||
{
|
||||
@ -637,7 +640,7 @@ load_image (GFile *file,
|
||||
}
|
||||
|
||||
/* Check for extra channels */
|
||||
for (gint32 i = 0; i < basicinfo.num_extra_channels; i++)
|
||||
for (i = 0; i < basicinfo.num_extra_channels; i++)
|
||||
{
|
||||
JxlExtraChannelInfo extra;
|
||||
|
||||
@ -936,205 +939,208 @@ load_image (GFile *file,
|
||||
g_object_unref (profile);
|
||||
}
|
||||
|
||||
if (basicinfo.have_container)
|
||||
if (metadata)
|
||||
{
|
||||
JxlDecoderReleaseInput (decoder);
|
||||
JxlDecoderRewind (decoder);
|
||||
if (basicinfo.have_container)
|
||||
{
|
||||
JxlDecoderReleaseInput (decoder);
|
||||
JxlDecoderRewind (decoder);
|
||||
|
||||
if (JxlDecoderSetInput (decoder, memory, inputFileSize) != JXL_DEC_SUCCESS)
|
||||
{
|
||||
g_printerr ("%s: JxlDecoderSetInput failed after JxlDecoderRewind\n", G_STRFUNC);
|
||||
}
|
||||
else
|
||||
{
|
||||
JxlDecoderCloseInput (decoder);
|
||||
if (JxlDecoderSubscribeEvents (decoder, JXL_DEC_BOX) != JXL_DEC_SUCCESS)
|
||||
if (JxlDecoderSetInput (decoder, memory, inputFileSize) != JXL_DEC_SUCCESS)
|
||||
{
|
||||
g_printerr ("%s: JxlDecoderSubscribeEvents for JXL_DEC_BOX failed\n", G_STRFUNC);
|
||||
g_printerr ("%s: JxlDecoderSetInput failed after JxlDecoderRewind\n", G_STRFUNC);
|
||||
}
|
||||
else
|
||||
{
|
||||
gboolean search_exif = TRUE;
|
||||
gboolean search_xmp = TRUE;
|
||||
gboolean success_exif = FALSE;
|
||||
gboolean success_xmp = FALSE;
|
||||
JxlBoxType box_type = { 0, 0, 0, 0 };
|
||||
GByteArray *exif_box = NULL;
|
||||
GByteArray *xml_box = NULL;
|
||||
size_t exif_remains = 0;
|
||||
size_t xml_remains = 0;
|
||||
|
||||
while (search_exif || search_xmp)
|
||||
JxlDecoderCloseInput (decoder);
|
||||
if (JxlDecoderSubscribeEvents (decoder, JXL_DEC_BOX) != JXL_DEC_SUCCESS)
|
||||
{
|
||||
status = JxlDecoderProcessInput (decoder);
|
||||
switch (status)
|
||||
g_printerr ("%s: JxlDecoderSubscribeEvents for JXL_DEC_BOX failed\n", G_STRFUNC);
|
||||
}
|
||||
else
|
||||
{
|
||||
gboolean search_exif = TRUE;
|
||||
gboolean search_xmp = TRUE;
|
||||
gboolean success_exif = FALSE;
|
||||
gboolean success_xmp = FALSE;
|
||||
JxlBoxType box_type = { 0, 0, 0, 0 };
|
||||
GByteArray *exif_box = NULL;
|
||||
GByteArray *xml_box = NULL;
|
||||
size_t exif_remains = 0;
|
||||
size_t xml_remains = 0;
|
||||
|
||||
while (search_exif || search_xmp)
|
||||
{
|
||||
case JXL_DEC_SUCCESS:
|
||||
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif)
|
||||
{
|
||||
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (exif_box, exif_box->len - exif_remains);
|
||||
success_exif = TRUE;
|
||||
}
|
||||
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp)
|
||||
{
|
||||
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (xml_box, xml_box->len - xml_remains);
|
||||
success_xmp = TRUE;
|
||||
}
|
||||
|
||||
search_exif = FALSE;
|
||||
search_xmp = FALSE;
|
||||
break;
|
||||
case JXL_DEC_ERROR:
|
||||
search_exif = FALSE;
|
||||
search_xmp = FALSE;
|
||||
g_printerr ("%s: Metadata decoding error\n", G_STRFUNC);
|
||||
break;
|
||||
case JXL_DEC_NEED_MORE_INPUT:
|
||||
search_exif = FALSE;
|
||||
search_xmp = FALSE;
|
||||
g_printerr ("%s: JXL metadata are probably incomplete\n", G_STRFUNC);
|
||||
break;
|
||||
case JXL_DEC_BOX:
|
||||
JxlDecoderSetDecompressBoxes (decoder, JXL_TRUE);
|
||||
|
||||
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif && exif_box)
|
||||
{
|
||||
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (exif_box, exif_box->len - exif_remains);
|
||||
|
||||
search_exif = FALSE;
|
||||
success_exif = TRUE;
|
||||
}
|
||||
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp && xml_box)
|
||||
{
|
||||
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (xml_box, xml_box->len - xml_remains);
|
||||
|
||||
search_xmp = FALSE;
|
||||
success_xmp = TRUE;
|
||||
}
|
||||
|
||||
if (JxlDecoderGetBoxType (decoder, box_type, JXL_TRUE) == JXL_DEC_SUCCESS)
|
||||
status = JxlDecoderProcessInput (decoder);
|
||||
switch (status)
|
||||
{
|
||||
case JXL_DEC_SUCCESS:
|
||||
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif)
|
||||
{
|
||||
exif_box = g_byte_array_sized_new (4096);
|
||||
g_byte_array_set_size (exif_box, 4096);
|
||||
|
||||
JxlDecoderSetBoxBuffer (decoder, exif_box->data, exif_box->len);
|
||||
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (exif_box, exif_box->len - exif_remains);
|
||||
success_exif = TRUE;
|
||||
}
|
||||
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp)
|
||||
{
|
||||
xml_box = g_byte_array_sized_new (4096);
|
||||
g_byte_array_set_size (xml_box, 4096);
|
||||
|
||||
JxlDecoderSetBoxBuffer (decoder, xml_box->data, xml_box->len);
|
||||
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (xml_box, xml_box->len - xml_remains);
|
||||
success_xmp = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
search_exif = FALSE;
|
||||
search_xmp = FALSE;
|
||||
g_printerr ("%s: Error in JxlDecoderGetBoxType\n", G_STRFUNC);
|
||||
}
|
||||
break;
|
||||
case JXL_DEC_BOX_NEED_MORE_OUTPUT:
|
||||
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif)
|
||||
{
|
||||
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (exif_box, exif_box->len + 4096);
|
||||
JxlDecoderSetBoxBuffer (decoder, exif_box->data + exif_box->len - (4096 + exif_remains), 4096 + exif_remains);
|
||||
}
|
||||
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp)
|
||||
{
|
||||
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (xml_box, xml_box->len + 4096);
|
||||
JxlDecoderSetBoxBuffer (decoder, xml_box->data + xml_box->len - (4096 + xml_remains), 4096 + xml_remains);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
case JXL_DEC_ERROR:
|
||||
search_exif = FALSE;
|
||||
search_xmp = FALSE;
|
||||
g_printerr ("%s: Metadata decoding error\n", G_STRFUNC);
|
||||
break;
|
||||
case JXL_DEC_NEED_MORE_INPUT:
|
||||
search_exif = FALSE;
|
||||
search_xmp = FALSE;
|
||||
g_printerr ("%s: JXL metadata are probably incomplete\n", G_STRFUNC);
|
||||
break;
|
||||
case JXL_DEC_BOX:
|
||||
JxlDecoderSetDecompressBoxes (decoder, JXL_TRUE);
|
||||
|
||||
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif && exif_box)
|
||||
{
|
||||
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (exif_box, exif_box->len - exif_remains);
|
||||
|
||||
search_exif = FALSE;
|
||||
success_exif = TRUE;
|
||||
}
|
||||
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp && xml_box)
|
||||
{
|
||||
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (xml_box, xml_box->len - xml_remains);
|
||||
|
||||
search_xmp = FALSE;
|
||||
success_xmp = TRUE;
|
||||
}
|
||||
|
||||
if (JxlDecoderGetBoxType (decoder, box_type, JXL_TRUE) == JXL_DEC_SUCCESS)
|
||||
{
|
||||
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif)
|
||||
{
|
||||
exif_box = g_byte_array_sized_new (4096);
|
||||
g_byte_array_set_size (exif_box, 4096);
|
||||
|
||||
JxlDecoderSetBoxBuffer (decoder, exif_box->data, exif_box->len);
|
||||
}
|
||||
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp)
|
||||
{
|
||||
xml_box = g_byte_array_sized_new (4096);
|
||||
g_byte_array_set_size (xml_box, 4096);
|
||||
|
||||
JxlDecoderSetBoxBuffer (decoder, xml_box->data, xml_box->len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
search_exif = FALSE;
|
||||
search_xmp = FALSE;
|
||||
g_printerr ("%s: Error in JxlDecoderGetBoxType\n", G_STRFUNC);
|
||||
}
|
||||
break;
|
||||
case JXL_DEC_BOX_NEED_MORE_OUTPUT:
|
||||
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif)
|
||||
{
|
||||
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (exif_box, exif_box->len + 4096);
|
||||
JxlDecoderSetBoxBuffer (decoder, exif_box->data + exif_box->len - (4096 + exif_remains), 4096 + exif_remains);
|
||||
}
|
||||
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp)
|
||||
{
|
||||
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||
g_byte_array_set_size (xml_box, xml_box->len + 4096);
|
||||
JxlDecoderSetBoxBuffer (decoder, xml_box->data + xml_box->len - (4096 + xml_remains), 4096 + xml_remains);
|
||||
}
|
||||
else
|
||||
{
|
||||
search_exif = FALSE;
|
||||
search_xmp = FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (success_exif || success_xmp)
|
||||
{
|
||||
PikaMetadata *metadata = pika_metadata_new ();
|
||||
|
||||
if (success_exif && exif_box)
|
||||
if (success_exif || success_xmp)
|
||||
{
|
||||
const guint8 tiffHeaderBE[4] = { 'M', 'M', 0, 42 };
|
||||
const guint8 tiffHeaderLE[4] = { 'I', 'I', 42, 0 };
|
||||
const guint8 *tiffheader = exif_box->data;
|
||||
glong new_exif_size = exif_box->len;
|
||||
gexiv2_metadata_clear (GEXIV2_METADATA (metadata));
|
||||
|
||||
while (new_exif_size >= 4) /*Searching for TIFF Header*/
|
||||
if (success_exif && exif_box)
|
||||
{
|
||||
if (tiffheader[0] == tiffHeaderBE[0] && tiffheader[1] == tiffHeaderBE[1] &&
|
||||
tiffheader[2] == tiffHeaderBE[2] && tiffheader[3] == tiffHeaderBE[3])
|
||||
const guint8 tiffHeaderBE[4] = { 'M', 'M', 0, 42 };
|
||||
const guint8 tiffHeaderLE[4] = { 'I', 'I', 42, 0 };
|
||||
const guint8 *tiffheader = exif_box->data;
|
||||
glong new_exif_size = exif_box->len;
|
||||
|
||||
while (new_exif_size >= 4) /*Searching for TIFF Header*/
|
||||
{
|
||||
break;
|
||||
if (tiffheader[0] == tiffHeaderBE[0] && tiffheader[1] == tiffHeaderBE[1] &&
|
||||
tiffheader[2] == tiffHeaderBE[2] && tiffheader[3] == tiffHeaderBE[3])
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (tiffheader[0] == tiffHeaderLE[0] && tiffheader[1] == tiffHeaderLE[1] &&
|
||||
tiffheader[2] == tiffHeaderLE[2] && tiffheader[3] == tiffHeaderLE[3])
|
||||
{
|
||||
break;
|
||||
}
|
||||
new_exif_size--;
|
||||
tiffheader++;
|
||||
}
|
||||
if (tiffheader[0] == tiffHeaderLE[0] && tiffheader[1] == tiffHeaderLE[1] &&
|
||||
tiffheader[2] == tiffHeaderLE[2] && tiffheader[3] == tiffHeaderLE[3])
|
||||
|
||||
if (new_exif_size > 4) /* TIFF header + some data found*/
|
||||
{
|
||||
break;
|
||||
if (! gexiv2_metadata_open_buf (GEXIV2_METADATA (metadata), tiffheader, new_exif_size, error))
|
||||
{
|
||||
g_printerr ("%s: Failed to set EXIF metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||
g_clear_error (error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr ("%s: EXIF metadata not set\n", G_STRFUNC);
|
||||
}
|
||||
new_exif_size--;
|
||||
tiffheader++;
|
||||
}
|
||||
|
||||
if (new_exif_size > 4) /* TIFF header + some data found*/
|
||||
if (success_xmp && xml_box)
|
||||
{
|
||||
if (! gexiv2_metadata_open_buf (GEXIV2_METADATA (metadata), tiffheader, new_exif_size, error))
|
||||
if (! pika_metadata_set_from_xmp (metadata, xml_box->data, xml_box->len, error))
|
||||
{
|
||||
g_printerr ("%s: Failed to set EXIF metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||
g_printerr ("%s: Failed to set XMP metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||
g_clear_error (error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr ("%s: EXIF metadata not set\n", G_STRFUNC);
|
||||
}
|
||||
}
|
||||
|
||||
if (success_xmp && xml_box)
|
||||
if (exif_box)
|
||||
{
|
||||
if (! pika_metadata_set_from_xmp (metadata, xml_box->data, xml_box->len, error))
|
||||
{
|
||||
g_printerr ("%s: Failed to set XMP metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||
g_clear_error (error);
|
||||
}
|
||||
g_byte_array_free (exif_box, TRUE);
|
||||
}
|
||||
|
||||
gexiv2_metadata_try_set_orientation (GEXIV2_METADATA (metadata),
|
||||
GEXIV2_ORIENTATION_NORMAL, NULL);
|
||||
gexiv2_metadata_try_set_metadata_pixel_width (GEXIV2_METADATA (metadata),
|
||||
basicinfo.xsize, NULL);
|
||||
gexiv2_metadata_try_set_metadata_pixel_height (GEXIV2_METADATA (metadata),
|
||||
basicinfo.ysize, NULL);
|
||||
pika_image_metadata_load_finish (image, "image/jxl", metadata,
|
||||
PIKA_METADATA_LOAD_COMMENT | PIKA_METADATA_LOAD_RESOLUTION);
|
||||
}
|
||||
|
||||
if (exif_box)
|
||||
{
|
||||
g_byte_array_free (exif_box, TRUE);
|
||||
}
|
||||
|
||||
if (xml_box)
|
||||
{
|
||||
g_byte_array_free (xml_box, TRUE);
|
||||
if (xml_box)
|
||||
{
|
||||
g_byte_array_free (xml_box, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gexiv2_metadata_try_set_orientation (GEXIV2_METADATA (metadata),
|
||||
GEXIV2_ORIENTATION_NORMAL, NULL);
|
||||
gexiv2_metadata_try_set_metadata_pixel_width (GEXIV2_METADATA (metadata),
|
||||
basicinfo.xsize, NULL);
|
||||
gexiv2_metadata_try_set_metadata_pixel_height (GEXIV2_METADATA (metadata),
|
||||
basicinfo.ysize, NULL);
|
||||
|
||||
*flags = PIKA_METADATA_LOAD_COMMENT | PIKA_METADATA_LOAD_RESOLUTION;
|
||||
}
|
||||
|
||||
JxlThreadParallelRunnerDestroy (runner);
|
||||
@ -1158,7 +1164,7 @@ jpegxl_load (PikaProcedure *procedure,
|
||||
|
||||
gegl_init (NULL, NULL);
|
||||
|
||||
image = load_image (file, run_mode, &error);
|
||||
image = load_image (file, run_mode, metadata, flags, &error);
|
||||
|
||||
if (! image)
|
||||
return pika_procedure_new_return_values (procedure,
|
||||
|
@ -886,12 +886,13 @@ gui_single (PikaProcedure *procedure,
|
||||
PikaProcedureConfig *config,
|
||||
PikaImage *image)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *widget;
|
||||
GList *missing_fonts;
|
||||
GList *dialog_props = NULL;
|
||||
gboolean run;
|
||||
gint32 n_layers;
|
||||
GtkWidget *window;
|
||||
GtkWidget *widget;
|
||||
PikaLayer **layers;
|
||||
GList *missing_fonts;
|
||||
GList *dialog_props = NULL;
|
||||
gboolean run;
|
||||
gint32 n_layers;
|
||||
|
||||
pika_ui_init (PLUG_IN_BINARY);
|
||||
|
||||
@ -910,7 +911,13 @@ gui_single (PikaProcedure *procedure,
|
||||
widget = pika_procedure_dialog_fill_frame (PIKA_PROCEDURE_DIALOG (window),
|
||||
"pages-frame", "layers-as-pages", FALSE,
|
||||
"pages-box");
|
||||
g_free (pika_image_get_layers (multi_page.images[0], &n_layers));
|
||||
/* Enable "layers-as-pages" if more than one layer, or there's a single
|
||||
* layer group has more than one layer */
|
||||
layers = pika_image_get_layers (multi_page.images[0], &n_layers);
|
||||
if (n_layers == 1 && pika_item_is_group (PIKA_ITEM (layers[0])))
|
||||
g_free (pika_item_get_children (PIKA_ITEM (layers[0]), &n_layers));
|
||||
g_free (layers);
|
||||
|
||||
gtk_widget_set_sensitive (widget, n_layers > 1);
|
||||
|
||||
/* Warning for missing fonts (non-embeddable with rasterization
|
||||
|
@ -65,6 +65,7 @@ typedef enum _PngExportformat
|
||||
PNG_FORMAT_GRAYA16
|
||||
} PngExportFormat;
|
||||
|
||||
static GSList *safe_to_copy_chunks;
|
||||
|
||||
typedef struct _Png Png;
|
||||
typedef struct _PngClass PngClass;
|
||||
@ -139,6 +140,9 @@ static gboolean ia_has_transparent_pixels (GeglBuffer *buffer);
|
||||
static gint find_unused_ia_color (GeglBuffer *buffer,
|
||||
gint *colors);
|
||||
|
||||
static gint read_unknown_chunk (png_structp png_ptr,
|
||||
png_unknown_chunkp chunk);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (Png, png, PIKA_TYPE_PLUG_IN)
|
||||
|
||||
@ -602,6 +606,7 @@ load_image (GFile *file,
|
||||
const Babl *file_format; /* BABL format for layer */
|
||||
png_structp pp; /* PNG read pointer */
|
||||
png_infop info; /* PNG info pointers */
|
||||
png_voidp user_chunkp; /* PNG unknown chunk pointer */
|
||||
guchar **pixels; /* Pixel rows */
|
||||
guchar *pixel; /* Pixel data */
|
||||
guchar alpha[256]; /* Index -> Alpha */
|
||||
@ -609,6 +614,8 @@ load_image (GFile *file,
|
||||
gint num_texts;
|
||||
struct read_error_data error_data;
|
||||
|
||||
safe_to_copy_chunks = NULL;
|
||||
|
||||
pp = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (! pp)
|
||||
{
|
||||
@ -667,6 +674,11 @@ load_image (GFile *file,
|
||||
png_init_io (pp, fp);
|
||||
png_set_compression_buffer_size (pp, 512);
|
||||
|
||||
/* Set up callback to save "safe to copy" chunks */
|
||||
png_set_keep_unknown_chunks (pp, PNG_HANDLE_CHUNK_IF_SAFE, NULL, 0);
|
||||
user_chunkp = png_get_user_chunk_ptr (pp);
|
||||
png_set_read_user_chunk_fn (pp, user_chunkp, read_unknown_chunk);
|
||||
|
||||
/*
|
||||
* Get the image info
|
||||
*/
|
||||
@ -1184,6 +1196,23 @@ load_image (GFile *file,
|
||||
g_object_unref (buffer);
|
||||
}
|
||||
|
||||
/* If any safe-to-copy chunks were saved,
|
||||
* store them in the image as parasite */
|
||||
if (safe_to_copy_chunks)
|
||||
{
|
||||
GSList *iter;
|
||||
|
||||
for (iter = safe_to_copy_chunks; iter; iter = iter->next)
|
||||
{
|
||||
PikaParasite *parasite = iter->data;
|
||||
|
||||
pika_image_attach_parasite ((PikaImage *) image, parasite);
|
||||
pika_parasite_free (parasite);
|
||||
}
|
||||
|
||||
g_slist_free (safe_to_copy_chunks);
|
||||
}
|
||||
|
||||
return (PikaImage *) image;
|
||||
}
|
||||
|
||||
@ -1292,6 +1321,7 @@ save_image (GFile *file,
|
||||
gint num; /* Number of rows to load */
|
||||
FILE *fp; /* File pointer */
|
||||
PikaColorProfile *profile = NULL; /* Color profile */
|
||||
gchar **parasites; /* Safe-to-copy chunks */
|
||||
gboolean out_linear; /* Save linear RGB */
|
||||
GeglBuffer *buffer; /* GEGL buffer for layer */
|
||||
const Babl *file_format = NULL; /* BABL format of file */
|
||||
@ -1914,6 +1944,51 @@ save_image (GFile *file,
|
||||
if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
|
||||
png_set_swap (pp);
|
||||
|
||||
/* Write any safe-to-copy chunks saved from import */
|
||||
parasites = pika_image_get_parasite_list (image);
|
||||
|
||||
if (parasites)
|
||||
{
|
||||
gint count;
|
||||
|
||||
count = g_strv_length (parasites);
|
||||
for (gint i = 0; i < count; i++)
|
||||
{
|
||||
if (strncmp (parasites[i], "png", 3) == 0)
|
||||
{
|
||||
PikaParasite *parasite;
|
||||
|
||||
parasite = pika_image_get_parasite (image, parasites[i]);
|
||||
|
||||
if (parasite)
|
||||
{
|
||||
gchar buf[1024];
|
||||
gchar *chunk_name;
|
||||
|
||||
g_strlcpy (buf, parasites[i], sizeof (buf));
|
||||
chunk_name = strchr (buf, '/');
|
||||
chunk_name++;
|
||||
|
||||
if (chunk_name)
|
||||
{
|
||||
png_byte name[4];
|
||||
const guint8 *data;
|
||||
guint32 len;
|
||||
|
||||
for (gint j = 0; j < 4; j++)
|
||||
name[j] = chunk_name[j];
|
||||
|
||||
data = (const guint8 *) pika_parasite_get_data (parasite, &len);
|
||||
|
||||
png_write_chunk (pp, name, data, len);
|
||||
}
|
||||
pika_parasite_free (parasite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g_strfreev (parasites);
|
||||
|
||||
/*
|
||||
* Turn on interlace handling...
|
||||
*/
|
||||
@ -2263,6 +2338,28 @@ respin_cmap (png_structp pp,
|
||||
return get_bit_depth_for_palette (colors);
|
||||
}
|
||||
|
||||
static gint
|
||||
read_unknown_chunk (png_structp png_ptr,
|
||||
png_unknown_chunkp chunk)
|
||||
{
|
||||
/* Chunks with a lowercase letter in the 4th byte
|
||||
* are safe to copy */
|
||||
if (g_ascii_islower (chunk->name[3]))
|
||||
{
|
||||
PikaParasite *parasite;
|
||||
gchar pname[255];
|
||||
|
||||
g_snprintf (pname, sizeof (pname), "png/%s", chunk->name);
|
||||
|
||||
if ((parasite = pika_parasite_new (pname,
|
||||
PIKA_PARASITE_PERSISTENT,
|
||||
chunk->size, chunk->data)))
|
||||
safe_to_copy_chunks = g_slist_prepend (safe_to_copy_chunks, parasite);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
save_dialog (PikaImage *image,
|
||||
PikaProcedure *procedure,
|
||||
|
@ -944,7 +944,7 @@ process_pam_header (PNMScanner *scan,
|
||||
{
|
||||
/* skip unknown headers but recognize xv's thumbnail format */
|
||||
CHECK_FOR_ERROR (g_ascii_isdigit (*buf), pnminfo->jmpbuf,
|
||||
_("PAM: Unsupported inofficial PNM variant."));
|
||||
_("PAM: Unsupported unofficial PNM variant."));
|
||||
}
|
||||
}
|
||||
CHECK_FOR_ERROR (pnmscanner_eof (scan), pnminfo->jmpbuf,
|
||||
|
@ -77,7 +77,7 @@ struct _LicClass
|
||||
|
||||
|
||||
#define LIC_TYPE (lic_get_type ())
|
||||
#define LIC (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LIC_TYPE, Lic))
|
||||
#define LIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LIC_TYPE, Lic))
|
||||
|
||||
GType lic_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
Reference in New Issue
Block a user