2 * Copyright (C) 2003 Robert Kooima
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
20 #include "base_config.h"
21 #include "base_image.h"
27 /*---------------------------------------------------------------------------*/
29 void image_size(int *W, int *H, int w, int h)
31 /* Round the image size up to the next power-of-two. */
36 while (*W < w) *W *= 2;
37 while (*H < h) *H *= 2;
40 /*---------------------------------------------------------------------------*/
42 static void *image_load_png(const char *filename, int *width,
48 png_structp readp = NULL;
49 png_infop infop = NULL;
50 png_bytep *bytep = NULL;
51 unsigned char *p = NULL;
53 /* Initialize all PNG import data structures. */
55 if (!(fh = fs_open(filename, "r")))
58 if (!(readp = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0)))
61 if (!(infop = png_create_info_struct(readp)))
64 /* Enable the default PNG error handler. */
66 if (setjmp(png_jmpbuf(readp)) == 0)
70 /* Read the PNG header. */
72 png_set_read_fn(readp, fh, fs_png_read);
73 png_read_info(readp, infop);
75 png_set_expand(readp);
76 png_set_strip_16(readp);
77 png_set_packing(readp);
79 png_read_update_info(readp, infop);
81 /* Extract and check image properties. */
83 w = (int) png_get_image_width (readp, infop);
84 h = (int) png_get_image_height(readp, infop);
86 switch (png_get_color_type(readp, infop))
88 case PNG_COLOR_TYPE_GRAY: b = 1; break;
89 case PNG_COLOR_TYPE_GRAY_ALPHA: b = 2; break;
90 case PNG_COLOR_TYPE_RGB: b = 3; break;
91 case PNG_COLOR_TYPE_RGB_ALPHA: b = 4; break;
93 default: longjmp(png_jmpbuf(readp), -1);
96 if (!(bytep = png_malloc(readp, h * png_sizeof(png_bytep))))
97 longjmp(png_jmpbuf(readp), -1);
99 /* Allocate the final pixel buffer and read pixels there. */
101 if ((p = (unsigned char *) malloc(w * h * b)))
103 for (i = 0; i < h; i++)
104 bytep[i] = p + w * b * (h - i - 1);
106 png_read_image(readp, bytep);
107 png_read_end(readp, NULL);
109 if (width) *width = w;
110 if (height) *height = h;
111 if (bytes) *bytes = b;
114 png_free(readp, bytep);
118 /* Free all resources. */
120 png_destroy_read_struct(&readp, &infop, NULL);
126 static void *image_load_jpg(const char *filename, int *width,
130 unsigned char *p = NULL;
133 if ((fp = fs_open(filename, "r")))
135 struct jpeg_decompress_struct cinfo;
136 struct jpeg_error_mgr jerr;
140 /* Initialize the JPG decompressor. */
142 cinfo.err = jpeg_std_error(&jerr);
143 jpeg_create_decompress(&cinfo);
145 /* Set up a VFS source manager. */
147 fs_jpg_src(&cinfo, fp);
149 /* Grab the JPG header info. */
151 jpeg_read_header(&cinfo, TRUE);
152 jpeg_start_decompress(&cinfo);
154 w = cinfo.output_width;
155 h = cinfo.output_height;
156 b = cinfo.output_components;
158 /* Allocate the final pixel buffer and copy pixels there. */
160 if ((p = (unsigned char *) malloc (w * h * b)))
162 while (cinfo.output_scanline < cinfo.output_height)
164 unsigned char *buffer = p + w * b * (h - i - 1);
165 i += jpeg_read_scanlines(&cinfo, &buffer, 1);
168 if (width) *width = w;
169 if (height) *height = h;
170 if (bytes) *bytes = b;
173 jpeg_finish_decompress(&cinfo);
174 jpeg_destroy_decompress(&cinfo);
182 void *image_load(const char *filename, int *width,
186 const char *ext = filename + strlen(filename) - 4;
188 if (strcmp(ext, ".png") == 0 || strcmp(ext, ".PNG") == 0)
189 return image_load_png(filename, width, height, bytes);
190 else if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".JPG") == 0)
191 return image_load_jpg(filename, width, height, bytes);
196 /*---------------------------------------------------------------------------*/
199 * Allocate and return a power-of-two image buffer with the given pixel buffer
200 * centered within in.
202 void *image_next2(const void *p, int w, int h, int b, int *w2, int *h2)
204 unsigned char *src = (unsigned char *) p;
205 unsigned char *dst = NULL;
210 image_size(&W, &H, w, h);
212 if ((dst = (unsigned char *) calloc(W * H * b, sizeof (unsigned char))))
214 int r, dr = (H - h) / 2;
215 int c, dc = (W - w) / 2;
218 for (r = 0; r < h; ++r)
219 for (c = 0; c < w; ++c)
220 for (i = 0; i < b; ++i)
225 dst[(R * W + C) * b + i] = src[(r * w + c) * b + i];
236 * Allocate and return a new down-sampled image buffer.
238 void *image_scale(const void *p, int w, int h, int b, int *wn, int *hn, int n)
240 unsigned char *src = (unsigned char *) p;
241 unsigned char *dst = NULL;
246 if ((dst = (unsigned char *) calloc(W * H * b, sizeof (unsigned char))))
252 /* Iterate each component of each destination pixel. */
254 for (di = 0; di < H; di++)
255 for (dj = 0; dj < W; dj++)
256 for (i = 0; i < b; i++)
260 /* Average the NxN source pixel block for each. */
262 for (si = di * n; si < (di + 1) * n; si++)
263 for (sj = dj * n; sj < (dj + 1) * n; sj++)
264 c += src[(si * w + sj) * b + i];
266 dst[(di * W + dj) * b + i] =
267 (unsigned char) (c / (n * n));
278 * Whiten the RGB channels of the given image without touching any alpha.
280 void image_white(void *p, int w, int h, int b)
282 unsigned char *s = (unsigned char *) p;
287 for (r = 0; r < h; r++)
288 for (c = 0; c < w; c++)
290 int k = (r * w + c) * b;
303 * Allocate and return an image buffer of the given image flipped horizontally
306 void *image_flip(const void *p, int w, int h, int b, int hflip, int vflip)
310 assert(hflip || vflip);
315 if ((q = malloc(w * b * h)))
319 for (r = 0; r < h; r++)
320 for (c = 0; c < w; c++)
321 for (i = 0; i < b; i++)
323 int pr = vflip ? h - r - 1 : r;
324 int pc = hflip ? w - c - 1 : c;
326 int qi = r * w * b + c * b + i;
327 int pi = pr * w * b + pc * b + i;
329 q[qi] = ((const unsigned char *) p)[pi];
336 /*---------------------------------------------------------------------------*/