400 lines
13 KiB
C
400 lines
13 KiB
C
|
/* PIKA - Photo and Image Kooker Application
|
||
|
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||
|
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||
|
*
|
||
|
* Original copyright, applying to most contents (license remains unchanged):
|
||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||
|
*
|
||
|
* jpeg-settings.c
|
||
|
* Copyright (C) 2007 Raphaël Quinet <raphael@gimp.org>
|
||
|
*
|
||
|
* This program is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Structure of the "jpeg-settings" parasite:
|
||
|
* 1 byte - JPEG color space (JCS_YCbCr, JCS_GRAYSCALE, JCS_CMYK, ...)
|
||
|
* 1 byte - quality (1..100 according to the IJG scale, or 0)
|
||
|
* 1 byte - number of components (0..4)
|
||
|
* 1 byte - number of quantization tables (0..4)
|
||
|
* C * 2 bytes - sampling factors for each component (1..4)
|
||
|
* T * 128 bytes - quantization tables (only if different from IJG tables)
|
||
|
*
|
||
|
* Additional data following the quantization tables is currently
|
||
|
* ignored and can be used for future extensions.
|
||
|
*
|
||
|
* In order to improve the compatibility with future versions of the
|
||
|
* plug-in that may support more subsampling types ("subsmp"), the
|
||
|
* parasite contains the original subsampling for each component
|
||
|
* instead of saving only one byte containing the subsampling type as
|
||
|
* used by the jpeg plug-in. The same applies to the other settings:
|
||
|
* for example, up to 4 quantization tables will be saved in the
|
||
|
* parasite even if the current code cannot restore more than 2 of
|
||
|
* them (4 tables may be needed by unusual JPEG color spaces such as
|
||
|
* JCS_CMYK or JCS_YCCK).
|
||
|
*/
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <setjmp.h>
|
||
|
|
||
|
#include <glib/gstdio.h>
|
||
|
|
||
|
#include <jpeglib.h>
|
||
|
|
||
|
#include <libpika/pika.h>
|
||
|
|
||
|
#include "libpika/stdplugins-intl.h"
|
||
|
|
||
|
#include "jpeg.h"
|
||
|
#include "jpeg-quality.h"
|
||
|
#include "jpeg-settings.h"
|
||
|
|
||
|
/**
|
||
|
* jpeg_detect_original_settings:
|
||
|
* @cinfo: a pointer to a JPEG decompressor info.
|
||
|
* @image: 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.
|
||
|
*
|
||
|
* This function must be called after jpeg_read_header() so that
|
||
|
* @cinfo contains the quantization tables and the sampling factors
|
||
|
* for each component.
|
||
|
*
|
||
|
* Returns: TRUE if a parasite has been attached to @image.
|
||
|
*/
|
||
|
gboolean
|
||
|
jpeg_detect_original_settings (struct jpeg_decompress_struct *cinfo,
|
||
|
PikaImage *image)
|
||
|
{
|
||
|
guint parasite_size;
|
||
|
guchar *parasite_data;
|
||
|
PikaParasite *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 = pika_parasite_new ("jpeg-settings",
|
||
|
PIKA_PARASITE_PERSISTENT,
|
||
|
parasite_size,
|
||
|
parasite_data);
|
||
|
g_free (parasite_data);
|
||
|
pika_image_attach_parasite (image, parasite);
|
||
|
pika_parasite_free (parasite);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* TODO: compare the JPEG color space found in the parasite with the
|
||
|
* PIKA color space of the drawable to be saved. If one of them is
|
||
|
* grayscale and the other isn't, then the quality setting may be used
|
||
|
* but the subsampling parameters and quantization tables should be
|
||
|
* ignored. The drawable needs to be passed around because the
|
||
|
* color space of the drawable may be different from that of the image
|
||
|
* (e.g., when saving a mask or channel).
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* jpeg_restore_original_settings:
|
||
|
* @image: 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. 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().
|
||
|
*
|
||
|
* Returns: TRUE if a valid parasite was attached to the image
|
||
|
*/
|
||
|
gboolean
|
||
|
jpeg_restore_original_settings (PikaImage *image,
|
||
|
gint *quality,
|
||
|
JpegSubsampling *subsmp,
|
||
|
gint *num_quant_tables)
|
||
|
{
|
||
|
PikaParasite *parasite;
|
||
|
const guchar *src;
|
||
|
guint32 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 = pika_image_get_parasite (image, "jpeg-settings");
|
||
|
if (parasite)
|
||
|
{
|
||
|
src = pika_parasite_get_data (parasite, &src_size);
|
||
|
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 = JPEG_SUBSAMPLING_1x1_1x1_1x1;
|
||
|
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 = JPEG_SUBSAMPLING_1x1_1x1_1x1;
|
||
|
else if (h[0] == 2 && v[0] == 1)
|
||
|
*subsmp = JPEG_SUBSAMPLING_2x1_1x1_1x1;
|
||
|
else if (h[0] == 1 && v[0] == 2)
|
||
|
*subsmp = JPEG_SUBSAMPLING_1x2_1x1_1x1;
|
||
|
else if (h[0] == 2 && v[0] == 2)
|
||
|
*subsmp = JPEG_SUBSAMPLING_2x2_1x1_1x1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pika_parasite_free (parasite);
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pika_parasite_free (parasite);
|
||
|
}
|
||
|
|
||
|
*quality = -1;
|
||
|
*subsmp = JPEG_SUBSAMPLING_1x1_1x1_1x1;
|
||
|
*num_quant_tables = 0;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* jpeg_restore_original_tables:
|
||
|
* @image: the image that may contain original jpeg settings in a parasite.
|
||
|
* @num_quant_tables: the number of quantization tables to restore.
|
||
|
*
|
||
|
* Retrieve the original quantization tables from the parasite
|
||
|
* attached to @image. Each table is an array of coefficients that
|
||
|
* can be associated with a component of a JPEG image when saving it.
|
||
|
*
|
||
|
* An array of newly allocated tables is returned if @num_quant_tables
|
||
|
* matches the number of tables saved in the parasite. These tables
|
||
|
* are returned as arrays of unsigned integers even if they will never
|
||
|
* use more than 16 bits (8 bits in most cases) because the IJG JPEG
|
||
|
* library expects arrays of unsigned integers. When these tables are
|
||
|
* not needed anymore, the caller should free them using g_free(). If
|
||
|
* no parasite exists or if it cannot be used, this function returns
|
||
|
* NULL.
|
||
|
*
|
||
|
* Returns: (nullable): an array of quantization tables, or NULL.
|
||
|
*/
|
||
|
guint **
|
||
|
jpeg_restore_original_tables (PikaImage *image,
|
||
|
gint num_quant_tables)
|
||
|
{
|
||
|
PikaParasite *parasite;
|
||
|
const guchar *src;
|
||
|
guint32 src_size;
|
||
|
gint num_components;
|
||
|
gint num_tables;
|
||
|
guint **quant_tables;
|
||
|
gint t;
|
||
|
gint i;
|
||
|
|
||
|
parasite = pika_image_get_parasite (image, "jpeg-settings");
|
||
|
if (parasite)
|
||
|
{
|
||
|
src = pika_parasite_get_data (parasite, &src_size);
|
||
|
if (src_size >= 4)
|
||
|
{
|
||
|
num_components = src[2];
|
||
|
num_tables = src[3];
|
||
|
|
||
|
if (src_size >= (4 + num_components * 2 + num_tables * 128)
|
||
|
&& num_tables == num_quant_tables)
|
||
|
{
|
||
|
src += 4 + num_components * 2;
|
||
|
quant_tables = g_new (guint *, num_tables);
|
||
|
|
||
|
for (t = 0; t < num_tables; t++)
|
||
|
{
|
||
|
quant_tables[t] = g_new (guint, 128);
|
||
|
for (i = 0; i < 64; i++)
|
||
|
{
|
||
|
guint c;
|
||
|
|
||
|
c = *src++ * 256;
|
||
|
c += *src++;
|
||
|
quant_tables[t][i] = c;
|
||
|
}
|
||
|
}
|
||
|
pika_parasite_free (parasite);
|
||
|
return quant_tables;
|
||
|
}
|
||
|
}
|
||
|
pika_parasite_free (parasite);
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* jpeg_swap_original_settings:
|
||
|
* @image: the image that may contain original jpeg settings in a parasite.
|
||
|
*
|
||
|
* Swap the horizontal and vertical axis for the saved subsampling
|
||
|
* parameters and quantization tables. This should be done if the
|
||
|
* image has been rotated by +90 or -90 degrees or if it has been
|
||
|
* mirrored along its diagonal.
|
||
|
*/
|
||
|
void
|
||
|
jpeg_swap_original_settings (PikaImage *image)
|
||
|
{
|
||
|
PikaParasite *parasite;
|
||
|
const guchar *src;
|
||
|
guint32 src_size;
|
||
|
gint num_components;
|
||
|
gint num_tables;
|
||
|
guchar *new_data;
|
||
|
guchar *dest;
|
||
|
gint t;
|
||
|
gint i;
|
||
|
gint j;
|
||
|
|
||
|
parasite = pika_image_get_parasite (image, "jpeg-settings");
|
||
|
if (parasite)
|
||
|
{
|
||
|
src = pika_parasite_get_data (parasite, &src_size);
|
||
|
if (src_size >= 4)
|
||
|
{
|
||
|
num_components = src[2];
|
||
|
num_tables = src[3];
|
||
|
|
||
|
if (src_size >= (4 + num_components * 2 + num_tables * 128))
|
||
|
{
|
||
|
new_data = g_new (guchar, src_size);
|
||
|
dest = new_data;
|
||
|
*dest++ = *src++;
|
||
|
*dest++ = *src++;
|
||
|
*dest++ = *src++;
|
||
|
*dest++ = *src++;
|
||
|
for (i = 0; i < num_components; i++)
|
||
|
{
|
||
|
dest[0] = src[1];
|
||
|
dest[1] = src[0];
|
||
|
dest += 2;
|
||
|
src += 2;
|
||
|
}
|
||
|
for (t = 0; t < num_tables; t++)
|
||
|
{
|
||
|
for (i = 0; i < 8; i++)
|
||
|
{
|
||
|
for (j = 0; j < 8; j++)
|
||
|
{
|
||
|
dest[i * 16 + j * 2] = src[j * 16 + i * 2];
|
||
|
dest[i * 16 + j * 2 + 1] = src[j * 16 + i * 2 + 1];
|
||
|
}
|
||
|
}
|
||
|
dest += 128;
|
||
|
src += 128;
|
||
|
if (src_size > (4 + num_components * 2 + num_tables * 128))
|
||
|
{
|
||
|
memcpy (dest, src, src_size - (4 + num_components * 2
|
||
|
+ num_tables * 128));
|
||
|
}
|
||
|
}
|
||
|
pika_parasite_free (parasite);
|
||
|
parasite = pika_parasite_new ("jpeg-settings",
|
||
|
PIKA_PARASITE_PERSISTENT,
|
||
|
src_size,
|
||
|
new_data);
|
||
|
g_free (new_data);
|
||
|
pika_image_attach_parasite (image, parasite);
|
||
|
}
|
||
|
}
|
||
|
pika_parasite_free (parasite);
|
||
|
}
|
||
|
}
|