X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=share%2Fbase_image.c;h=b3c5808424772eafed4e61786942501274385061;hb=4483dfdacd29073b37a6429ca8e123c80deac75a;hp=3378428545f67ff1f4c88cbfa62803cad4ddb0fe;hpb=70a7d71562ecf00d04102ff6da28350910f1995a;p=neverball diff --git a/share/base_image.c b/share/base_image.c index 3378428..b3c5808 100644 --- a/share/base_image.c +++ b/share/base_image.c @@ -12,106 +12,326 @@ * General Public License for more details. */ -#include +#include +#include +#include +#include + +#include "glext.h" +#include "base_config.h" +#include "base_image.h" + +#include "fs.h" +#include "fs_png.h" +#include "fs_jpg.h" + +/*---------------------------------------------------------------------------*/ + +void image_size(int *W, int *H, int w, int h) +{ + /* Round the image size up to the next power-of-two. */ + + *W = w ? 1 : 0; + *H = h ? 1 : 0; + + while (*W < w) *W *= 2; + while (*H < h) *H *= 2; +} /*---------------------------------------------------------------------------*/ -void image_swab(SDL_Surface *src) +static void *image_load_png(const char *filename, int *width, + int *height, + int *bytes) { - int i, j, b = (src->format->BitsPerPixel == 32) ? 4 : 3; + fs_file fh; + + png_structp readp = NULL; + png_infop infop = NULL; + png_bytep *bytep = NULL; + unsigned char *p = NULL; + + /* Initialize all PNG import data structures. */ + + if (!(fh = fs_open(filename, "r"))) + return NULL; + + if (!(readp = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) + return NULL; + + if (!(infop = png_create_info_struct(readp))) + return NULL; - SDL_LockSurface(src); + /* Enable the default PNG error handler. */ + + if (setjmp(png_jmpbuf(readp)) == 0) { - unsigned char *s = (unsigned char *) src->pixels; - unsigned char t; + int w, h, b, i; - /* Iterate over each pixel of the image. */ + /* Read the PNG header. */ - for (i = 0; i < src->h; i++) - for (j = 0; j < src->w; j++) - { - int k = (i * src->w + j) * b; + png_set_read_fn(readp, fh, fs_png_read); + png_read_info(readp, infop); - /* Swap the red and blue channels of each. */ + png_set_expand(readp); + png_set_strip_16(readp); + png_set_packing(readp); - t = s[k + 2]; - s[k + 2] = s[k + 0]; - s[k + 0] = t; - } + png_read_update_info(readp, infop); + + /* Extract and check image properties. */ + + w = (int) png_get_image_width (readp, infop); + h = (int) png_get_image_height(readp, infop); + + switch (png_get_color_type(readp, infop)) + { + case PNG_COLOR_TYPE_GRAY: b = 1; break; + case PNG_COLOR_TYPE_GRAY_ALPHA: b = 2; break; + case PNG_COLOR_TYPE_RGB: b = 3; break; + case PNG_COLOR_TYPE_RGB_ALPHA: b = 4; break; + + default: longjmp(png_jmpbuf(readp), -1); + } + + if (!(bytep = png_malloc(readp, h * png_sizeof(png_bytep)))) + longjmp(png_jmpbuf(readp), -1); + + /* Allocate the final pixel buffer and read pixels there. */ + + if ((p = (unsigned char *) malloc(w * h * b))) + { + for (i = 0; i < h; i++) + bytep[i] = p + w * b * (h - i - 1); + + png_read_image(readp, bytep); + png_read_end(readp, NULL); + + if (width) *width = w; + if (height) *height = h; + if (bytes) *bytes = b; + } + + png_free(readp, bytep); } - SDL_UnlockSurface(src); + else p = NULL; + + /* Free all resources. */ + + png_destroy_read_struct(&readp, &infop, NULL); + fs_close(fh); + + return p; } -void image_white(SDL_Surface *src) +static void *image_load_jpg(const char *filename, int *width, + int *height, + int *bytes) { - int i, j, b = (src->format->BitsPerPixel == 32) ? 4 : 3; + GLubyte *p = NULL; + fs_file fp; - SDL_LockSurface(src); + if ((fp = fs_open(filename, "r"))) { - unsigned char *s = (unsigned char *) src->pixels; + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; - /* Iterate over each pixel of the image. */ + int w, h, b, i = 0; - for (i = 0; i < src->h; i++) - for (j = 0; j < src->w; j++) - { - int k = (i * src->w + j) * b; + /* Initialize the JPG decompressor. */ - /* Whiten the RGB channels without touching any Alpha. */ + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); - s[k + 0] = 0xFF; - s[k + 1] = 0xFF; - s[k + 2] = 0xFF; + /* Set up a VFS source manager. */ + + fs_jpg_src(&cinfo, fp); + + /* Grab the JPG header info. */ + + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + + w = cinfo.output_width; + h = cinfo.output_height; + b = cinfo.output_components; + + /* Allocate the final pixel buffer and copy pixels there. */ + + if ((p = (GLubyte *) malloc (w * h * b))) + { + while (cinfo.output_scanline < cinfo.output_height) + { + GLubyte *buffer = p + w * b * (h - i - 1); + i += jpeg_read_scanlines(&cinfo, &buffer, 1); } + + if (width) *width = w; + if (height) *height = h; + if (bytes) *bytes = b; + } + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + fs_close(fp); } - SDL_UnlockSurface(src); + + return p; } -SDL_Surface *image_scale(SDL_Surface *src, int n) +void *image_load(const char *filename, int *width, + int *height, + int *bytes) { - int si, di; - int sj, dj; - int k, b = (src->format->BitsPerPixel == 32) ? 4 : 3; - - SDL_Surface *dst = SDL_CreateRGBSurface(SDL_SWSURFACE, - src->w / n, - src->h / n, - src->format->BitsPerPixel, - src->format->Rmask, - src->format->Gmask, - src->format->Bmask, - src->format->Amask); - if (dst) + const char *ext = filename + strlen(filename) - 4; + + if (strcmp(ext, ".png") == 0 || strcmp(ext, ".PNG") == 0) + return image_load_png(filename, width, height, bytes); + else if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".JPG") == 0) + return image_load_jpg(filename, width, height, bytes); + + return NULL; +} + +/*---------------------------------------------------------------------------*/ + +/* + * Allocate and return a power-of-two image buffer with the given pixel buffer + * centered within in. + */ +void *image_next2(const void *p, int w, int h, int b, int *w2, int *h2) +{ + unsigned char *src = (unsigned char *) p; + unsigned char *dst = NULL; + + int W; + int H; + + image_size(&W, &H, w, h); + + if ((dst = (unsigned char *) calloc(W * H * b, sizeof (unsigned char)))) { - SDL_LockSurface(src); - SDL_LockSurface(dst); - { - unsigned char *s = (unsigned char *) src->pixels; - unsigned char *d = (unsigned char *) dst->pixels; + int r, dr = (H - h) / 2; + int c, dc = (W - w) / 2; + int i; - /* Iterate each component of each distination pixel. */ + for (r = 0; r < h; ++r) + for (c = 0; c < w; ++c) + for (i = 0; i < b; ++i) + { + int R = r + dr; + int C = c + dc; - for (di = 0; di < src->h / n; di++) - for (dj = 0; dj < src->w / n; dj++) - for (k = 0; k < b; k++) - { - int c = 0; + dst[(R * W + C) * b + i] = src[(r * w + c) * b + i]; + } - /* Average the NxN source pixel block for each. */ + if (w2) *w2 = W; + if (h2) *h2 = H; + } - for (si = di * n; si < (di + 1) * n; si++) - for (sj = dj * n; sj < (dj + 1) * n; sj++) - c += s[(si * src->w + sj) * b + k]; + return dst; +} - d[(di * dst->w + dj) * b + k] = - (unsigned char) (c / (n * n)); - } - } - SDL_UnlockSurface(dst); - SDL_UnlockSurface(src); +/* + * Allocate and return a new down-sampled image buffer. + */ +void *image_scale(const void *p, int w, int h, int b, int *wn, int *hn, int n) +{ + unsigned char *src = (unsigned char *) p; + unsigned char *dst = NULL; + + int W = w / n; + int H = h / n; + + if ((dst = (unsigned char *) calloc(W * H * b, sizeof (unsigned char)))) + { + int si, di; + int sj, dj; + int i; + + /* Iterate each component of each destination pixel. */ + + for (di = 0; di < H; di++) + for (dj = 0; dj < W; dj++) + for (i = 0; i < b; i++) + { + int c = 0; + + /* Average the NxN source pixel block for each. */ + + for (si = di * n; si < (di + 1) * n; si++) + for (sj = dj * n; sj < (dj + 1) * n; sj++) + c += src[(si * w + sj) * b + i]; + + dst[(di * W + dj) * b + i] = + (unsigned char) (c / (n * n)); + } + + if (wn) *wn = W; + if (hn) *hn = H; } return dst; } +/* + * Whiten the RGB channels of the given image without touching any alpha. + */ +void image_white(void *p, int w, int h, int b) +{ + unsigned char *s = (unsigned char *) p; + + int r; + int c; + + for (r = 0; r < h; r++) + for (c = 0; c < w; c++) + { + int k = (r * w + c) * b; + + s[k + 0] = 0xFF; + + if (b > 2) + { + s[k + 1] = 0xFF; + s[k + 2] = 0xFF; + } + } +} + +/* + * Allocate and return an image buffer of the given image flipped horizontally + * and/or vertically. + */ +void *image_flip(const void *p, int w, int h, int b, int hflip, int vflip) +{ + unsigned char *q; + + assert(hflip || vflip); + + if (!p) + return NULL; + + if ((q = malloc(w * b * h))) + { + int r, c, i; + + for (r = 0; r < h; r++) + for (c = 0; c < w; c++) + for (i = 0; i < b; i++) + { + int pr = vflip ? h - r - 1 : r; + int pc = hflip ? w - c - 1 : c; + + int qi = r * w * b + c * b + i; + int pi = pr * w * b + pc * b + i; + + q[qi] = ((const unsigned char *) p)[pi]; + } + return q; + } + return NULL; +} + /*---------------------------------------------------------------------------*/