Browse Source

image: start to implement some conversions between pixel spaces.

undefined
Sam Hocevar 10 years ago
parent
commit
eac62b436b
4 changed files with 113 additions and 263 deletions
  1. +2
    -1
      TODO
  2. +1
    -1
      src/Makefile.am
  3. +1
    -25
      src/image/image.cpp
  4. +109
    -236
      src/image/pixels.cpp

+ 2
- 1
TODO View File

@@ -10,6 +10,8 @@

Image:
- Handle pitch in SDL codec (and all others, actually)
- Fix the Floyd-Steinberg ode in pixels.cpp
- Add gamma handling in pixels.cpp
- port libpipi files:
· accessors.cpp
· analysis/histogram.cpp
@@ -55,7 +57,6 @@ Image:
· pipi-stubs.h
· pipi-template.h
· pipi-types.h
· pixels.cpp
· quantize/reduce.cpp
· resample/bicubic.cpp
· resample/bresenham.cpp


+ 1
- 1
src/Makefile.am View File

@@ -110,7 +110,7 @@ liblolcore_sources = \
sys/init.cpp sys/timer.cpp sys/file.cpp \
sys/thread.cpp sys/threadbase.h \
\
image/image.cpp image/image-private.h image/stock.cpp \
image/image.cpp image/image-private.h image/stock.cpp image/pixels.cpp \
image/codec/gdiplus-image.cpp image/codec/imlib2-image.cpp \
image/codec/sdl-image.cpp image/codec/ios-image.cpp \
image/codec/zed-image.cpp image/codec/zed-palette-image.cpp \


+ 1
- 25
src/image/image.cpp View File

@@ -1,7 +1,7 @@
//
// Lol Engine
//
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
@@ -169,30 +169,6 @@ void Image::SetSize(ivec2 size)
}
}

PixelFormat Image::GetFormat() const
{
return m_data->m_format;
}

void Image::SetFormat(PixelFormat fmt)
{
/* If we never used this format, allocate a new buffer: we will
* obviously need it. */
if (m_data->m_pixels[(int)fmt] == nullptr)
{
int bytes = m_data->m_size.x * m_data->m_size.y * BytesPerPixel(fmt);
m_data->m_pixels[(int)fmt] = new uint8_t[bytes];
}

/* If the requested format is different from the current format, and if
* the current format is a valid format, convert pixels. */
if (fmt != m_data->m_format && m_data->m_format != PixelFormat::Unknown)
{
/* TODO: convert data */
}
m_data->m_format = fmt;
}

/* The Lock() method */
template<PixelFormat T> typename PixelType<T>::type *Image::Lock()
{


+ 109
- 236
src/image/pixels.cpp View File

@@ -1,285 +1,158 @@
/*
* libpipi Pathetic image processing interface library
* Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This library is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/

/*
* pixels.c: pixel-level image manipulation
*/

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <math.h>
//
// Lol Engine
//
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
//

#if defined HAVE_CONFIG_H
# include "config.h"
#endif

#include "core.h"
#include "image-private.h"

namespace lol
{

#include "pipi.h"
#include "pipi-internals.h"
static vec4 u8tof32(u8vec4 pixel)
{
//vec4 ret;
//ret.r = pow((float)pixel.r / 255.f, global_gamma);
//ret.g = pow((float)pixel.g / 255.f, global_gamma);
//ret.b = pow((float)pixel.b / 255.f, global_gamma);
return (vec4)pixel / 255.f;
}

static void init_tables(void);
static u8vec4 f32tou8(vec4 pixel)
{
return (u8vec4)(pixel * 255.99f);
}

static double global_gamma = 2.2;
static int done = 0;
/*
* Pixel-level image manipulation
*/

static float u8tof32_table[256];
static inline float u8tof32(uint8_t p) { return u8tof32_table[(int)p]; }
PixelFormat Image::GetFormat() const
{
return m_data->m_format;
}

/* Return a direct pointer to an image's pixels. */
pipi_pixels_t *pipi_get_pixels(pipi_image_t *img, pipi_format_t type)
void Image::SetFormat(PixelFormat fmt)
{
size_t bytes = 0;
int x, y, i, bpp = 0;
ivec2 size = GetSize();
int count = size.x * size.y;

if(type < 0 || type >= PIPI_PIXELS_MAX)
return NULL;
/* Set the new active pixel format */
PixelFormat old_fmt = m_data->m_format;
m_data->m_format = fmt;

if(img->last_modified == type)
return &img->p[type];
/* If we never used this format, allocate a new buffer: we will
* obviously need it. */
if (m_data->m_pixels[(int)fmt] == nullptr)
{
m_data->m_pixels[(int)fmt] = new uint8_t[count * BytesPerPixel(fmt)];
}

/* Handle special cases */
if(type == PIPI_PIXELS_MASK_U8)
return &img->p[type];
/* If the requested format is already the current format, or if the
* current format is invalid, there is nothing to convert. */
if (fmt == old_fmt || old_fmt == PixelFormat::Unknown)
return;

#if 0
/* Preliminary conversions */
if(img->last_modified == PIPI_PIXELS_RGBA_U8
&& type == PIPI_PIXELS_Y_F32)
pipi_get_pixels(img, PIPI_PIXELS_RGBA_F32);
else if(img->last_modified == PIPI_PIXELS_BGR_U8
&& type == PIPI_PIXELS_Y_F32)
pipi_get_pixels(img, PIPI_PIXELS_RGBA_F32);
else if(img->last_modified == PIPI_PIXELS_Y_F32
&& type == PIPI_PIXELS_RGBA_U8)
pipi_get_pixels(img, PIPI_PIXELS_RGBA_F32);
else if(img->last_modified == PIPI_PIXELS_Y_F32
&& type == PIPI_PIXELS_BGR_U8)
pipi_get_pixels(img, PIPI_PIXELS_RGBA_F32);

/* Allocate pixels if necessary */
if(!img->p[type].pixels)
{
switch(type)
{
case PIPI_PIXELS_RGBA_U8:
bytes = img->w * img->h * 4 * sizeof(uint8_t);
bpp = 4 * sizeof(uint8_t);
break;
case PIPI_PIXELS_BGR_U8:
bytes = img->w * img->h * 3 * sizeof(uint8_t);
bpp = 3 * sizeof(uint8_t);
break;
case PIPI_PIXELS_RGBA_F32:
bytes = img->w * img->h * 4 * sizeof(float);
bpp = 4 * sizeof(float);
break;
case PIPI_PIXELS_Y_F32:
bytes = img->w * img->h * sizeof(float);
bpp = sizeof(float);
break;
default:
return NULL;
}

img->p[type].pixels = malloc(bytes);
img->p[type].bytes = bytes;
img->p[type].bpp = bpp;
img->p[type].w = img->w;
img->p[type].h = img->h;
}
if (old_fmt == PixelFormat::RGBA_8 && fmt == PixelFormat::Y_F32)
pipi_get_pixels(img, PixelFormat::RGBA_F32);
else if (old_fmt == PixelFormat::BGR_U8 && fmt == PixelFormat::Y_F32)
pipi_get_pixels(img, PixelFormat::RGBA_F32);
else if (old_fmt == PixelFormat::Y_F32 && fmt == PixelFormat::RGBA_8)
pipi_get_pixels(img, PixelFormat::RGBA_F32);
else if (old_fmt == PixelFormat::Y_F32 && fmt == PixelFormat::BGR_U8)
pipi_get_pixels(img, PixelFormat::RGBA_F32);
#endif

/* Convert pixels */
if(img->last_modified == PIPI_PIXELS_RGBA_U8
&& type == PIPI_PIXELS_RGBA_F32)
if (old_fmt == PixelFormat::RGBA_8 && fmt == PixelFormat::RGBA_F32)
{
uint8_t *src = (uint8_t *)img->p[PIPI_PIXELS_RGBA_U8].pixels;
float *dest = (float *)img->p[type].pixels;

init_tables();
u8vec4 *src = (u8vec4 *)m_data->m_pixels[(int)old_fmt];
vec4 *dest = (vec4 *)m_data->m_pixels[(int)fmt];

for(y = 0; y < img->h; y++)
for(x = 0; x < img->w; x++)
for(i = 0; i < 4; i++)
dest[4 * (y * img->w + x) + i]
= u8tof32(src[4 * (y * img->w + x) + i]);
for (int n = 0; n < count; ++n)
dest[n] = u8tof32(src[n]);
}
else if(img->last_modified == PIPI_PIXELS_BGR_U8
&& type == PIPI_PIXELS_RGBA_F32)
else if (old_fmt == PixelFormat::RGB_8 && fmt == PixelFormat::RGBA_F32)
{
uint8_t *src = (uint8_t *)img->p[PIPI_PIXELS_BGR_U8].pixels;
float *dest = (float *)img->p[type].pixels;
u8vec3 *src = (u8vec3 *)m_data->m_pixels[(int)old_fmt];
vec4 *dest = (vec4 *)m_data->m_pixels[(int)fmt];

init_tables();

for(y = 0; y < img->h; y++)
for(x = 0; x < img->w; x++)
{
dest[4 * (y * img->w + x)]
= u8tof32(src[3 * (y * img->w + x) + 2]);
dest[4 * (y * img->w + x) + 1]
= u8tof32(src[3 * (y * img->w + x) + 1]);
dest[4 * (y * img->w + x) + 2]
= u8tof32(src[3 * (y * img->w + x)]);
dest[4 * (y * img->w + x) + 3] = 1.0;
}
for (int n = 0; n < count; ++n)
dest[n] = u8tof32(u8vec4(src[n], 255));
}
else if(img->last_modified == PIPI_PIXELS_RGBA_F32
&& type == PIPI_PIXELS_RGBA_U8)
else if (old_fmt == PixelFormat::RGBA_F32 && fmt == PixelFormat::RGBA_8)
{
float *src = (float *)img->p[PIPI_PIXELS_RGBA_F32].pixels;
uint8_t *dest = (uint8_t *)img->p[type].pixels;
vec4 *src = (vec4 *)m_data->m_pixels[(int)old_fmt];
u8vec4 *dest = (u8vec4 *)m_data->m_pixels[(int)fmt];

for (int n = 0; n < count; ++n)
dest[n] = f32tou8(src[n]);
#if 0
init_tables();

for(y = 0; y < img->h; y++)
for(x = 0; x < img->w; x++)
for(i = 0; i < 4; i++)
for (int y = 0; y < size.y; y++)
for (int x = 0; x < size.x; x++)
for (i = 0; i < 4; i++)
{
double p, e;
uint8_t d;

p = src[4 * (y * img->w + x) + i];
p = src[4 * (y * size.x + x) + i];

if(p < 0.) d = 0.;
else if(p > 1.) d = 255;
if (p < 0.) d = 0.;
else if (p > 1.) d = 255;
else d = (int)(255.999 * pow(p, 1. / global_gamma));

dest[4 * (y * img->w + x) + i] = d;
dest[4 * (y * size.x + x) + i] = d;

e = (p - u8tof32(d)) / 16;
if(x < img->w - 1)
src[4 * (y * img->w + x + 1) + i] += e * 7;
if(y < img->h - 1)
if (x < size.x - 1)
src[4 * (y * size.x + x + 1) + i] += e * 7;
if (y < size.y - 1)
{
if(x > 0)
src[4 * ((y + 1) * img->w + x - 1) + i] += e * 3;
src[4 * ((y + 1) * img->w + x) + i] += e * 5;
if(x < img->w - 1)
src[4 * ((y + 1) * img->w + x + 1) + i] += e;
if (x > 0)
src[4 * ((y + 1) * size.x + x - 1) + i] += e * 3;
src[4 * ((y + 1) * size.x + x) + i] += e * 5;
if (x < size.x - 1)
src[4 * ((y + 1) * size.x + x + 1) + i] += e;
}
}
#endif
}
else if(img->last_modified == PIPI_PIXELS_RGBA_F32
&& type == PIPI_PIXELS_BGR_U8)
else if (old_fmt == PixelFormat::Y_F32 && fmt == PixelFormat::RGBA_F32)
{
float *src = (float *)img->p[PIPI_PIXELS_RGBA_F32].pixels;
uint8_t *dest = (uint8_t *)img->p[type].pixels;

init_tables();

for(y = 0; y < img->h; y++)
for(x = 0; x < img->w; x++)
for(i = 0; i < 3; i++)
{
double p, e;
uint8_t d;
float *src = (float *)m_data->m_pixels[(int)old_fmt];
vec4 *dest = (vec4 *)m_data->m_pixels[(int)fmt];

p = src[4 * (y * img->w + x) + i];

if(p < 0.) d = 0.;
else if(p > 1.) d = 255;
else d = (int)(255.999 * pow(p, 1. / global_gamma));

dest[3 * (y * img->w + x) + i] = d;

e = (p - u8tof32(d)) / 16;
if(x < img->w - 1)
src[4 * (y * img->w + x + 1) + i] += e * 7;
if(y < img->h - 1)
{
if(x > 0)
src[4 * ((y + 1) * img->w + x - 1) + i] += e * 3;
src[4 * ((y + 1) * img->w + x) + i] += e * 5;
if(x < img->w - 1)
src[4 * ((y + 1) * img->w + x + 1) + i] += e;
}
}
for (int n = 0; n < count; ++n)
dest[n] = vec4(vec3(src[n]), 1.0f);
}
else if(img->last_modified == PIPI_PIXELS_Y_F32
&& type == PIPI_PIXELS_RGBA_F32)
else if (old_fmt == PixelFormat::RGBA_F32 && fmt == PixelFormat::Y_F32)
{
float *src = (float *)img->p[PIPI_PIXELS_Y_F32].pixels;
float *dest = (float *)img->p[PIPI_PIXELS_RGBA_F32].pixels;
vec4 *src = (vec4 *)m_data->m_pixels[(int)old_fmt];
float *dest = (float *)m_data->m_pixels[(int)fmt];

init_tables();
vec3 const coeff(0.299f, 0.587f, 0.114f);

for(y = 0; y < img->h; y++)
for(x = 0; x < img->w; x++)
{
float p = src[y * img->w + x];
dest[4 * (y * img->w + x)] = p;
dest[4 * (y * img->w + x) + 1] = p;
dest[4 * (y * img->w + x) + 2] = p;
dest[4 * (y * img->w + x) + 3] = 1.0;
}
}
else if(img->last_modified == PIPI_PIXELS_RGBA_F32
&& type == PIPI_PIXELS_Y_F32)
{
float *src = (float *)img->p[PIPI_PIXELS_RGBA_F32].pixels;
float *dest = (float *)img->p[PIPI_PIXELS_Y_F32].pixels;

init_tables();

for(y = 0; y < img->h; y++)
for(x = 0; x < img->w; x++)
{
float p = 0.;
p += 0.299 * src[4 * (y * img->w + x)];
p += 0.587 * src[4 * (y * img->w + x) + 1];
p += 0.114 * src[4 * (y * img->w + x) + 2];
dest[y * img->w + x] = p;
}
for (int n = 0; n < count; ++n)
dest[n] = dot(coeff, src[n].rgb);
}
else
{
memset(img->p[type].pixels, 0, bytes);
ASSERT(false, "Unable to find proper conversion");
}

img->last_modified = type;

return &img->p[type];
}

void pipi_release_pixels(pipi_image_t *img, pipi_pixels_t *p)
{
return;
}

void pipi_set_colorspace(pipi_image_t *img, pipi_format_t fmt)
{
pipi_pixels_t *p = pipi_get_pixels(img, fmt);
pipi_release_pixels(img, p);
}

void pipi_set_gamma(double g)
{
if(g > 0.)
{
global_gamma = g;
done = 0;
}
}

static void init_tables(void)
{
int i;

if(done)
return;

for(i = 0; i < 256; i++)
u8tof32_table[i] = pow((double)i / 255., global_gamma);

done = 1;
}
} /* namespace lol */


Loading…
Cancel
Save