forked from openkylin/gimp
262 lines
6.5 KiB
C
262 lines
6.5 KiB
C
/*
|
|
* 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 <libgimp/gimp.h>
|
|
#include "misc.h"
|
|
|
|
static inline float
|
|
saturate (float a)
|
|
{
|
|
if(a < 0) a = 0;
|
|
if(a > 1) a = 1;
|
|
|
|
return a;
|
|
}
|
|
|
|
void
|
|
decode_ycocg_image (gint32 drawableID,
|
|
gboolean shadow)
|
|
{
|
|
GeglBuffer *buffer, *sbuffer;
|
|
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;
|
|
|
|
buffer = gimp_drawable_get_buffer (drawableID);
|
|
|
|
if (shadow)
|
|
{
|
|
sbuffer = gimp_drawable_get_shadow_buffer (drawableID);
|
|
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);
|
|
h = gegl_buffer_get_height (buffer);
|
|
num_pixels = w * h;
|
|
|
|
data = g_malloc (num_pixels * 4);
|
|
|
|
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;
|
|
|
|
/* convert YCoCg to RGB */
|
|
Co -= offset;
|
|
Cg -= offset;
|
|
|
|
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);
|
|
|
|
if ((i & 0x7fff) == 0)
|
|
gimp_progress_update ((float)i / (float)num_pixels);
|
|
}
|
|
|
|
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 (drawableID, TRUE);
|
|
|
|
gimp_drawable_update (drawableID, 0, 0, w, h);
|
|
|
|
g_free (data);
|
|
|
|
g_object_unref (buffer);
|
|
}
|
|
|
|
void
|
|
decode_ycocg_scaled_image (gint32 drawableID,
|
|
gboolean shadow)
|
|
{
|
|
GeglBuffer *buffer, *sbuffer;
|
|
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;
|
|
|
|
buffer = gimp_drawable_get_buffer (drawableID);
|
|
|
|
if (shadow)
|
|
{
|
|
sbuffer = gimp_drawable_get_shadow_buffer(drawableID);
|
|
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);
|
|
h = gegl_buffer_get_height (buffer);
|
|
num_pixels = w * h;
|
|
|
|
data = g_malloc (num_pixels * 4);
|
|
|
|
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;
|
|
|
|
/* convert YCoCg to RGB */
|
|
s = 1.0f / ((255.0f / 8.0f) * s + 1.0f);
|
|
|
|
Co = (Co - offset) * s;
|
|
Cg = (Cg - offset) * s;
|
|
|
|
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);
|
|
|
|
/* set alpha to 1 */
|
|
data[4 * i + 3] = 255;
|
|
|
|
if ((i & 0x7fff) == 0)
|
|
gimp_progress_update ((float)i / (float)num_pixels);
|
|
}
|
|
|
|
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 (drawableID, TRUE);
|
|
|
|
gimp_drawable_update (drawableID, 0, 0, w, h);
|
|
|
|
g_free (data);
|
|
|
|
g_object_unref (buffer);
|
|
}
|
|
|
|
void
|
|
decode_alpha_exp_image (gint32 drawableID,
|
|
gboolean shadow)
|
|
{
|
|
GeglBuffer *buffer, *sbuffer;
|
|
const Babl *format;
|
|
unsigned char *data;
|
|
unsigned int i, w, h, num_pixels;
|
|
int R, G, B, A;
|
|
|
|
buffer = gimp_drawable_get_buffer (drawableID);
|
|
|
|
if (shadow)
|
|
{
|
|
sbuffer = gimp_drawable_get_shadow_buffer (drawableID);
|
|
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);
|
|
h = gegl_buffer_get_height (buffer);
|
|
num_pixels = w * h;
|
|
|
|
data = g_malloc (num_pixels * 4);
|
|
|
|
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...");
|
|
|
|
for (i = 0; i < num_pixels; ++i)
|
|
{
|
|
R = data[4 * i + 0];
|
|
G = data[4 * i + 1];
|
|
B = data[4 * i + 2];
|
|
A = data[4 * i + 3];
|
|
|
|
R = (R * A + 1) >> 8;
|
|
G = (G * A + 1) >> 8;
|
|
B = (B * A + 1) >> 8;
|
|
A = 255;
|
|
|
|
data[4 * i + 0] = R;
|
|
data[4 * i + 1] = G;
|
|
data[4 * i + 2] = B;
|
|
data[4 * i + 3] = A;
|
|
|
|
if ((i & 0x7fff) == 0)
|
|
gimp_progress_update ((float)i / (float)num_pixels);
|
|
}
|
|
|
|
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 (drawableID, TRUE);
|
|
|
|
gimp_drawable_update (drawableID, 0, 0, w, h);
|
|
|
|
g_free (data);
|
|
|
|
g_object_unref (buffer);
|
|
}
|