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-862c8a59935f
remotes/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; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||