262 lines
6.5 KiB
C
262 lines
6.5 KiB
C
|
/*
|
||
|
* DDS PIKA 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 <libpika/pika.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 (PikaDrawable *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 = pika_drawable_get_buffer (drawable);
|
||
|
|
||
|
if (shadow)
|
||
|
{
|
||
|
sbuffer = pika_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);
|
||
|
|
||
|
pika_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)
|
||
|
pika_progress_update ((float)i / (float)num_pixels);
|
||
|
}
|
||
|
|
||
|
gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data,
|
||
|
GEGL_AUTO_ROWSTRIDE);
|
||
|
|
||
|
pika_progress_update (1.0);
|
||
|
|
||
|
gegl_buffer_flush (buffer);
|
||
|
|
||
|
if (shadow)
|
||
|
pika_drawable_merge_shadow (drawable, TRUE);
|
||
|
|
||
|
pika_drawable_update (drawable, 0, 0, w, h);
|
||
|
|
||
|
g_free (data);
|
||
|
|
||
|
g_object_unref (buffer);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
decode_ycocg_scaled_image (PikaDrawable *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 = pika_drawable_get_buffer (drawable);
|
||
|
|
||
|
if (shadow)
|
||
|
{
|
||
|
sbuffer = pika_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);
|
||
|
|
||
|
pika_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)
|
||
|
pika_progress_update ((float)i / (float)num_pixels);
|
||
|
}
|
||
|
|
||
|
gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data,
|
||
|
GEGL_AUTO_ROWSTRIDE);
|
||
|
|
||
|
pika_progress_update (1.0);
|
||
|
|
||
|
gegl_buffer_flush (buffer);
|
||
|
|
||
|
if (shadow)
|
||
|
pika_drawable_merge_shadow (drawable, TRUE);
|
||
|
|
||
|
pika_drawable_update (drawable, 0, 0, w, h);
|
||
|
|
||
|
g_free (data);
|
||
|
|
||
|
g_object_unref (buffer);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
decode_alpha_exp_image (PikaDrawable *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 = pika_drawable_get_buffer (drawable);
|
||
|
|
||
|
if (shadow)
|
||
|
{
|
||
|
sbuffer = pika_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);
|
||
|
|
||
|
pika_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)
|
||
|
pika_progress_update ((float)i / (float)num_pixels);
|
||
|
}
|
||
|
|
||
|
gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data,
|
||
|
GEGL_AUTO_ROWSTRIDE);
|
||
|
|
||
|
pika_progress_update (1.0);
|
||
|
|
||
|
gegl_buffer_flush (buffer);
|
||
|
|
||
|
if (shadow)
|
||
|
pika_drawable_merge_shadow (drawable, TRUE);
|
||
|
|
||
|
pika_drawable_update (drawable, 0, 0, w, h);
|
||
|
|
||
|
g_free (data);
|
||
|
|
||
|
g_object_unref (buffer);
|
||
|
}
|