colour spaces for a given image. For instance, if pipi_gaussian_blur is applied to a 32-bpp image, it is automatically converted to gamma-corrected 32-bit floats beforehands, then converted back to normal. * TODO: clipping, regions of interest, more formats, getpixel macros... git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@2605 92316355-f0b4-4df1-b90c-862c8a59935fremotes/tiles
@@ -49,23 +49,6 @@ pipi_image_t *pipi_new(int width, int height) | |||||
#endif | #endif | ||||
} | } | ||||
pipi_image_t *pipi_copy(pipi_image_t const *img) | |||||
{ | |||||
pipi_image_t *dst; | |||||
int x, y; | |||||
dst = pipi_new(img->width, img->height); | |||||
for(y = 0; y < img->height; y++) | |||||
{ | |||||
for(x = 0; x < img->width; x++) | |||||
{ | |||||
double r, g, b; | |||||
pipi_getpixel(img, x, y, &r, &g, &b); | |||||
pipi_setpixel(dst, x, y, r, g, b); | |||||
} | |||||
} | |||||
return dst; | |||||
} | |||||
void pipi_free(pipi_image_t *img) | void pipi_free(pipi_image_t *img) | ||||
{ | { | ||||
#if USE_SDL | #if USE_SDL | ||||
@@ -37,13 +37,20 @@ pipi_image_t *pipi_load_imlib2(const char *name) | |||||
return NULL; | return NULL; | ||||
img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | ||||
memset(img, 0, sizeof(pipi_image_t)); | |||||
imlib_context_set_image(priv); | imlib_context_set_image(priv); | ||||
img->width = imlib_image_get_width(); | |||||
img->height = imlib_image_get_height(); | |||||
img->pitch = 4 * imlib_image_get_width(); | |||||
img->channels = 4; | |||||
img->pixels = (char *)imlib_image_get_data(); | |||||
img->priv = (void *)priv; | |||||
img->w = imlib_image_get_width(); | |||||
img->h = imlib_image_get_height(); | |||||
img->p[PIPI_PIXELS_RGBA32].pixels = imlib_image_get_data(); | |||||
img->p[PIPI_PIXELS_RGBA32].w = imlib_image_get_width(); | |||||
img->p[PIPI_PIXELS_RGBA32].h = imlib_image_get_height(); | |||||
img->p[PIPI_PIXELS_RGBA32].pitch = 4 * imlib_image_get_width(); | |||||
img->last_modified = PIPI_PIXELS_RGBA32; | |||||
img->codec_priv = (void *)priv; | |||||
img->codec_format = PIPI_PIXELS_RGBA32; | |||||
return img; | return img; | ||||
} | } | ||||
@@ -57,20 +64,27 @@ pipi_image_t *pipi_new_imlib2(int width, int height) | |||||
return NULL; | return NULL; | ||||
img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | ||||
memset(img, 0, sizeof(pipi_image_t)); | |||||
imlib_context_set_image(priv); | imlib_context_set_image(priv); | ||||
img->width = imlib_image_get_width(); | |||||
img->height = imlib_image_get_height(); | |||||
img->pitch = 4 * imlib_image_get_width(); | |||||
img->channels = 4; | |||||
img->pixels = (char *)imlib_image_get_data(); | |||||
img->priv = (void *)priv; | |||||
img->w = imlib_image_get_width(); | |||||
img->h = imlib_image_get_height(); | |||||
img->p[PIPI_PIXELS_RGBA32].pixels = imlib_image_get_data(); | |||||
img->p[PIPI_PIXELS_RGBA32].w = imlib_image_get_width(); | |||||
img->p[PIPI_PIXELS_RGBA32].h = imlib_image_get_height(); | |||||
img->p[PIPI_PIXELS_RGBA32].pitch = 4 * imlib_image_get_width(); | |||||
img->last_modified = PIPI_PIXELS_RGBA32; | |||||
img->codec_priv = (void *)priv; | |||||
img->codec_format = PIPI_PIXELS_RGBA32; | |||||
return img; | return img; | ||||
} | } | ||||
void pipi_free_imlib2(pipi_image_t *img) | void pipi_free_imlib2(pipi_image_t *img) | ||||
{ | { | ||||
imlib_context_set_image(img->priv); | |||||
imlib_context_set_image(img->codec_priv); | |||||
imlib_free_image(); | imlib_free_image(); | ||||
free(img); | free(img); | ||||
@@ -78,7 +92,8 @@ void pipi_free_imlib2(pipi_image_t *img) | |||||
void pipi_save_imlib2(pipi_image_t *img, const char *name) | void pipi_save_imlib2(pipi_image_t *img, const char *name) | ||||
{ | { | ||||
imlib_context_set_image(img->priv); | |||||
pipi_getpixels(img, img->codec_format); | |||||
imlib_context_set_image(img->codec_priv); | |||||
imlib_save_image(name); | imlib_save_image(name); | ||||
} | } | ||||
@@ -38,12 +38,19 @@ pipi_image_t *pipi_load_opencv(const char *name) | |||||
return NULL; | return NULL; | ||||
img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | ||||
img->width = priv->width; | |||||
img->height = priv->height; | |||||
img->pitch = priv->widthStep; | |||||
img->channels = priv->nChannels; | |||||
img->pixels = priv->imageData; | |||||
img->priv = (void *)priv; | |||||
memset(img, 0, sizeof(pipi_image_t)); | |||||
img->w = priv->width; | |||||
img->h = priv->height; | |||||
img->p[PIPI_PIXELS_RGBA32].pixels = priv->imageData; | |||||
img->p[PIPI_PIXELS_RGBA32].w = priv->width; | |||||
img->p[PIPI_PIXELS_RGBA32].h = priv->height; | |||||
img->p[PIPI_PIXELS_RGBA32].pitch = priv->widthStep; | |||||
img->last_modified = PIPI_PIXELS_RGBA32; | |||||
img->codec_priv = (void *)priv; | |||||
img->codec_format = PIPI_PIXELS_RGBA32; | |||||
return img; | return img; | ||||
} | } | ||||
@@ -57,12 +64,19 @@ pipi_image_t *pipi_new_opencv(int width, int height) | |||||
return NULL; | return NULL; | ||||
img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | ||||
img->width = priv->width; | |||||
img->height = priv->height; | |||||
img->pitch = priv->widthStep; | |||||
img->channels = priv->nChannels; | |||||
img->pixels = priv->imageData; | |||||
img->priv = (void *)priv; | |||||
memset(img, 0, sizeof(pipi_image_t)); | |||||
img->w = priv->width; | |||||
img->h = priv->height; | |||||
img->p[PIPI_PIXELS_RGBA32].pixels = priv->imageData; | |||||
img->p[PIPI_PIXELS_RGBA32].w = priv->width; | |||||
img->p[PIPI_PIXELS_RGBA32].h = priv->height; | |||||
img->p[PIPI_PIXELS_RGBA32].pitch = priv->widthStep; | |||||
img->last_modified = PIPI_PIXELS_RGBA32; | |||||
img->codec_priv = (void *)priv; | |||||
img->codec_format = PIPI_PIXELS_RGBA32; | |||||
return img; | return img; | ||||
} | } | ||||
@@ -70,7 +84,7 @@ pipi_image_t *pipi_new_opencv(int width, int height) | |||||
void pipi_free_opencv(pipi_image_t *img) | void pipi_free_opencv(pipi_image_t *img) | ||||
{ | { | ||||
IplImage *iplimg; | IplImage *iplimg; | ||||
iplimg = (IplImage *)img->priv; | |||||
iplimg = (IplImage *)img->codec_priv; | |||||
cvReleaseImage(&iplimg); | cvReleaseImage(&iplimg); | ||||
free(img); | free(img); | ||||
@@ -78,6 +92,7 @@ void pipi_free_opencv(pipi_image_t *img) | |||||
void pipi_save_opencv(pipi_image_t *img, const char *name) | void pipi_save_opencv(pipi_image_t *img, const char *name) | ||||
{ | { | ||||
cvSaveImage(name, img->priv); | |||||
pipi_getpixels(img, img->codec_format); | |||||
cvSaveImage(name, img->codec_priv); | |||||
} | } | ||||
@@ -36,21 +36,28 @@ pipi_image_t *pipi_load_sdl(const char *name) | |||||
if(!priv) | if(!priv) | ||||
return NULL; | return NULL; | ||||
if(priv->format->BytesPerPixel == 1) | |||||
if(priv->format->BytesPerPixel != 4) | |||||
{ | { | ||||
img = pipi_new(priv->w, priv->h); | img = pipi_new(priv->w, priv->h); | ||||
SDL_BlitSurface(priv, NULL, img->priv, NULL); | |||||
SDL_BlitSurface(priv, NULL, img->codec_priv, NULL); | |||||
SDL_FreeSurface(priv); | SDL_FreeSurface(priv); | ||||
return img; | return img; | ||||
} | } | ||||
img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | ||||
img->width = priv->w; | |||||
img->height = priv->h; | |||||
img->pitch = priv->pitch; | |||||
img->channels = priv->format->BytesPerPixel; | |||||
img->pixels = priv->pixels; | |||||
img->priv = (void *)priv; | |||||
memset(img, 0, sizeof(pipi_image_t)); | |||||
img->w = priv->w; | |||||
img->h = priv->h; | |||||
img->p[PIPI_PIXELS_RGBA32].pixels = priv->pixels; | |||||
img->p[PIPI_PIXELS_RGBA32].w = priv->w; | |||||
img->p[PIPI_PIXELS_RGBA32].h = priv->h; | |||||
img->p[PIPI_PIXELS_RGBA32].pitch = priv->pitch; | |||||
img->last_modified = PIPI_PIXELS_RGBA32; | |||||
img->codec_priv = (void *)priv; | |||||
img->codec_format = PIPI_PIXELS_RGBA32; | |||||
return img; | return img; | ||||
} | } | ||||
@@ -78,25 +85,33 @@ pipi_image_t *pipi_new_sdl(int width, int height) | |||||
return NULL; | return NULL; | ||||
img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | img = (pipi_image_t *)malloc(sizeof(pipi_image_t)); | ||||
img->width = priv->w; | |||||
img->height = priv->h; | |||||
img->pitch = priv->pitch; | |||||
img->channels = priv->format->BytesPerPixel; | |||||
img->pixels = priv->pixels; | |||||
img->priv = (void *)priv; | |||||
memset(img, 0, sizeof(pipi_image_t)); | |||||
img->w = priv->w; | |||||
img->h = priv->h; | |||||
img->p[PIPI_PIXELS_RGBA32].pixels = priv->pixels; | |||||
img->p[PIPI_PIXELS_RGBA32].w = priv->w; | |||||
img->p[PIPI_PIXELS_RGBA32].h = priv->h; | |||||
img->p[PIPI_PIXELS_RGBA32].pitch = priv->pitch; | |||||
img->last_modified = PIPI_PIXELS_RGBA32; | |||||
img->codec_priv = (void *)priv; | |||||
img->codec_format = PIPI_PIXELS_RGBA32; | |||||
return img; | return img; | ||||
} | } | ||||
void pipi_free_sdl(pipi_image_t *img) | void pipi_free_sdl(pipi_image_t *img) | ||||
{ | { | ||||
SDL_FreeSurface(img->priv); | |||||
SDL_FreeSurface(img->codec_priv); | |||||
free(img); | free(img); | ||||
} | } | ||||
void pipi_save_sdl(pipi_image_t *img, const char *name) | void pipi_save_sdl(pipi_image_t *img, const char *name) | ||||
{ | { | ||||
SDL_SaveBMP(img->priv, name); | |||||
pipi_getpixels(img, img->codec_format); | |||||
SDL_SaveBMP(img->codec_priv, name); | |||||
} | } | ||||
@@ -28,6 +28,8 @@ | |||||
void pipi_dither_24to16(pipi_image_t *img) | void pipi_dither_24to16(pipi_image_t *img) | ||||
{ | { | ||||
/* XXX: disabled because this is not the right place... see pixels.c instead */ | |||||
#if 0 | |||||
int *error, *nexterror; | int *error, *nexterror; | ||||
uint32_t *p32; | uint32_t *p32; | ||||
int x, y; | int x, y; | ||||
@@ -84,5 +86,6 @@ void pipi_dither_24to16(pipi_image_t *img) | |||||
free(error); | free(error); | ||||
free(nexterror); | free(nexterror); | ||||
#endif | |||||
} | } | ||||
@@ -27,15 +27,24 @@ | |||||
#include "pipi.h" | #include "pipi.h" | ||||
#include "pipi_internals.h" | #include "pipi_internals.h" | ||||
pipi_image_t *pipi_gaussian_blur(pipi_image_t const *src, float radius) | |||||
pipi_image_t *pipi_gaussian_blur(pipi_image_t *src, float radius) | |||||
{ | { | ||||
pipi_image_t *dst; | pipi_image_t *dst; | ||||
pipi_pixels_t *srcp, *dstp; | |||||
float *srcdata, *dstdata; | |||||
double *kernel; | double *kernel; | ||||
double K, L, t = 0.; | double K, L, t = 0.; | ||||
int x, y, i, j, w, h, kr, kw; | int x, y, i, j, w, h, kr, kw; | ||||
w = src->width; | |||||
h = src->height; | |||||
w = src->w; | |||||
h = src->h; | |||||
srcp = pipi_getpixels(src, PIPI_PIXELS_RGBA_F); | |||||
srcdata = (float *)srcp->pixels; | |||||
dst = pipi_new(w, h); | |||||
dstp = pipi_getpixels(dst, PIPI_PIXELS_RGBA_F); | |||||
dstdata = (float *)dstp->pixels; | |||||
kr = (int)(3. * radius + 0.99999); | kr = (int)(3. * radius + 0.99999); | ||||
kw = 2 * kr + 1; | kw = 2 * kr + 1; | ||||
@@ -52,8 +61,6 @@ pipi_image_t *pipi_gaussian_blur(pipi_image_t const *src, float radius) | |||||
for(i = -kr; i <= kr; i++) | for(i = -kr; i <= kr; i++) | ||||
kernel[(j + kr) * kw + (i + kr)] /= t; | kernel[(j + kr) * kw + (i + kr)] /= t; | ||||
dst = pipi_new(w, h); | |||||
for(y = 0; y < h; y++) | for(y = 0; y < h; y++) | ||||
{ | { | ||||
for(x = 0; x < w; x++) | for(x = 0; x < w; x++) | ||||
@@ -63,15 +70,16 @@ pipi_image_t *pipi_gaussian_blur(pipi_image_t const *src, float radius) | |||||
for(j = -kr; j <= kr; j++) | for(j = -kr; j <= kr; j++) | ||||
for(i = -kr; i <= kr; i++) | for(i = -kr; i <= kr; i++) | ||||
{ | { | ||||
double r, g, b, f = kernel[(j + kr) * kw + (i + kr)]; | |||||
double f = kernel[(j + kr) * kw + (i + kr)]; | |||||
pipi_getpixel(src, x + i, y + j, &r, &g, &b); | |||||
R += f * r; | |||||
G += f * g; | |||||
B += f * b; | |||||
R += f * srcdata[((y + j) * w + x + i) * 4]; | |||||
G += f * srcdata[((y + j) * w + x + i) * 4 + 1]; | |||||
B += f * srcdata[((y + j) * w + x + i) * 4 + 2]; | |||||
} | } | ||||
pipi_setpixel(dst, x, y, R, G, B); | |||||
dstdata[(y * w + x) * 4] = R; | |||||
dstdata[(y * w + x) * 4 + 1] = G; | |||||
dstdata[(y * w + x) * 4 + 2] = B; | |||||
} | } | ||||
} | } | ||||
@@ -0,0 +1,40 @@ | |||||
/* | |||||
* libpipi Proper image processing implementation 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. | |||||
*/ | |||||
/* | |||||
* pipi.c: core library routines | |||||
*/ | |||||
#include "config.h" | |||||
#include "common.h" | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include "pipi.h" | |||||
#include "pipi_internals.h" | |||||
/* | |||||
static int init = 0; | |||||
void _pipi_init(void) | |||||
{ | |||||
if(init) | |||||
return; | |||||
_pipi_init_pixels(); | |||||
} | |||||
*/ | |||||
@@ -24,25 +24,42 @@ extern "C" | |||||
{ | { | ||||
#endif | #endif | ||||
/* pipi_format_t: this enum is a list of all possible pixel formats for | |||||
* our internal images. RGBA32 is the most usual format when an image has | |||||
* just been loaded, but RGBA_F is a lot better for complex operations. */ | |||||
typedef enum | |||||
{ | |||||
PIPI_PIXELS_RGBA32 = 0, | |||||
PIPI_PIXELS_RGBA_F = 1, | |||||
PIPI_PIXELS_MAX = 2 | |||||
} | |||||
pipi_format_t; | |||||
/* pipi_pixels_t: this structure stores a pixel view of an image. */ | |||||
typedef struct | |||||
{ | |||||
void *pixels; | |||||
int w, h, pitch; | |||||
} | |||||
pipi_pixels_t; | |||||
/* pipi_image_t: the main image type */ | |||||
typedef struct pipi_image pipi_image_t; | typedef struct pipi_image pipi_image_t; | ||||
extern pipi_image_t *pipi_load(const char *name); | |||||
extern pipi_image_t *pipi_new(int width, int height); | |||||
extern pipi_image_t *pipi_copy(const pipi_image_t *img); | |||||
extern void pipi_free(pipi_image_t *img); | |||||
extern void pipi_save(pipi_image_t *img, const char *name); | |||||
extern int pipi_getgray(pipi_image_t const *img, int x, int y, int *g); | |||||
extern int pipi_getpixel(pipi_image_t const *img, | |||||
int x, int y, double *r, double *g, double *b); | |||||
extern int pipi_setpixel(pipi_image_t *img, int x, int y, | |||||
double r, double g, double b); | |||||
extern pipi_image_t *pipi_load(const char *); | |||||
extern pipi_image_t *pipi_new(int, int); | |||||
extern void pipi_free(pipi_image_t *); | |||||
extern void pipi_save(pipi_image_t *, const char *); | |||||
extern pipi_pixels_t *pipi_getpixels(pipi_image_t *, pipi_format_t); | |||||
extern pipi_image_t *pipi_resize(pipi_image_t const *, int, int); | |||||
extern pipi_image_t *pipi_resize(pipi_image_t *, int, int); | |||||
extern pipi_image_t *pipi_gaussian_blur(pipi_image_t const *, float); | |||||
extern pipi_image_t *pipi_gaussian_blur(pipi_image_t *, float); | |||||
extern void pipi_dither_24to16(pipi_image_t *img); | |||||
extern void pipi_dither_24to16(pipi_image_t *); | |||||
extern void pipi_test(pipi_image_t *); | extern void pipi_test(pipi_image_t *); | ||||
@@ -16,14 +16,22 @@ | |||||
* pipi_internals.h: internal types | * pipi_internals.h: internal types | ||||
*/ | */ | ||||
#ifndef __CACA_INTERNALS_H__ | |||||
#define __CACA_INTERNALS_H__ | |||||
#ifndef __PIPI_INTERNALS_H__ | |||||
#define __PIPI_INTERNALS_H__ | |||||
/* pipi_image_t: the image structure. This is probably going to be the most | |||||
* complex structure in the library, but right now it only has fairly normal | |||||
* stuff, like width and height and pointers to pixel areas. */ | |||||
struct pipi_image | struct pipi_image | ||||
{ | { | ||||
int width, height, pitch, channels; | |||||
unsigned char *pixels; | |||||
void *priv; | |||||
int w, h, pitch; | |||||
pipi_format_t codec_format, last_modified; | |||||
/* List of all possible pixel formats */ | |||||
pipi_pixels_t p[PIPI_PIXELS_MAX]; | |||||
/* Private data used by the codec */ | |||||
void *codec_priv; | |||||
}; | }; | ||||
#ifdef USE_IMLIB2 | #ifdef USE_IMLIB2 | ||||
@@ -31,52 +31,68 @@ | |||||
#define C2I(p) (pow(((double)p)/255., 2.2)) | #define C2I(p) (pow(((double)p)/255., 2.2)) | ||||
#define I2C(p) ((int)255.999*pow(((double)p), 1./2.2)) | #define I2C(p) ((int)255.999*pow(((double)p), 1./2.2)) | ||||
int pipi_getgray(pipi_image_t const *img, int x, int y, int *g) | |||||
/* Return a direct pointer to an image's pixels. */ | |||||
pipi_pixels_t *pipi_getpixels(pipi_image_t *img, pipi_format_t type) | |||||
{ | { | ||||
if(x < 0 || y < 0 || x >= img->width || y >= img->height) | |||||
{ | |||||
*g = 255; | |||||
return -1; | |||||
} | |||||
*g = (unsigned char)img->pixels[y * img->pitch + x * img->channels + 1]; | |||||
size_t bytes = 0; | |||||
int x, y, i; | |||||
return 0; | |||||
} | |||||
int pipi_getpixel(pipi_image_t const *img, | |||||
int x, int y, double *r, double *g, double *b) | |||||
{ | |||||
uint8_t *pixel; | |||||
if(type < 0 || type >= PIPI_PIXELS_MAX) | |||||
return NULL; | |||||
if(x < 0) x = 0; | |||||
else if(x >= img->width) x = img->width - 1; | |||||
if(y < 0) y = 0; | |||||
else if(y >= img->height) y = img->height - 1; | |||||
pixel = img->pixels + y * img->pitch + x * img->channels; | |||||
*b = C2I((unsigned char)pixel[0]); | |||||
*g = C2I((unsigned char)pixel[1]); | |||||
*r = C2I((unsigned char)pixel[2]); | |||||
return 0; | |||||
} | |||||
if(img->last_modified == type) | |||||
return &img->p[type]; | |||||
int pipi_setpixel(pipi_image_t *img, int x, int y, double r, double g, double b) | |||||
{ | |||||
uint8_t *pixel; | |||||
if(x < 0 || y < 0 || x >= img->width || y >= img->height) | |||||
return -1; | |||||
/* Allocate pixels if necessary */ | |||||
if(!img->p[type].pixels) | |||||
{ | |||||
switch(type) | |||||
{ | |||||
case PIPI_PIXELS_RGBA32: | |||||
bytes = img->w * img->h * 4 * sizeof(uint8_t); | |||||
break; | |||||
case PIPI_PIXELS_RGBA_F: | |||||
bytes = img->w * img->h * 4 * sizeof(float); | |||||
break; | |||||
default: | |||||
return NULL; | |||||
} | |||||
img->p[type].pixels = malloc(bytes); | |||||
} | |||||
pixel = img->pixels + y * img->pitch + x * img->channels; | |||||
/* Convert pixels */ | |||||
if(img->last_modified == PIPI_PIXELS_RGBA32 | |||||
&& type == PIPI_PIXELS_RGBA_F) | |||||
{ | |||||
uint8_t *src = (uint8_t *)img->p[PIPI_PIXELS_RGBA32].pixels; | |||||
float *dest = (float *)img->p[type].pixels; | |||||
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] | |||||
= C2I(src[4 * (y * img->w + x) + i]); | |||||
} | |||||
else if(img->last_modified == PIPI_PIXELS_RGBA_F | |||||
&& type == PIPI_PIXELS_RGBA32) | |||||
{ | |||||
float *src = (float *)img->p[PIPI_PIXELS_RGBA_F].pixels; | |||||
uint8_t *dest = (uint8_t *)img->p[type].pixels; | |||||
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] | |||||
= I2C(src[4 * (y * img->w + x) + i]); | |||||
} | |||||
else | |||||
{ | |||||
memset(img->p[type].pixels, 0, bytes); | |||||
} | |||||
pixel[0] = I2C(b); | |||||
pixel[1] = I2C(g); | |||||
pixel[2] = I2C(r); | |||||
img->last_modified = type; | |||||
return 0; | |||||
return &img->p[type]; | |||||
} | } | ||||
@@ -25,46 +25,54 @@ | |||||
#include "pipi.h" | #include "pipi.h" | ||||
#include "pipi_internals.h" | #include "pipi_internals.h" | ||||
pipi_image_t *pipi_resize(pipi_image_t const *src, int w, int h) | |||||
pipi_image_t *pipi_resize(pipi_image_t *src, int w, int h) | |||||
{ | { | ||||
double *aline, *line; | |||||
float *srcdata, *dstdata, *aline, *line; | |||||
pipi_image_t *dst; | pipi_image_t *dst; | ||||
pipi_pixels_t *srcp, *dstp; | |||||
int x, y, x0, y0, sw, dw, sh, dh, remy; | int x, y, x0, y0, sw, dw, sh, dh, remy; | ||||
srcp = pipi_getpixels(src, PIPI_PIXELS_RGBA_F); | |||||
srcdata = (float *)srcp->pixels; | |||||
dst = pipi_new(w, h); | dst = pipi_new(w, h); | ||||
dstp = pipi_getpixels(dst, PIPI_PIXELS_RGBA_F); | |||||
dstdata = (float *)dstp->pixels; | |||||
sw = src->width; sh = src->height; | |||||
dw = dst->width; dh = dst->height; | |||||
sw = src->w; sh = src->h; | |||||
dw = dst->w; dh = dst->h; | |||||
aline = malloc(3 * dw * sizeof(double)); | |||||
line = malloc(3 * dw * sizeof(double)); | |||||
aline = malloc(3 * dw * sizeof(float)); | |||||
line = malloc(3 * dw * sizeof(float)); | |||||
memset(line, 0, 3 * dw * sizeof(double)); | |||||
memset(line, 0, 3 * dw * sizeof(float)); | |||||
remy = 0; | remy = 0; | ||||
for(y = 0, y0 = 0; y < dst->height; y++) | |||||
for(y = 0, y0 = 0; y < dh; y++) | |||||
{ | { | ||||
int toty = 0, ny; | int toty = 0, ny; | ||||
memset(aline, 0, 3 * dw * sizeof(double)); | |||||
memset(aline, 0, 3 * dw * sizeof(float)); | |||||
while(toty < sh) | while(toty < sh) | ||||
{ | { | ||||
if(remy == 0) | if(remy == 0) | ||||
{ | { | ||||
double r = 0, g = 0, b = 0; | |||||
float r = 0, g = 0, b = 0; | |||||
int remx = 0; | int remx = 0; | ||||
for(x = 0, x0 = 0; x < dst->width; x++) | |||||
for(x = 0, x0 = 0; x < dw; x++) | |||||
{ | { | ||||
double ar = 0, ag = 0, ab = 0; | |||||
float ar = 0, ag = 0, ab = 0; | |||||
int totx = 0, nx; | int totx = 0, nx; | ||||
while(totx < sw) | while(totx < sw) | ||||
{ | { | ||||
if(remx == 0) | if(remx == 0) | ||||
{ | { | ||||
pipi_getpixel(src, x0, y0, &r, &g, &b); | |||||
r = srcdata[(y0 * sw + x0) * 4]; | |||||
g = srcdata[(y0 * sw + x0) * 4 + 1]; | |||||
b = srcdata[(y0 * sw + x0) * 4 + 2]; | |||||
x0++; | x0++; | ||||
remx = dw; | remx = dw; | ||||
} | } | ||||
@@ -85,7 +93,7 @@ pipi_image_t *pipi_resize(pipi_image_t const *src, int w, int h) | |||||
} | } | ||||
ny = (toty + remy <= sh) ? remy : sh - toty; | ny = (toty + remy <= sh) ? remy : sh - toty; | ||||
for(x = 0; x < dst->width; x++) | |||||
for(x = 0; x < dw; x++) | |||||
{ | { | ||||
aline[3 * x] += ny * line[3 * x]; | aline[3 * x] += ny * line[3 * x]; | ||||
aline[3 * x + 1] += ny * line[3 * x + 1]; | aline[3 * x + 1] += ny * line[3 * x + 1]; | ||||
@@ -95,11 +103,12 @@ pipi_image_t *pipi_resize(pipi_image_t const *src, int w, int h) | |||||
remy -= ny; | remy -= ny; | ||||
} | } | ||||
for(x = 0; x < dst->width; x++) | |||||
pipi_setpixel(dst, x, y, | |||||
aline[3 * x] / (sw * sh), | |||||
aline[3 * x + 1] / (sw * sh), | |||||
aline[3 * x + 2] / (sw * sh)); | |||||
for(x = 0; x < dw; x++) | |||||
{ | |||||
dstdata[(y * dw + x) * 4] = aline[3 * x] / (sw * sh); | |||||
dstdata[(y * dw + x) * 4 + 1] = aline[3 * x + 1] / (sw * sh); | |||||
dstdata[(y * dw + x) * 4 + 2] = aline[3 * x + 2] / (sw * sh); | |||||
} | |||||
} | } | ||||
free(aline); | free(aline); | ||||
@@ -27,15 +27,23 @@ | |||||
void pipi_test(pipi_image_t *img) | void pipi_test(pipi_image_t *img) | ||||
{ | { | ||||
pipi_pixels_t *pixels; | |||||
float *data; | |||||
int x, y; | int x, y; | ||||
for(y = 0; y < img->height; y++) | |||||
pixels = pipi_getpixels(img, PIPI_PIXELS_RGBA_F); | |||||
data = (float *)pixels->pixels; | |||||
for(y = 0; y < img->h; y++) | |||||
{ | { | ||||
for(x = 0; x < img->width; x++) | |||||
for(x = 0; x < img->w; x++) | |||||
{ | { | ||||
double r = 0, g = 0, b = 0; | double r = 0, g = 0, b = 0; | ||||
pipi_getpixel(img, x, y, &r, &g, &b); | |||||
r = data[(y * img->w + x) * 4]; | |||||
g = data[(y * img->w + x) * 4 + 1]; | |||||
b = data[(y * img->w + x) * 4 + 2]; | |||||
if(r + g + b == 0) | if(r + g + b == 0) | ||||
r = g = b = 1. / 3; | r = g = b = 1. / 3; | ||||
else if(r + g + b < 1.) | else if(r + g + b < 1.) | ||||
@@ -53,7 +61,10 @@ void pipi_test(pipi_image_t *img) | |||||
double d = (-1. - r + g + b) / 3; | double d = (-1. - r + g + b) / 3; | ||||
r += d; g -= d; b -= d; | r += d; g -= d; b -= d; | ||||
} | } | ||||
pipi_setpixel(img, x, y, r, g, b); | |||||
data[(y * img->w + x) * 4] = r; | |||||
data[(y * img->w + x) * 4 + 1] = g; | |||||
data[(y * img->w + x) * 4 + 2] = b; | |||||
} | } | ||||
} | } | ||||
} | } | ||||