gimp/plug-ins/file-dds/misc.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 (GimpDrawable *drawable,
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 (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);
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 (drawable, TRUE);
gimp_drawable_update (drawable, 0, 0, w, h);
g_free (data);
g_object_unref (buffer);
}
void
decode_ycocg_scaled_image (GimpDrawable *drawable,
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 (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);
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 (drawable, TRUE);
gimp_drawable_update (drawable, 0, 0, w, h);
g_free (data);
g_object_unref (buffer);
}
void
decode_alpha_exp_image (GimpDrawable *drawable,
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 (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);
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 (drawable, TRUE);
gimp_drawable_update (drawable, 0, 0, w, h);
g_free (data);
g_object_unref (buffer);
}