Consolidate YCoCg/AlphaExp code, always decode

Moves most of the code relating to YCoCg and Alpha Exponent into
misc.c/h, in the interest of making the rest of the codebase cleaner.
Removes the decode option from the import menu, as encoded files are
always decoded now (there used to be a menu button for doing this
after import, but with it gone there's no reason ever to not decode).
Finally, the remaining functions in color.c were only ever called once,
so these were extracted and inlined, and the empty file deleted.
This commit is contained in:
Stayd 2023-11-25 19:47:49 -07:00 committed by Jacob Boerema
parent 30922cc266
commit a5d1d96a38
10 changed files with 459 additions and 711 deletions

View File

@ -1,62 +0,0 @@
/*
* DDS GIMP plugin
*
* Copyright (C) 2004-2012 Shawn Kirst <skirst@gmail.com>,
* with parts (C) 2003 Arne Reuter <homepage@arnereuter.de> where specified.
*
* 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 2 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; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301, USA.
*/
#include <math.h>
#include <libgimp/gimp.h>
#include "color.h"
gfloat
linear_to_sRGB (gfloat c)
{
gfloat v = (gfloat) c;
if (v < 0.0f)
v = 0.0f;
else if (v > 1.0f)
v = 1.0f;
else if (v <= 0.0031308f)
v = 12.92f * v;
else
v = 1.055f * powf (v, 0.41666f) - 0.055f;
return v;
}
gfloat
sRGB_to_linear (gfloat c)
{
gfloat v = (gfloat) c;
if (v < 0.0f)
v = 0.0f;
else if (v > 1.0f)
v = 1.0f;
else if (v <= 0.04045f)
v /= 12.92f;
else
v = powf ((v + 0.055f) / 1.055f, 2.4f);
return v;
}

View File

@ -1,112 +0,0 @@
/*
* DDS GIMP plugin
*
* Copyright (C) 2004-2012 Shawn Kirst <skirst@gmail.com>,
* with parts (C) 2003 Arne Reuter <homepage@arnereuter.de> where specified.
*
* 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/>.
*/
#ifndef __COLOR_H__
#define __COLOR_H__
#include "imath.h"
/* sRGB encoding & decoding */
gfloat linear_to_sRGB (gfloat c);
gfloat sRGB_to_linear (gfloat c);
/* YCoCg encoding */
static inline void
RGB_to_YCoCg (guchar *dst, gint r, gint g, gint b)
{
gint y = ((r + (g << 1) + b) + 2) >> 2;
gint co = ((((r << 1) - (b << 1)) + 2) >> 2) + 128;
gint cg = (((-r + (g << 1) - b) + 2) >> 2) + 128;
dst[0] = 255;
dst[1] = (cg > 255 ? 255 : (cg < 0 ? 0 : cg));
dst[2] = (co > 255 ? 255 : (co < 0 ? 0 : co));
dst[3] = (y > 255 ? 255 : (y < 0 ? 0 : y));
}
/* Other color conversions */
static inline gint
rgb_to_luminance (gint r,
gint g,
gint b)
{
/* ITU-R BT.709 luma coefficients, scaled by 256 */
return ((r * 54 + g * 182 + b * 20) + 128) >> 8;
}
static inline gushort
pack_r5g6b5 (gint r,
gint g,
gint b)
{
return (mul8bit (r, 31) << 11) |
(mul8bit (g, 63) << 5) |
(mul8bit (b, 31) );
}
static inline gushort
pack_rgba4 (gint r,
gint g,
gint b,
gint a)
{
return (mul8bit (a, 15) << 12) |
(mul8bit (r, 15) << 8) |
(mul8bit (g, 15) << 4) |
(mul8bit (b, 15) );
}
static inline gushort
pack_rgb5a1 (gint r,
gint g,
gint b,
gint a)
{
return (((a >> 7) & 0x01) << 15) |
(mul8bit (r, 31) << 10) |
(mul8bit (g, 31) << 5) |
(mul8bit (b, 31) );
}
static inline guchar
pack_r3g3b2 (gint r,
gint g,
gint b)
{
return (mul8bit (r, 7) << 5) |
(mul8bit (g, 7) << 2) |
(mul8bit (b, 3) );
}
static inline guint
pack_rgb10a2 (gint r, gint g, gint b, gint a)
{
return ((guint) ((a >> 6) & 0x003) << 30) |
((guint) ((b << 2) & 0x3ff) << 20) |
((guint) ((g << 2) & 0x3ff) << 10) |
((guint) ((r << 2) & 0x3ff) );
}
#endif /* __COLOR_H__ */

View File

@ -42,10 +42,6 @@
#define LOAD_PROC "file-dds-load"
#define SAVE_PROC "file-dds-save"
#define DECODE_YCOCG_PROC "color-decode-ycocg"
#define DECODE_YCOCG_SCALED_PROC "color-decode-ycocg-scaled"
#define DECODE_ALPHA_EXP_PROC "color-decode-alpha-exp"
typedef struct _Dds Dds;
typedef struct _DdsClass DdsClass;
@ -86,15 +82,6 @@ static GimpValueArray * dds_save (GimpProcedure *procedure,
GimpMetadata *metadata,
GimpProcedureConfig *config,
gpointer run_data);
#if 0
static GimpValueArray * dds_decode (GimpProcedure *procedure,
GimpRunMode run_mode,
GimpImage *image,
gint n_drawables,
GimpDrawable **drawables,
GimpProcedureConfig *config,
gpointer run_data);
#endif
G_DEFINE_TYPE (Dds, dds, GIMP_TYPE_PLUG_IN)
@ -125,11 +112,6 @@ dds_query_procedures (GimpPlugIn *plug_in)
list = g_list_append (list, g_strdup (LOAD_PROC));
list = g_list_append (list, g_strdup (SAVE_PROC));
#if 0
list = g_list_append (list, g_strdup (DECODE_YCOCG_PROC));
list = g_list_append (list, g_strdup (DECODE_YCOCG_SCALED_PROC));
list = g_list_append (list, g_strdup (DECODE_ALPHA_EXP_PROC));
#endif
return list;
}
@ -183,12 +165,6 @@ dds_create_procedure (GimpPlugIn *plug_in,
"to opaque black"),
TRUE,
G_PARAM_READWRITE);
GIMP_PROC_ARG_BOOLEAN (procedure, "decode-images",
_("Automatically decode YCoCg/AE_xp images when detected"),
_("Decode YCoCg/AExp images when detected"),
TRUE,
G_PARAM_READWRITE);
}
else if (! strcmp (name, SAVE_PROC))
{
@ -358,78 +334,6 @@ dds_create_procedure (GimpPlugIn *plug_in,
0.0, 1.0, 0.5,
G_PARAM_READWRITE);
}
#if 0
else if (! strcmp (name, DECODE_YCOCG_PROC))
{
procedure = gimp_image_procedure_new (plug_in, name,
GIMP_PDB_PROC_TYPE_PLUGIN,
dds_decode, NULL, NULL);
gimp_procedure_set_image_types (procedure, "RGBA");
gimp_procedure_set_sensitivity_mask (procedure,
GIMP_PROCEDURE_SENSITIVE_DRAWABLE);
gimp_procedure_set_menu_label (procedure, _("Decode YCoCg"));
/* gimp_procedure_add_menu_path (procedure, "<Image>/Filters/Colors"); */
gimp_procedure_set_documentation (procedure,
_("Converts YCoCg encoded pixels to RGB"),
_("Converts YCoCg encoded pixels to RGB"),
name);
gimp_procedure_set_attribution (procedure,
"Shawn Kirst",
"Shawn Kirst",
"2008");
}
else if (! strcmp (name, DECODE_YCOCG_SCALED_PROC))
{
procedure = gimp_image_procedure_new (plug_in, name,
GIMP_PDB_PROC_TYPE_PLUGIN,
dds_decode, NULL, NULL);
gimp_procedure_set_image_types (procedure, "RGBA");
gimp_procedure_set_sensitivity_mask (procedure,
GIMP_PROCEDURE_SENSITIVE_DRAWABLE);
gimp_procedure_set_menu_label (procedure, _("Decode YCoCg (scaled)"));
/* gimp_procedure_add_menu_path (procedure, "<Image>/Filters/Colors"); */
gimp_procedure_set_documentation (procedure,
_("Converts YCoCg (scaled) encoded "
"pixels to RGB"),
_("Converts YCoCg (scaled) encoded "
"pixels to RGB"),
name);
gimp_procedure_set_attribution (procedure,
"Shawn Kirst",
"Shawn Kirst",
"2008");
}
else if (! strcmp (name, DECODE_ALPHA_EXP_PROC))
{
procedure = gimp_image_procedure_new (plug_in, name,
GIMP_PDB_PROC_TYPE_PLUGIN,
dds_decode, NULL, NULL);
gimp_procedure_set_image_types (procedure, "RGBA");
gimp_procedure_set_sensitivity_mask (procedure,
GIMP_PROCEDURE_SENSITIVE_DRAWABLE);
gimp_procedure_set_menu_label (procedure, _("Decode Alpha exponent"));
/* gimp_procedure_add_menu_path (procedure, "<Image>/Filters/Colors"); */
gimp_procedure_set_documentation (procedure,
_("Converts alpha exponent encoded "
"pixels to RGB",
_("Converts alpha exponent encoded "
"pixels to RGB"),
name);
gimp_procedure_set_attribution (procedure,
"Shawn Kirst",
"Shawn Kirst",
"2008");
}
#endif
return procedure;
}
@ -535,53 +439,3 @@ dds_save (GimpProcedure *procedure,
return gimp_procedure_new_return_values (procedure, status, error);
}
#if 0
static GimpValueArray *
dds_decode (GimpProcedure *procedure,
GimpRunMode run_mode,
GimpImage *image,
gint n_drawables,
GimpDrawable **drawables,
GimpProcedureConfig *config,
gpointer run_data)
{
const gchar *name = gimp_procedure_get_name (procedure);
GimpDrawable *drawable,
if (n_drawables != 1)
{
GError *error = NULL;
g_set_error (&error, GIMP_PLUG_IN_ERROR, 0,
_("Procedure '%s' only works with one drawable."),
name);
return gimp_procedure_new_return_values (procedure,
GIMP_PDB_EXECUTION_ERROR,
error);
}
else
{
drawable = drawables[0];
}
if (! strcmp (name, DECODE_YCOCG_PROC))
{
decode_ycocg_image (drawable, TRUE);
}
else if (! strcmp (name, DECODE_YCOCG_SCALED_PROC))
{
decode_ycocg_scaled_image (drawable, TRUE);
}
else if (! strcmp (name, DECODE_ALPHA_EXP_PROC))
{
decode_alpha_exp_image (drawable, TRUE);
}
if (run_mode != GIMP_RUN_NONINTERACTIVE)
gimp_displays_flush ();
return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL);
}
#endif

View File

@ -85,7 +85,6 @@ static gboolean load_layer (FILE *fp,
guint *layer_index,
guchar *pixels,
guchar *buf,
gboolean decode_images,
GError **error);
static gboolean load_mipmaps (FILE *fp,
const dds_header_t *hdr,
@ -97,7 +96,6 @@ static gboolean load_mipmaps (FILE *fp,
guchar *pixels,
guchar *buf,
gboolean read_mipmaps,
gboolean decode_images,
GError **error);
static gboolean load_face (FILE *fp,
const dds_header_t *hdr,
@ -109,7 +107,6 @@ static gboolean load_face (FILE *fp,
guchar *pixels,
guchar *buf,
gboolean read_mipmaps,
gboolean decode_images,
GError **error);
static guchar color_bits (guint mask);
static guchar color_shift (guint mask);
@ -138,7 +135,6 @@ read_dds (GFile *file,
GimpImageBaseType type;
GimpPrecision precision;
gboolean read_mipmaps;
gboolean decode_images;
gint i, j;
guint computed_pitch_or_linsize;
gboolean flip_import;
@ -156,7 +152,6 @@ read_dds (GFile *file,
"load-mipmaps", &read_mipmaps,
"flip-image", &flip_import,
"bc1-use-transparency", &bc1_use_transparency,
"decode-images", &decode_images,
NULL);
fp = g_fopen (g_file_peek_path (file), "rb");
@ -629,7 +624,7 @@ read_dds (GFile *file,
dx10hdr.arraySize <= 1) /* Standard image texture with mipmaps */
{
if (! load_layer (fp, &hdr, &dx10hdr, &load_info, image, 0, "", &layer_index,
pixels, buf, decode_images, error))
pixels, buf, error))
{
fclose (fp);
gimp_image_delete (image);
@ -637,7 +632,7 @@ read_dds (GFile *file,
}
if (! load_mipmaps (fp, &hdr, &dx10hdr, &load_info, image, "", &layer_index,
pixels, buf, read_mipmaps, decode_images, error))
pixels, buf, read_mipmaps, error))
{
fclose (fp);
gimp_image_delete (image);
@ -648,7 +643,7 @@ read_dds (GFile *file,
{
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEX) &&
! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(positive x)",
&layer_index, pixels, buf, read_mipmaps, decode_images, error))
&layer_index, pixels, buf, read_mipmaps, error))
{
fclose (fp);
gimp_image_delete (image);
@ -657,7 +652,7 @@ read_dds (GFile *file,
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) &&
! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(negative x)",
&layer_index, pixels, buf, read_mipmaps, decode_images, error))
&layer_index, pixels, buf, read_mipmaps, error))
{
fclose (fp);
gimp_image_delete (image);
@ -666,7 +661,7 @@ read_dds (GFile *file,
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEY) &&
! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(positive y)",
&layer_index, pixels, buf, read_mipmaps, decode_images, error))
&layer_index, pixels, buf, read_mipmaps, error))
{
fclose (fp);
gimp_image_delete (image);
@ -675,7 +670,7 @@ read_dds (GFile *file,
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) &&
! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(negative y)",
&layer_index, pixels, buf, read_mipmaps, decode_images, error))
&layer_index, pixels, buf, read_mipmaps, error))
{
fclose (fp);
gimp_image_delete (image);
@ -684,7 +679,7 @@ read_dds (GFile *file,
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) &&
! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(positive z)",
&layer_index, pixels, buf, read_mipmaps, decode_images, error))
&layer_index, pixels, buf, read_mipmaps, error))
{
fclose (fp);
gimp_image_delete (image);
@ -693,7 +688,7 @@ read_dds (GFile *file,
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) &&
! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(negative z)",
&layer_index, pixels, buf, read_mipmaps, decode_images, error))
&layer_index, pixels, buf, read_mipmaps, error))
{
fclose (fp);
gimp_image_delete (image);
@ -711,7 +706,7 @@ read_dds (GFile *file,
plane = g_strdup_printf ("(z = %d)", i);
if (! load_layer (fp, &hdr, &dx10hdr, &load_info, image, 0, plane,
&layer_index, pixels, buf, decode_images, error))
&layer_index, pixels, buf, error))
{
g_free (plane);
fclose (fp);
@ -738,7 +733,7 @@ read_dds (GFile *file,
plane = g_strdup_printf ("(z = %d)", i);
if (! load_layer (fp, &hdr, &dx10hdr, &load_info, image, level, plane,
&layer_index, pixels, buf, decode_images, error))
&layer_index, pixels, buf, error))
{
g_free (plane);
fclose (fp);
@ -761,7 +756,7 @@ read_dds (GFile *file,
elem = g_strdup_printf ("(array element %d)", i);
if (! load_layer (fp, &hdr, &dx10hdr, &load_info, image, 0, elem, &layer_index,
pixels, buf, decode_images, error))
pixels, buf, error))
{
fclose (fp);
gimp_image_delete (image);
@ -769,7 +764,7 @@ read_dds (GFile *file,
}
if (! load_mipmaps (fp, &hdr, &dx10hdr, &load_info, image, elem, &layer_index,
pixels, buf, read_mipmaps, decode_images, error))
pixels, buf, read_mipmaps, error))
{
fclose (fp);
gimp_image_delete (image);
@ -1309,7 +1304,6 @@ load_layer (FILE *fp,
guint *layer_index,
guchar *pixels,
guchar *buf,
gboolean decode_images,
GError **error)
{
GeglBuffer *buffer;
@ -2025,21 +2019,20 @@ load_layer (FILE *fp,
g_object_unref (buffer);
/* gimp dds specific. decode encoded images */
if (decode_images &&
hdr->reserved.gimp_dds_special.magic1 == FOURCC ('G','I','M','P') &&
/* Decode files with GIMP-specific encodings */
if (hdr->reserved.gimp_dds_special.magic1 == FOURCC ('G','I','M','P') &&
hdr->reserved.gimp_dds_special.magic2 == FOURCC ('-','D','D','S'))
{
switch (hdr->reserved.gimp_dds_special.extra_fourcc)
{
case FOURCC ('A','E','X','P'):
decode_alpha_exp_image (GIMP_DRAWABLE (layer), FALSE);
decode_alpha_exponent (GIMP_DRAWABLE (layer));
break;
case FOURCC ('Y','C','G','1'):
decode_ycocg_image (GIMP_DRAWABLE (layer), FALSE);
decode_ycocg (GIMP_DRAWABLE (layer));
break;
case FOURCC ('Y','C','G','2'):
decode_ycocg_scaled_image (GIMP_DRAWABLE (layer), FALSE);
decode_ycocg_scaled (GIMP_DRAWABLE (layer));
break;
default:
break;
@ -2060,7 +2053,6 @@ load_mipmaps (FILE *fp,
guchar *pixels,
guchar *buf,
gboolean read_mipmaps,
gboolean decode_images,
GError **error)
{
guint level;
@ -2072,7 +2064,7 @@ load_mipmaps (FILE *fp,
for (level = 1; level < hdr->num_mipmaps; ++level)
{
if (! load_layer (fp, hdr, dx10hdr, load_info, image, level, prefix, layer_index,
pixels, buf, decode_images, error))
pixels, buf, error))
return FALSE;
}
}
@ -2091,15 +2083,14 @@ load_face (FILE *fp,
guchar *pixels,
guchar *buf,
gboolean read_mipmaps,
gboolean decode_images,
GError **error)
{
if (! load_layer (fp, hdr, dx10hdr, load_info, image, 0, prefix,
layer_index, pixels, buf, decode_images, error))
layer_index, pixels, buf, error))
return FALSE;
return load_mipmaps (fp, hdr, dx10hdr, load_info, image, prefix, layer_index,
pixels, buf, read_mipmaps, decode_images, error);
pixels, buf, read_mipmaps, error);
}
static guchar
@ -2124,7 +2115,7 @@ color_shift (guint mask)
if (! mask)
return 0;
while (!((mask >> i) & 1))
while (! ((mask >> i) & 1))
++i;
return i;
@ -2147,7 +2138,6 @@ load_dialog (GimpProcedure *procedure,
"load-mipmaps",
"flip-image",
"bc1-use-transparency",
"decode-images",
NULL);
gtk_box_set_spacing (GTK_BOX (vbox), 8);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);

View File

@ -35,13 +35,13 @@
#include <libgimp/stdplugins-intl.h>
#include "color.h"
#include "dds.h"
#include "ddswrite.h"
#include "dxt.h"
#include "endian_rw.h"
#include "imath.h"
#include "mipmap.h"
#include "misc.h"
static gboolean write_image (FILE *fp,
@ -244,7 +244,7 @@ check_cubemap (GimpImage *image)
(gimp_drawable_get_height (drawable) != h))
continue;
layer_name = (char *) gimp_item_get_name (GIMP_ITEM (drawable));
layer_name = (gchar *) gimp_item_get_name (GIMP_ITEM (drawable));
for (j = 0; j < 6; ++j)
{
for (k = 0; k < 4; ++k)
@ -608,45 +608,6 @@ swap_rb (guchar *pixels,
}
}
static void
alpha_exp (guchar *dst,
gint r,
gint g,
gint b,
gint a)
{
gfloat ar, ag, ab, aa;
ar = (gfloat) r / 255.0f;
ag = (gfloat) g / 255.0f;
ab = (gfloat) b / 255.0f;
aa = MAX (ar, MAX (ag, ab));
if (aa < 1e-04f)
{
dst[0] = b;
dst[1] = g;
dst[2] = r;
dst[3] = 255;
return;
}
ar /= aa;
ag /= aa;
ab /= aa;
r = (gint) floorf (255.0f * ar + 0.5f);
g = (gint) floorf (255.0f * ag + 0.5f);
b = (gint) floorf (255.0f * ab + 0.5f);
a = (gint) floorf (255.0f * aa + 0.5f);
dst[0] = MAX (0, MIN (255, b));
dst[1] = MAX (0, MIN (255, g));
dst[2] = MAX (0, MIN (255, r));
dst[3] = MAX (0, MIN (255, a));
}
static void
convert_pixels (guchar *dst,
guchar *src,
@ -729,36 +690,56 @@ convert_pixels (guchar *dst,
dst[4 * i + 3] = a;
break;
case DDS_FORMAT_R5G6B5:
PUTL16 (&dst[2 * i], pack_r5g6b5 (r, g, b));
PUTL16 (&dst[2 * i],
(mul8bit (r, 31) << 11) |
(mul8bit (g, 63) << 5) |
(mul8bit (b, 31) ));
break;
case DDS_FORMAT_RGBA4:
PUTL16 (&dst[2 * i], pack_rgba4 (r, g, b, a));
PUTL16 (&dst[2 * i],
(mul8bit (a, 15) << 12) |
(mul8bit (r, 15) << 8) |
(mul8bit (g, 15) << 4) |
(mul8bit (b, 15) ));
break;
case DDS_FORMAT_RGB5A1:
PUTL16 (&dst[2 * i], pack_rgb5a1 (r, g, b, a));
PUTL16 (&dst[2 * i],
(((a >> 7) & 0x01) << 15) |
(mul8bit (r, 31) << 10) |
(mul8bit (g, 31) << 5) |
(mul8bit (b, 31) ));
break;
case DDS_FORMAT_RGB10A2:
PUTL32 (&dst[4 * i], pack_rgb10a2 (r, g, b, a));
PUTL32 (&dst[4 * i],
((guint) ((a >> 6) & 0x003) << 30) |
((guint) ((b << 2) & 0x3ff) << 20) |
((guint) ((g << 2) & 0x3ff) << 10) |
((guint) ((r << 2) & 0x3ff) ));
break;
case DDS_FORMAT_R3G3B2:
dst[i] = pack_r3g3b2 (r, g, b);
dst[i] =
(mul8bit (r, 7) << 5) |
(mul8bit (g, 7) << 2) |
(mul8bit (b, 3) );
break;
case DDS_FORMAT_A8:
dst[i] = a;
break;
case DDS_FORMAT_L8:
dst[i] = rgb_to_luminance (r, g, b);
dst[i] =
((r * 54 + g * 182 + b * 20) + 128) >> 8;
break;
case DDS_FORMAT_L8A8:
dst[2 * i + 0] = rgb_to_luminance (r, g, b);
dst[2 * i + 0] =
((r * 54 + g * 182 + b * 20) + 128) >> 8;
dst[2 * i + 1] = a;
break;
case DDS_FORMAT_YCOCG:
dst[4 * i] = a;
RGB_to_YCoCg (&dst[4 * i], r, g, b);
encode_ycocg (&dst[4 * i], r, g, b);
break;
case DDS_FORMAT_AEXP:
alpha_exp (&dst[4 * i], r, g, b, a);
encode_alpha_exponent (&dst[4 * i], r, g, b, a);
break;
default:
break;

View File

@ -34,11 +34,14 @@
#include <math.h>
#include <glib.h>
#include <libgimp/gimp.h>
#include "dds.h"
#include "dxt.h"
#include "endian_rw.h"
#include "mipmap.h"
#include "imath.h"
#include "mipmap.h"
#include "misc.h"
#include "vec.h"
#include "dxt_tables.h"
@ -757,181 +760,6 @@ encode_color_block (unsigned char *dst,
PUTL32(dst + 4, indices);
}
static void
get_min_max_YCoCg (const unsigned char *block,
unsigned char *mincolor,
unsigned char *maxcolor)
{
int i;
mincolor[2] = mincolor[1] = 255;
maxcolor[2] = maxcolor[1] = 0;
for (i = 0; i < 16; ++i)
{
if (block[4 * i + 2] < mincolor[2]) mincolor[2] = block[4 * i + 2];
if (block[4 * i + 1] < mincolor[1]) mincolor[1] = block[4 * i + 1];
if (block[4 * i + 2] > maxcolor[2]) maxcolor[2] = block[4 * i + 2];
if (block[4 * i + 1] > maxcolor[1]) maxcolor[1] = block[4 * i + 1];
}
}
static void
scale_YCoCg (unsigned char *block,
unsigned char *mincolor,
unsigned char *maxcolor)
{
const int s0 = 128 / 2 - 1;
const int s1 = 128 / 4 - 1;
int m0, m1, m2, m3;
int mask0, mask1, scale;
int i;
m0 = abs(mincolor[2] - 128);
m1 = abs(mincolor[1] - 128);
m2 = abs(maxcolor[2] - 128);
m3 = abs(maxcolor[1] - 128);
if (m1 > m0) m0 = m1;
if (m3 > m2) m2 = m3;
if (m2 > m0) m0 = m2;
mask0 = -(m0 <= s0);
mask1 = -(m0 <= s1);
scale = 1 + (1 & mask0) + (2 & mask1);
mincolor[2] = (mincolor[2] - 128) * scale + 128;
mincolor[1] = (mincolor[1] - 128) * scale + 128;
mincolor[0] = (scale - 1) << 3;
maxcolor[2] = (maxcolor[2] - 128) * scale + 128;
maxcolor[1] = (maxcolor[1] - 128) * scale + 128;
maxcolor[0] = (scale - 1) << 3;
for (i = 0; i < 16; ++i)
{
block[i * 4 + 2] = (block[i * 4 + 2] - 128) * scale + 128;
block[i * 4 + 1] = (block[i * 4 + 1] - 128) * scale + 128;
}
}
#define INSET_SHIFT 4
static void
inset_bbox_YCoCg (unsigned char *mincolor,
unsigned char *maxcolor)
{
int inset[4], mini[4], maxi[4];
inset[2] = (maxcolor[2] - mincolor[2]) - ((1 << (INSET_SHIFT - 1)) - 1);
inset[1] = (maxcolor[1] - mincolor[1]) - ((1 << (INSET_SHIFT - 1)) - 1);
mini[2] = ((mincolor[2] << INSET_SHIFT) + inset[2]) >> INSET_SHIFT;
mini[1] = ((mincolor[1] << INSET_SHIFT) + inset[1]) >> INSET_SHIFT;
maxi[2] = ((maxcolor[2] << INSET_SHIFT) - inset[2]) >> INSET_SHIFT;
maxi[1] = ((maxcolor[1] << INSET_SHIFT) - inset[1]) >> INSET_SHIFT;
mini[2] = (mini[2] >= 0) ? mini[2] : 0;
mini[1] = (mini[1] >= 0) ? mini[1] : 0;
maxi[2] = (maxi[2] <= 255) ? maxi[2] : 255;
maxi[1] = (maxi[1] <= 255) ? maxi[1] : 255;
mincolor[2] = (mini[2] & 0xf8) | (mini[2] >> 5);
mincolor[1] = (mini[1] & 0xfc) | (mini[1] >> 6);
maxcolor[2] = (maxi[2] & 0xf8) | (maxi[2] >> 5);
maxcolor[1] = (maxi[1] & 0xfc) | (maxi[1] >> 6);
}
static void
select_diagonal_YCoCg (const unsigned char *block,
unsigned char *mincolor,
unsigned char *maxcolor)
{
unsigned char mid0, mid1, side, mask, b0, b1, c0, c1;
int i;
mid0 = ((int)mincolor[2] + maxcolor[2] + 1) >> 1;
mid1 = ((int)mincolor[1] + maxcolor[1] + 1) >> 1;
side = 0;
for (i = 0; i < 16; ++i)
{
b0 = block[i * 4 + 2] >= mid0;
b1 = block[i * 4 + 1] >= mid1;
side += (b0 ^ b1);
}
mask = -(side > 8);
mask &= -(mincolor[2] != maxcolor[2]);
c0 = mincolor[1];
c1 = maxcolor[1];
c0 ^= c1;
c1 ^= c0 & mask;
c0 ^= c1;
mincolor[1] = c0;
maxcolor[1] = c1;
}
static void
encode_YCoCg_block (unsigned char *dst,
unsigned char *block)
{
unsigned char colors[4][3], *maxcolor, *mincolor;
unsigned int mask;
int c0, c1, d0, d1, d2, d3;
int b0, b1, b2, b3, b4;
int x0, x1, x2;
int i, idx;
maxcolor = &colors[0][0];
mincolor = &colors[1][0];
get_min_max_YCoCg(block, mincolor, maxcolor);
scale_YCoCg(block, mincolor, maxcolor);
inset_bbox_YCoCg(mincolor, maxcolor);
select_diagonal_YCoCg(block, mincolor, maxcolor);
lerp_rgb13(&colors[2][0], maxcolor, mincolor);
lerp_rgb13(&colors[3][0], mincolor, maxcolor);
mask = 0;
for (i = 0; i < 16; ++i)
{
c0 = block[4 * i + 2];
c1 = block[4 * i + 1];
d0 = abs(colors[0][2] - c0) + abs(colors[0][1] - c1);
d1 = abs(colors[1][2] - c0) + abs(colors[1][1] - c1);
d2 = abs(colors[2][2] - c0) + abs(colors[2][1] - c1);
d3 = abs(colors[3][2] - c0) + abs(colors[3][1] - c1);
b0 = d0 > d3;
b1 = d1 > d2;
b2 = d0 > d2;
b3 = d1 > d3;
b4 = d2 > d3;
x0 = b1 & b2;
x1 = b0 & b3;
x2 = b0 & b4;
idx = (x2 | ((x0 | x1) << 1));
mask |= idx << (2 * i);
}
PUTL16(dst + 0, pack_rgb565(maxcolor));
PUTL16(dst + 2, pack_rgb565(mincolor));
PUTL32(dst + 4, mask);
}
/* write DXT3 alpha block */
static void
encode_alpha_block_BC2 (unsigned char *dst,

View File

@ -2,7 +2,6 @@ plugin_name = 'file-dds'
plugin_sources = [
'dds.c',
'color.c',
'ddsread.c',
'ddswrite.c',
'dxt.c',

View File

@ -36,7 +36,6 @@
#include "dds.h"
#include "mipmap.h"
#include "imath.h"
#include "color.h"
typedef gfloat (*filterfunc_t) (gfloat);
@ -217,6 +216,23 @@ wrap_clamp (gint x,
* Gamma-correction
*/
static gfloat
linear_to_sRGB (gfloat c)
{
gfloat v = (gfloat) c;
if (v < 0.0f)
v = 0.0f;
else if (v > 1.0f)
v = 1.0f;
else if (v <= 0.0031308f)
v = 12.92f * v;
else
v = 1.055f * powf (v, 0.41666f) - 0.055f;
return v;
}
static gfloat
linear_to_gamma (gint gc,
gfloat v,
@ -236,6 +252,24 @@ linear_to_gamma (gint gc,
return v;
}
static gfloat
sRGB_to_linear (gfloat c)
{
gfloat v = (gfloat) c;
if (v < 0.0f)
v = 0.0f;
else if (v > 1.0f)
v = 1.0f;
else if (v <= 0.04045f)
v /= 12.92f;
else
v = powf ((v + 0.055f) / 1.055f, 2.4f);
return v;
}
static gfloat
gamma_to_linear (gint gc,
gfloat v,

View File

@ -4,56 +4,53 @@
* Copyright (C) 2004-2012 Shawn Kirst <skirst@gmail.com>,
* with parts (C) 2003 Arne Reuter <homepage@arnereuter.de> where specified.
*
* 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 2 of the License, or (at your option) any later version.
* 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.
* 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; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301, USA.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <libgimp/gimp.h>
#include "endian_rw.h"
#include "imath.h"
#include "misc.h"
static inline float
saturate (float a)
{
if(a < 0) a = 0;
if(a > 1) a = 1;
/*
* Decoding Functions
*/
static inline gfloat
saturate (gfloat a)
{
if (a < 0) a = 0;
if (a > 1) a = 1;
return a;
}
void
decode_ycocg_image (GimpDrawable *drawable,
gboolean shadow)
decode_ycocg (GimpDrawable *drawable)
{
GeglBuffer *buffer, *sbuffer;
GeglBuffer *buffer;
const Babl *format;
unsigned char *data;
unsigned int i, w, h, num_pixels;
const float offset = 0.5f * 256.0f / 255.0f;
float Y, Co, Cg, R, G, B;
guchar *data;
guint num_pixels;
guint i, w, h;
const gfloat offset = 0.5f * 256.0f / 255.0f;
gfloat Y, Co, Cg;
gfloat R, G, B;
buffer = gimp_drawable_get_buffer (drawable);
if (shadow)
{
sbuffer = gimp_drawable_get_shadow_buffer (drawable);
gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, sbuffer, NULL);
g_object_unref (buffer);
buffer = sbuffer;
}
format = babl_format ("R'G'B'A u8");
w = gegl_buffer_get_width (buffer);
@ -62,46 +59,43 @@ decode_ycocg_image (GimpDrawable *drawable,
data = g_malloc (num_pixels * 4);
gegl_buffer_get (buffer, GEGL_RECTANGLE(0, 0, w, h), 1.0, format, data,
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, data,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gimp_progress_init ("Decoding YCoCg pixels...");
for (i = 0; i < num_pixels; ++i)
{
Y = (float)data[4 * i + 3] / 255.0f;
Co = (float)data[4 * i + 0] / 255.0f;
Cg = (float)data[4 * i + 1] / 255.0f;
Y = (gfloat) data[4 * i + 3] / 255.0f;
Co = (gfloat) data[4 * i + 0] / 255.0f;
Cg = (gfloat) data[4 * i + 1] / 255.0f;
/* convert YCoCg to RGB */
Co -= offset;
Cg -= offset;
R = saturate(Y + Co - Cg);
G = saturate(Y + Cg);
B = saturate(Y - Co - Cg);
R = saturate (Y + Co - Cg);
G = saturate (Y + Cg);
B = saturate (Y - Co - Cg);
/* copy new alpha from blue */
data[4 * i + 3] = data[4 * i + 2];
data[4 * i + 0] = (unsigned char)(R * 255.0f);
data[4 * i + 1] = (unsigned char)(G * 255.0f);
data[4 * i + 2] = (unsigned char)(B * 255.0f);
data[4 * i + 0] = (guchar) (R * 255.0f);
data[4 * i + 1] = (guchar) (G * 255.0f);
data[4 * i + 2] = (guchar) (B * 255.0f);
if ((i & 0x7fff) == 0)
gimp_progress_update ((float)i / (float)num_pixels);
gimp_progress_update ((gdouble) i / (gdouble) num_pixels);
}
gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data,
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, w, h), 0, format, data,
GEGL_AUTO_ROWSTRIDE);
gimp_progress_update (1.0);
gegl_buffer_flush (buffer);
if (shadow)
gimp_drawable_merge_shadow (drawable, TRUE);
gimp_drawable_update (drawable, 0, 0, w, h);
g_free (data);
@ -110,27 +104,19 @@ decode_ycocg_image (GimpDrawable *drawable,
}
void
decode_ycocg_scaled_image (GimpDrawable *drawable,
gboolean shadow)
decode_ycocg_scaled (GimpDrawable *drawable)
{
GeglBuffer *buffer, *sbuffer;
GeglBuffer *buffer;
const Babl *format;
unsigned char *data;
unsigned int i, w, h, num_pixels;
const float offset = 0.5f * 256.0f / 255.0f;
float Y, Co, Cg, R, G, B, s;
guchar *data;
guint num_pixels;
guint i, w, h;
const gfloat offset = 0.5f * 256.0f / 255.0f;
gfloat Y, Co, Cg;
gfloat R, G, B, s;
buffer = gimp_drawable_get_buffer (drawable);
if (shadow)
{
sbuffer = gimp_drawable_get_shadow_buffer (drawable);
gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, sbuffer, NULL);
g_object_unref (buffer);
buffer = sbuffer;
}
format = babl_format ("R'G'B'A u8");
w = gegl_buffer_get_width (buffer);
@ -139,17 +125,17 @@ decode_ycocg_scaled_image (GimpDrawable *drawable,
data = g_malloc (num_pixels * 4);
gegl_buffer_get (buffer, GEGL_RECTANGLE(0, 0, w, h), 1.0, format, data,
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, data,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gimp_progress_init ("Decoding YCoCg (scaled) pixels...");
for (i = 0; i < num_pixels; ++i)
{
Y = (float)data[4 * i + 3] / 255.0f;
Co = (float)data[4 * i + 0] / 255.0f;
Cg = (float)data[4 * i + 1] / 255.0f;
s = (float)data[4 * i + 2] / 255.0f;
Y = (gfloat) data[4 * i + 3] / 255.0f;
Co = (gfloat) data[4 * i + 0] / 255.0f;
Cg = (gfloat) data[4 * i + 1] / 255.0f;
s = (gfloat) data[4 * i + 2] / 255.0f;
/* convert YCoCg to RGB */
s = 1.0f / ((255.0f / 8.0f) * s + 1.0f);
@ -157,31 +143,28 @@ decode_ycocg_scaled_image (GimpDrawable *drawable,
Co = (Co - offset) * s;
Cg = (Cg - offset) * s;
R = saturate(Y + Co - Cg);
G = saturate(Y + Cg);
B = saturate(Y - Co - Cg);
R = saturate (Y + Co - Cg);
G = saturate (Y + Cg);
B = saturate (Y - Co - Cg);
data[4 * i + 0] = (unsigned char)(R * 255.0f);
data[4 * i + 1] = (unsigned char)(G * 255.0f);
data[4 * i + 2] = (unsigned char)(B * 255.0f);
data[4 * i + 0] = (guchar) (R * 255.0f);
data[4 * i + 1] = (guchar) (G * 255.0f);
data[4 * i + 2] = (guchar) (B * 255.0f);
/* set alpha to 1 */
data[4 * i + 3] = 255;
if ((i & 0x7fff) == 0)
gimp_progress_update ((float)i / (float)num_pixels);
gimp_progress_update ((gdouble) i / (gdouble) num_pixels);
}
gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data,
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, w, h), 0, format, data,
GEGL_AUTO_ROWSTRIDE);
gimp_progress_update (1.0);
gegl_buffer_flush (buffer);
if (shadow)
gimp_drawable_merge_shadow (drawable, TRUE);
gimp_drawable_update (drawable, 0, 0, w, h);
g_free (data);
@ -190,25 +173,17 @@ decode_ycocg_scaled_image (GimpDrawable *drawable,
}
void
decode_alpha_exp_image (GimpDrawable *drawable,
gboolean shadow)
decode_alpha_exponent (GimpDrawable *drawable)
{
GeglBuffer *buffer, *sbuffer;
GeglBuffer *buffer;
const Babl *format;
unsigned char *data;
unsigned int i, w, h, num_pixels;
int R, G, B, A;
guchar *data;
guint num_pixels;
guint i, w, h;
gint R, G, B, A;
buffer = gimp_drawable_get_buffer (drawable);
if (shadow)
{
sbuffer = gimp_drawable_get_shadow_buffer (drawable);
gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, sbuffer, NULL);
g_object_unref (buffer);
buffer = sbuffer;
}
format = babl_format ("R'G'B'A u8");
w = gegl_buffer_get_width (buffer);
@ -217,7 +192,7 @@ decode_alpha_exp_image (GimpDrawable *drawable,
data = g_malloc (num_pixels * 4);
gegl_buffer_get (buffer, GEGL_RECTANGLE(0, 0, w, h), 1.0, format, data,
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, data,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gimp_progress_init ("Decoding Alpha-exponent pixels...");
@ -240,22 +215,268 @@ decode_alpha_exp_image (GimpDrawable *drawable,
data[4 * i + 3] = A;
if ((i & 0x7fff) == 0)
gimp_progress_update ((float)i / (float)num_pixels);
gimp_progress_update ((gdouble) i / (gdouble) num_pixels);
}
gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data,
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, w, h), 0, format, data,
GEGL_AUTO_ROWSTRIDE);
gimp_progress_update (1.0);
gegl_buffer_flush (buffer);
if (shadow)
gimp_drawable_merge_shadow (drawable, TRUE);
gimp_drawable_update (drawable, 0, 0, w, h);
g_free (data);
g_object_unref (buffer);
}
/*
* Encoding Functions
*/
void
encode_ycocg (guchar *dst,
gint r,
gint g,
gint b)
{
gint y = ((r + (g << 1) + b) + 2) >> 2;
gint co = ((((r << 1) - (b << 1)) + 2) >> 2) + 128;
gint cg = (((-r + (g << 1) - b) + 2) >> 2) + 128;
dst[0] = 255;
dst[1] = (cg > 255 ? 255 : (cg < 0 ? 0 : cg));
dst[2] = (co > 255 ? 255 : (co < 0 ? 0 : co));
dst[3] = (y > 255 ? 255 : (y < 0 ? 0 : y));
}
void
encode_alpha_exponent (guchar *dst,
gint r,
gint g,
gint b,
gint a)
{
gfloat ar, ag, ab, aa;
ar = (gfloat) r / 255.0f;
ag = (gfloat) g / 255.0f;
ab = (gfloat) b / 255.0f;
aa = MAX (ar, MAX (ag, ab));
if (aa < 1e-04f)
{
dst[0] = b;
dst[1] = g;
dst[2] = r;
dst[3] = 255;
return;
}
ar /= aa;
ag /= aa;
ab /= aa;
r = (gint) floorf (255.0f * ar + 0.5f);
g = (gint) floorf (255.0f * ag + 0.5f);
b = (gint) floorf (255.0f * ab + 0.5f);
a = (gint) floorf (255.0f * aa + 0.5f);
dst[0] = MAX (0, MIN (255, b));
dst[1] = MAX (0, MIN (255, g));
dst[2] = MAX (0, MIN (255, r));
dst[3] = MAX (0, MIN (255, a));
}
/*
* Compression Functions
*/
static void
get_min_max_YCoCg (const guchar *block,
guchar *mincolor,
guchar *maxcolor)
{
gint i;
mincolor[2] = mincolor[1] = 255;
maxcolor[2] = maxcolor[1] = 0;
for (i = 0; i < 16; ++i)
{
if (block[4 * i + 2] < mincolor[2]) mincolor[2] = block[4 * i + 2];
if (block[4 * i + 1] < mincolor[1]) mincolor[1] = block[4 * i + 1];
if (block[4 * i + 2] > maxcolor[2]) maxcolor[2] = block[4 * i + 2];
if (block[4 * i + 1] > maxcolor[1]) maxcolor[1] = block[4 * i + 1];
}
}
static void
scale_YCoCg (guchar *block,
guchar *mincolor,
guchar *maxcolor)
{
const gint s0 = 128 / 2 - 1;
const gint s1 = 128 / 4 - 1;
gint m0, m1, m2, m3;
gint mask0, mask1, scale;
gint i;
m0 = abs (mincolor[2] - 128);
m1 = abs (mincolor[1] - 128);
m2 = abs (maxcolor[2] - 128);
m3 = abs (maxcolor[1] - 128);
if (m1 > m0) m0 = m1;
if (m3 > m2) m2 = m3;
if (m2 > m0) m0 = m2;
mask0 = -(m0 <= s0);
mask1 = -(m0 <= s1);
scale = 1 + (1 & mask0) + (2 & mask1);
mincolor[2] = (mincolor[2] - 128) * scale + 128;
mincolor[1] = (mincolor[1] - 128) * scale + 128;
mincolor[0] = (scale - 1) << 3;
maxcolor[2] = (maxcolor[2] - 128) * scale + 128;
maxcolor[1] = (maxcolor[1] - 128) * scale + 128;
maxcolor[0] = (scale - 1) << 3;
for (i = 0; i < 16; ++i)
{
block[i * 4 + 2] = (block[i * 4 + 2] - 128) * scale + 128;
block[i * 4 + 1] = (block[i * 4 + 1] - 128) * scale + 128;
}
}
#define INSET_SHIFT 4
static void
inset_bbox_YCoCg (guchar *mincolor,
guchar *maxcolor)
{
gint inset[4], mini[4], maxi[4];
inset[2] = (maxcolor[2] - mincolor[2]) - ((1 << (INSET_SHIFT - 1)) - 1);
inset[1] = (maxcolor[1] - mincolor[1]) - ((1 << (INSET_SHIFT - 1)) - 1);
mini[2] = ((mincolor[2] << INSET_SHIFT) + inset[2]) >> INSET_SHIFT;
mini[1] = ((mincolor[1] << INSET_SHIFT) + inset[1]) >> INSET_SHIFT;
maxi[2] = ((maxcolor[2] << INSET_SHIFT) - inset[2]) >> INSET_SHIFT;
maxi[1] = ((maxcolor[1] << INSET_SHIFT) - inset[1]) >> INSET_SHIFT;
mini[2] = (mini[2] >= 0) ? mini[2] : 0;
mini[1] = (mini[1] >= 0) ? mini[1] : 0;
maxi[2] = (maxi[2] <= 255) ? maxi[2] : 255;
maxi[1] = (maxi[1] <= 255) ? maxi[1] : 255;
mincolor[2] = (mini[2] & 0xf8) | (mini[2] >> 5);
mincolor[1] = (mini[1] & 0xfc) | (mini[1] >> 6);
maxcolor[2] = (maxi[2] & 0xf8) | (maxi[2] >> 5);
maxcolor[1] = (maxi[1] & 0xfc) | (maxi[1] >> 6);
}
static void
select_diagonal_YCoCg (const guchar *block,
guchar *mincolor,
guchar *maxcolor)
{
guchar mid0, mid1, side, mask, b0, b1, c0, c1;
gint i;
mid0 = ((gint) mincolor[2] + maxcolor[2] + 1) >> 1;
mid1 = ((gint) mincolor[1] + maxcolor[1] + 1) >> 1;
side = 0;
for (i = 0; i < 16; ++i)
{
b0 = block[i * 4 + 2] >= mid0;
b1 = block[i * 4 + 1] >= mid1;
side += (b0 ^ b1);
}
mask = -(side > 8);
mask &= -(mincolor[2] != maxcolor[2]);
c0 = mincolor[1];
c1 = maxcolor[1];
c0 ^= c1;
c1 ^= c0 & mask;
c0 ^= c1;
mincolor[1] = c0;
maxcolor[1] = c1;
}
void
encode_YCoCg_block (guchar *dst,
guchar *block)
{
guchar colors[4][3], *maxcolor, *mincolor;
guint mask;
gint c0, c1, d0, d1, d2, d3;
gint b0, b1, b2, b3, b4;
gint x0, x1, x2;
gint i, idx;
maxcolor = &colors[0][0];
mincolor = &colors[1][0];
get_min_max_YCoCg (block, mincolor, maxcolor);
scale_YCoCg (block, mincolor, maxcolor);
inset_bbox_YCoCg (mincolor, maxcolor);
select_diagonal_YCoCg (block, mincolor, maxcolor);
colors[2][0] = (2 * maxcolor[0] + mincolor[0]) / 3;
colors[2][1] = (2 * maxcolor[1] + mincolor[1]) / 3;
colors[2][2] = (2 * maxcolor[2] + mincolor[2]) / 3;
colors[3][0] = (2 * mincolor[0] + maxcolor[0]) / 3;
colors[3][1] = (2 * mincolor[1] + maxcolor[1]) / 3;
colors[3][2] = (2 * mincolor[2] + maxcolor[2]) / 3;
mask = 0;
for (i = 0; i < 16; ++i)
{
c0 = block[4 * i + 2];
c1 = block[4 * i + 1];
d0 = abs (colors[0][2] - c0) + abs (colors[0][1] - c1);
d1 = abs (colors[1][2] - c0) + abs (colors[1][1] - c1);
d2 = abs (colors[2][2] - c0) + abs (colors[2][1] - c1);
d3 = abs (colors[3][2] - c0) + abs (colors[3][1] - c1);
b0 = d0 > d3;
b1 = d1 > d2;
b2 = d0 > d2;
b3 = d1 > d3;
b4 = d2 > d3;
x0 = b1 & b2;
x1 = b0 & b3;
x2 = b0 & b4;
idx = (x2 | ((x0 | x1) << 1));
mask |= idx << (2 * i);
}
PUTL16 (dst + 0, (mul8bit (maxcolor[2], 31) << 11) |
(mul8bit (maxcolor[1], 63) << 5) |
(mul8bit (maxcolor[0], 31) ));
PUTL16 (dst + 2, (mul8bit (mincolor[2], 31) << 11) |
(mul8bit (mincolor[1], 63) << 5) |
(mul8bit (mincolor[0], 31) ));
PUTL32 (dst + 4, mask);
}

View File

@ -21,11 +21,26 @@
#ifndef __MISC_H__
#define __MISC_H__
void decode_ycocg_image (GimpDrawable *drawable,
gboolean shadow);
void decode_ycocg_scaled_image (GimpDrawable *drawable,
gboolean shadow);
void decode_alpha_exp_image (GimpDrawable *drawable,
gboolean shadow);
void decode_ycocg (GimpDrawable *drawable);
void decode_ycocg_scaled (GimpDrawable *drawable);
void decode_alpha_exponent (GimpDrawable *drawable);
void encode_ycocg (guchar *dst,
gint r,
gint g,
gint b);
void encode_alpha_exponent (guchar *dst,
gint r,
gint g,
gint b,
gint a);
void encode_YCoCg_block (guchar *dst,
guchar *block);
#endif /* __MISC_H__ */