Files
gimp/plug-ins/file-dds/misc.c

254 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);
}