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.
21 #include "base_config.h"
22 #include "base_image.h"
28 /*---------------------------------------------------------------------------*/
30 void image_size(int *W
, int *H
, int w
, int h
)
32 /* Round the image size up to the next power-of-two. */
37 while (*W
< w
) *W
*= 2;
38 while (*H
< h
) *H
*= 2;
41 void image_near2(int *W
, int *H
, int w
, int h
)
43 image_size(W
, H
, w
, h
);
45 if (*W
> 1 && (*W
- w
> w
- (*W
/ 2)))
47 if (*H
> 1 && (*H
- h
> h
- (*H
/ 2)))
51 /*---------------------------------------------------------------------------*/
53 static void *image_load_png(const char *filename
, int *width
,
59 png_structp readp
= NULL
;
60 png_infop infop
= NULL
;
61 png_bytep
*bytep
= NULL
;
62 unsigned char *p
= NULL
;
64 /* Initialize all PNG import data structures. */
66 if (!(fh
= fs_open(filename
, "r")))
69 if (!(readp
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, 0, 0, 0)))
72 if (!(infop
= png_create_info_struct(readp
)))
75 /* Enable the default PNG error handler. */
77 if (setjmp(png_jmpbuf(readp
)) == 0)
81 /* Read the PNG header. */
83 png_set_read_fn(readp
, fh
, fs_png_read
);
84 png_read_info(readp
, infop
);
86 png_set_expand(readp
);
87 png_set_strip_16(readp
);
88 png_set_packing(readp
);
90 png_read_update_info(readp
, infop
);
92 /* Extract and check image properties. */
94 w
= (int) png_get_image_width (readp
, infop
);
95 h
= (int) png_get_image_height(readp
, infop
);
97 switch (png_get_color_type(readp
, infop
))
99 case PNG_COLOR_TYPE_GRAY
: b
= 1; break;
100 case PNG_COLOR_TYPE_GRAY_ALPHA
: b
= 2; break;
101 case PNG_COLOR_TYPE_RGB
: b
= 3; break;
102 case PNG_COLOR_TYPE_RGB_ALPHA
: b
= 4; break;
104 default: longjmp(png_jmpbuf(readp
), -1);
107 if (!(bytep
= png_malloc(readp
, h
* sizeof (png_bytep
))))
108 longjmp(png_jmpbuf(readp
), -1);
110 /* Allocate the final pixel buffer and read pixels there. */
112 if ((p
= (unsigned char *) malloc(w
* h
* b
)))
114 for (i
= 0; i
< h
; i
++)
115 bytep
[i
] = p
+ w
* b
* (h
- i
- 1);
117 png_read_image(readp
, bytep
);
118 png_read_end(readp
, NULL
);
120 if (width
) *width
= w
;
121 if (height
) *height
= h
;
122 if (bytes
) *bytes
= b
;
125 png_free(readp
, bytep
);
129 /* Free all resources. */
131 png_destroy_read_struct(&readp
, &infop
, NULL
);
137 static void *image_load_jpg(const char *filename
, int *width
,
141 unsigned char *p
= NULL
;
144 if ((fp
= fs_open(filename
, "r")))
146 struct jpeg_decompress_struct cinfo
;
147 struct jpeg_error_mgr jerr
;
151 /* Initialize the JPG decompressor. */
153 cinfo
.err
= jpeg_std_error(&jerr
);
154 jpeg_create_decompress(&cinfo
);
156 /* Set up a VFS source manager. */
158 fs_jpg_src(&cinfo
, fp
);
160 /* Grab the JPG header info. */
162 jpeg_read_header(&cinfo
, TRUE
);
163 jpeg_start_decompress(&cinfo
);
165 w
= cinfo
.output_width
;
166 h
= cinfo
.output_height
;
167 b
= cinfo
.output_components
;
169 /* Allocate the final pixel buffer and copy pixels there. */
171 if ((p
= (unsigned char *) malloc (w
* h
* b
)))
173 while (cinfo
.output_scanline
< cinfo
.output_height
)
175 unsigned char *buffer
= p
+ w
* b
* (h
- i
- 1);
176 i
+= jpeg_read_scanlines(&cinfo
, &buffer
, 1);
179 if (width
) *width
= w
;
180 if (height
) *height
= h
;
181 if (bytes
) *bytes
= b
;
184 jpeg_finish_decompress(&cinfo
);
185 jpeg_destroy_decompress(&cinfo
);
193 void *image_load(const char *filename
, int *width
,
199 const char *ext
= filename
+ strlen(filename
) - 4;
201 if (strcmp(ext
, ".png") == 0 || strcmp(ext
, ".PNG") == 0)
202 return image_load_png(filename
, width
, height
, bytes
);
203 else if (strcmp(ext
, ".jpg") == 0 || strcmp(ext
, ".JPG") == 0)
204 return image_load_jpg(filename
, width
, height
, bytes
);
209 /*---------------------------------------------------------------------------*/
212 * Allocate and return a power-of-two image buffer with the given pixel buffer
213 * centered within in.
215 void *image_next2(const void *p
, int w
, int h
, int b
, int *w2
, int *h2
)
217 unsigned char *src
= (unsigned char *) p
;
218 unsigned char *dst
= NULL
;
223 image_size(&W
, &H
, w
, h
);
225 if ((dst
= (unsigned char *) calloc(W
* H
* b
, sizeof (unsigned char))))
227 const int dr
= (H
- h
) / 2;
228 const int dc
= (W
- w
) / 2;
232 for (r
= 0; r
< h
; ++r
)
234 const int R
= r
+ dr
;
237 memcpy(&dst
[(R
* W
+ C
) * b
], &src
[(r
* w
) * b
], w
* b
);
248 * Allocate and return a new down-sampled image buffer.
250 void *image_scale(const void *p
, int w
, int h
, int b
, int *wn
, int *hn
, int n
)
252 unsigned char *src
= (unsigned char *) p
;
253 unsigned char *dst
= NULL
;
258 if ((dst
= (unsigned char *) calloc(W
* H
* b
, sizeof (unsigned char))))
264 /* Iterate each component of each destination pixel. */
266 for (di
= 0; di
< H
; di
++)
267 for (dj
= 0; dj
< W
; dj
++)
268 for (i
= 0; i
< b
; i
++)
272 /* Average the NxN source pixel block for each. */
274 for (si
= di
* n
; si
< (di
+ 1) * n
; si
++)
275 for (sj
= dj
* n
; sj
< (dj
+ 1) * n
; sj
++)
276 c
+= src
[(si
* w
+ sj
) * b
+ i
];
278 dst
[(di
* W
+ dj
) * b
+ i
] =
279 (unsigned char) (c
/ (n
* n
));
290 * Whiten the RGB channels of the given image without touching any alpha.
292 void image_white(void *p
, int w
, int h
, int b
)
294 unsigned char *s
= (unsigned char *) p
;
298 assert(b
>= 1 && b
<= 4);
300 if (b
== 1 || b
== 3)
302 memset(s
, 0xFF, w
* h
* b
);
306 for (i
= 0; i
< w
* h
* b
; i
+= 2)
311 for (i
= 0; i
< w
* h
* b
; i
+= 4)
321 * Allocate and return an image buffer of the given image flipped horizontally
324 void *image_flip(const void *p
, int w
, int h
, int b
, int hflip
, int vflip
)
328 assert(hflip
|| vflip
);
333 if ((q
= malloc(w
* b
* h
)))
337 for (r
= 0; r
< h
; r
++)
338 for (c
= 0; c
< w
; c
++)
339 for (i
= 0; i
< b
; i
++)
341 int pr
= vflip
? h
- r
- 1 : r
;
342 int pc
= hflip
? w
- c
- 1 : c
;
344 int qi
= r
* w
* b
+ c
* b
+ i
;
345 int pi
= pr
* w
* b
+ pc
* b
+ i
;
347 q
[qi
] = ((const unsigned char *) p
)[pi
];
354 /*---------------------------------------------------------------------------*/