1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2007 The Android Open Source Project
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Licensed under the Apache License, Version 2.0 (the "License");
5*4882a593Smuzhiyun * you may not use this file except in compliance with the License.
6*4882a593Smuzhiyun * You may obtain a copy of the License at
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * http://www.apache.org/licenses/LICENSE-2.0
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Unless required by applicable law or agreed to in writing, software
11*4882a593Smuzhiyun * distributed under the License is distributed on an "AS IS" BASIS,
12*4882a593Smuzhiyun * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4882a593Smuzhiyun * See the License for the specific language governing permissions and
14*4882a593Smuzhiyun * limitations under the License.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <stdlib.h>
18*4882a593Smuzhiyun #include <unistd.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <fcntl.h>
21*4882a593Smuzhiyun #include <stdio.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include <sys/ioctl.h>
24*4882a593Smuzhiyun #include <sys/mman.h>
25*4882a593Smuzhiyun #include <sys/types.h>
26*4882a593Smuzhiyun #include <string.h>
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <linux/fb.h>
29*4882a593Smuzhiyun #include <linux/kd.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include <png.h>
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #include "minui.h"
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun extern char* locale;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define SURFACE_DATA_ALIGNMENT 8
38*4882a593Smuzhiyun
malloc_surface(size_t data_size)39*4882a593Smuzhiyun static gr_surface malloc_surface(size_t data_size)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun unsigned char* temp = malloc(sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT);
42*4882a593Smuzhiyun if (temp == NULL) return NULL;
43*4882a593Smuzhiyun gr_surface surface = (gr_surface) temp;
44*4882a593Smuzhiyun surface->data = temp + sizeof(GRSurface) +
45*4882a593Smuzhiyun (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT));
46*4882a593Smuzhiyun return surface;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
open_png(const char * name,png_structp * png_ptr,png_infop * info_ptr,png_uint_32 * width,png_uint_32 * height,png_byte * channels)49*4882a593Smuzhiyun static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr,
50*4882a593Smuzhiyun png_uint_32* width, png_uint_32* height, png_byte* channels)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun char resPath[256];
53*4882a593Smuzhiyun unsigned char header[8];
54*4882a593Smuzhiyun int result = 0;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun snprintf(resPath, sizeof(resPath) - 1, "/res/images/%s.png", name);
57*4882a593Smuzhiyun resPath[sizeof(resPath) - 1] = '\0';
58*4882a593Smuzhiyun FILE* fp = fopen(resPath, "rb");
59*4882a593Smuzhiyun if (fp == NULL) {
60*4882a593Smuzhiyun result = -1;
61*4882a593Smuzhiyun goto exit;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun size_t bytesRead = fread(header, 1, sizeof(header), fp);
65*4882a593Smuzhiyun if (bytesRead != sizeof(header)) {
66*4882a593Smuzhiyun result = -2;
67*4882a593Smuzhiyun goto exit;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun if (png_sig_cmp(header, 0, sizeof(header))) {
71*4882a593Smuzhiyun result = -3;
72*4882a593Smuzhiyun goto exit;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
76*4882a593Smuzhiyun if (!*png_ptr) {
77*4882a593Smuzhiyun result = -4;
78*4882a593Smuzhiyun goto exit;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun *info_ptr = png_create_info_struct(*png_ptr);
82*4882a593Smuzhiyun if (!*info_ptr) {
83*4882a593Smuzhiyun result = -5;
84*4882a593Smuzhiyun goto exit;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (setjmp(png_jmpbuf(*png_ptr))) {
88*4882a593Smuzhiyun result = -6;
89*4882a593Smuzhiyun goto exit;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun png_init_io(*png_ptr, fp);
93*4882a593Smuzhiyun png_set_sig_bytes(*png_ptr, sizeof(header));
94*4882a593Smuzhiyun png_read_info(*png_ptr, *info_ptr);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun int color_type, bit_depth;
97*4882a593Smuzhiyun png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth,
98*4882a593Smuzhiyun &color_type, NULL, NULL, NULL);
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun *channels = png_get_channels(*png_ptr, *info_ptr);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) {
103*4882a593Smuzhiyun // 8-bit RGB images: great, nothing to do.
104*4882a593Smuzhiyun } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) {
105*4882a593Smuzhiyun // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray.
106*4882a593Smuzhiyun png_set_expand_gray_1_2_4_to_8(*png_ptr);
107*4882a593Smuzhiyun } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) {
108*4882a593Smuzhiyun // paletted images: expand to 8-bit RGB. Note that we DON'T
109*4882a593Smuzhiyun // currently expand the tRNS chunk (if any) to an alpha
110*4882a593Smuzhiyun // channel, because minui doesn't support alpha channels in
111*4882a593Smuzhiyun // general.
112*4882a593Smuzhiyun png_set_palette_to_rgb(*png_ptr);
113*4882a593Smuzhiyun *channels = 3;
114*4882a593Smuzhiyun } else {
115*4882a593Smuzhiyun fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n",
116*4882a593Smuzhiyun bit_depth, *channels, color_type);
117*4882a593Smuzhiyun result = -7;
118*4882a593Smuzhiyun goto exit;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun return result;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun exit:
124*4882a593Smuzhiyun if (result < 0) {
125*4882a593Smuzhiyun png_destroy_read_struct(png_ptr, info_ptr, NULL);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun if (fp != NULL) {
128*4882a593Smuzhiyun fclose(fp);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun return result;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun // "display" surfaces are transformed into the framebuffer's required
135*4882a593Smuzhiyun // pixel format (currently only RGBX is supported) at load time, so
136*4882a593Smuzhiyun // gr_blit() can be nothing more than a memcpy() for each row. The
137*4882a593Smuzhiyun // next two functions are the only ones that know anything about the
138*4882a593Smuzhiyun // framebuffer pixel format; they need to be modified if the
139*4882a593Smuzhiyun // framebuffer format changes (but nothing else should).
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun // Allocate and return a gr_surface sufficient for storing an image of
142*4882a593Smuzhiyun // the indicated size in the framebuffer pixel format.
init_display_surface(png_uint_32 width,png_uint_32 height)143*4882a593Smuzhiyun static gr_surface init_display_surface(png_uint_32 width, png_uint_32 height)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun gr_surface surface;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun surface = malloc_surface(width * height * 4);
148*4882a593Smuzhiyun if (surface == NULL) return NULL;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun surface->width = width;
151*4882a593Smuzhiyun surface->height = height;
152*4882a593Smuzhiyun surface->row_bytes = width * 4;
153*4882a593Smuzhiyun surface->pixel_bytes = 4;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun return surface;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun // Copy 'input_row' to 'output_row', transforming it to the
159*4882a593Smuzhiyun // framebuffer pixel format. The input format depends on the value of
160*4882a593Smuzhiyun // 'channels':
161*4882a593Smuzhiyun //
162*4882a593Smuzhiyun // 1 - input is 8-bit grayscale
163*4882a593Smuzhiyun // 3 - input is 24-bit RGB
164*4882a593Smuzhiyun // 4 - input is 32-bit RGBA/RGBX
165*4882a593Smuzhiyun //
166*4882a593Smuzhiyun // 'width' is the number of pixels in the row.
transform_rgb_to_draw(unsigned char * input_row,unsigned char * output_row,int channels,int width)167*4882a593Smuzhiyun static void transform_rgb_to_draw(unsigned char* input_row,
168*4882a593Smuzhiyun unsigned char* output_row,
169*4882a593Smuzhiyun int channels, int width)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun int x;
172*4882a593Smuzhiyun unsigned char* ip = input_row;
173*4882a593Smuzhiyun unsigned char* op = output_row;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun switch (channels) {
176*4882a593Smuzhiyun case 1:
177*4882a593Smuzhiyun // expand gray level to RGBX
178*4882a593Smuzhiyun for (x = 0; x < width; ++x) {
179*4882a593Smuzhiyun *op++ = *ip;
180*4882a593Smuzhiyun *op++ = *ip;
181*4882a593Smuzhiyun *op++ = *ip;
182*4882a593Smuzhiyun *op++ = 0xff;
183*4882a593Smuzhiyun ip++;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun break;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun case 3:
188*4882a593Smuzhiyun // expand RGBA to RGBX
189*4882a593Smuzhiyun for (x = 0; x < width; ++x) {
190*4882a593Smuzhiyun *op++ = *ip++;
191*4882a593Smuzhiyun *op++ = *ip++;
192*4882a593Smuzhiyun *op++ = *ip++;
193*4882a593Smuzhiyun *op++ = 0xff;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun break;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun case 4:
198*4882a593Smuzhiyun // copy RGBA to RGBX
199*4882a593Smuzhiyun memcpy(output_row, input_row, width * 4);
200*4882a593Smuzhiyun break;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
res_create_display_surface(const char * name,gr_surface * pSurface)204*4882a593Smuzhiyun int res_create_display_surface(const char* name, gr_surface* pSurface)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun gr_surface surface = NULL;
207*4882a593Smuzhiyun int result = 0;
208*4882a593Smuzhiyun png_structp png_ptr = NULL;
209*4882a593Smuzhiyun png_infop info_ptr = NULL;
210*4882a593Smuzhiyun png_uint_32 width, height;
211*4882a593Smuzhiyun png_byte channels;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun *pSurface = NULL;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
216*4882a593Smuzhiyun if (result < 0) return result;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun surface = init_display_surface(width, height);
219*4882a593Smuzhiyun if (surface == NULL) {
220*4882a593Smuzhiyun result = -8;
221*4882a593Smuzhiyun goto exit;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun unsigned char* p_row = malloc(width * 4);
225*4882a593Smuzhiyun unsigned int y;
226*4882a593Smuzhiyun for (y = 0; y < height; ++y) {
227*4882a593Smuzhiyun png_read_row(png_ptr, p_row, NULL);
228*4882a593Smuzhiyun transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun free(p_row);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun *pSurface = surface;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun exit:
235*4882a593Smuzhiyun png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
236*4882a593Smuzhiyun if (result < 0 && surface != NULL) free(surface);
237*4882a593Smuzhiyun return result;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
res_create_multi_display_surface(const char * name,int * frames,gr_surface ** pSurface)240*4882a593Smuzhiyun int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun gr_surface* surface = NULL;
243*4882a593Smuzhiyun int result = 0;
244*4882a593Smuzhiyun png_structp png_ptr = NULL;
245*4882a593Smuzhiyun png_infop info_ptr = NULL;
246*4882a593Smuzhiyun png_uint_32 width, height;
247*4882a593Smuzhiyun png_byte channels;
248*4882a593Smuzhiyun int i;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun *pSurface = NULL;
251*4882a593Smuzhiyun *frames = -1;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
254*4882a593Smuzhiyun if (result < 0) return result;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun *frames = 1;
257*4882a593Smuzhiyun png_textp text;
258*4882a593Smuzhiyun int num_text;
259*4882a593Smuzhiyun if (png_get_text(png_ptr, info_ptr, &text, &num_text)) {
260*4882a593Smuzhiyun for (i = 0; i < num_text; ++i) {
261*4882a593Smuzhiyun if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) {
262*4882a593Smuzhiyun *frames = atoi(text[i].text);
263*4882a593Smuzhiyun break;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun printf(" found frames = %d\n", *frames);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun if (height % *frames != 0) {
270*4882a593Smuzhiyun printf("bad height (%d) for frame count (%d)\n", height, *frames);
271*4882a593Smuzhiyun result = -9;
272*4882a593Smuzhiyun goto exit;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun surface = malloc(*frames * sizeof(gr_surface));
276*4882a593Smuzhiyun if (surface == NULL) {
277*4882a593Smuzhiyun result = -8;
278*4882a593Smuzhiyun goto exit;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun for (i = 0; i < *frames; ++i) {
281*4882a593Smuzhiyun surface[i] = init_display_surface(width, height / *frames);
282*4882a593Smuzhiyun if (surface[i] == NULL) {
283*4882a593Smuzhiyun result = -8;
284*4882a593Smuzhiyun goto exit;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun unsigned char* p_row = malloc(width * 4);
289*4882a593Smuzhiyun unsigned int y;
290*4882a593Smuzhiyun for (y = 0; y < height; ++y) {
291*4882a593Smuzhiyun png_read_row(png_ptr, p_row, NULL);
292*4882a593Smuzhiyun int frame = y % *frames;
293*4882a593Smuzhiyun unsigned char* out_row = surface[frame]->data +
294*4882a593Smuzhiyun (y / *frames) * surface[frame]->row_bytes;
295*4882a593Smuzhiyun transform_rgb_to_draw(p_row, out_row, channels, width);
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun free(p_row);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun *pSurface = (gr_surface*) surface;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun exit:
302*4882a593Smuzhiyun png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun if (result < 0) {
305*4882a593Smuzhiyun if (surface) {
306*4882a593Smuzhiyun for (i = 0; i < *frames; ++i) {
307*4882a593Smuzhiyun if (surface[i]) free(surface[i]);
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun free(surface);
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun return result;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
res_create_alpha_surface(const char * name,gr_surface * pSurface)315*4882a593Smuzhiyun int res_create_alpha_surface(const char* name, gr_surface* pSurface)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun gr_surface surface = NULL;
318*4882a593Smuzhiyun int result = 0;
319*4882a593Smuzhiyun png_structp png_ptr = NULL;
320*4882a593Smuzhiyun png_infop info_ptr = NULL;
321*4882a593Smuzhiyun png_uint_32 width, height;
322*4882a593Smuzhiyun png_byte channels;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun *pSurface = NULL;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
327*4882a593Smuzhiyun if (result < 0) return result;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (channels != 1) {
330*4882a593Smuzhiyun result = -7;
331*4882a593Smuzhiyun goto exit;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun surface = malloc_surface(width * height);
335*4882a593Smuzhiyun if (surface == NULL) {
336*4882a593Smuzhiyun result = -8;
337*4882a593Smuzhiyun goto exit;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun surface->width = width;
340*4882a593Smuzhiyun surface->height = height;
341*4882a593Smuzhiyun surface->row_bytes = width;
342*4882a593Smuzhiyun surface->pixel_bytes = 1;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun unsigned char* p_row;
345*4882a593Smuzhiyun unsigned int y;
346*4882a593Smuzhiyun for (y = 0; y < height; ++y) {
347*4882a593Smuzhiyun p_row = surface->data + y * surface->row_bytes;
348*4882a593Smuzhiyun png_read_row(png_ptr, p_row, NULL);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun *pSurface = surface;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun exit:
354*4882a593Smuzhiyun png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
355*4882a593Smuzhiyun if (result < 0 && surface != NULL) free(surface);
356*4882a593Smuzhiyun return result;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
matches_locale(const char * loc,const char * locale)359*4882a593Smuzhiyun static int matches_locale(const char* loc, const char* locale)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun if (locale == NULL) return 0;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun if (strcmp(loc, locale) == 0) return 1;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun // if loc does *not* have an underscore, and it matches the start
366*4882a593Smuzhiyun // of locale, and the next character in locale *is* an underscore,
367*4882a593Smuzhiyun // that's a match. For instance, loc == "en" matches locale ==
368*4882a593Smuzhiyun // "en_US".
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun int i;
371*4882a593Smuzhiyun for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);
372*4882a593Smuzhiyun if (loc[i] == '_') return 0;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun return (strncmp(locale, loc, i) == 0 && locale[i] == '_');
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
res_create_localized_alpha_surface(const char * name,const char * locale,gr_surface * pSurface)377*4882a593Smuzhiyun int res_create_localized_alpha_surface(const char* name,
378*4882a593Smuzhiyun const char* locale,
379*4882a593Smuzhiyun gr_surface* pSurface)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun gr_surface surface = NULL;
382*4882a593Smuzhiyun int result = 0;
383*4882a593Smuzhiyun png_structp png_ptr = NULL;
384*4882a593Smuzhiyun png_infop info_ptr = NULL;
385*4882a593Smuzhiyun png_uint_32 width, height;
386*4882a593Smuzhiyun png_byte channels;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun *pSurface = NULL;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun if (locale == NULL) {
391*4882a593Smuzhiyun surface = malloc_surface(0);
392*4882a593Smuzhiyun surface->width = 0;
393*4882a593Smuzhiyun surface->height = 0;
394*4882a593Smuzhiyun surface->row_bytes = 0;
395*4882a593Smuzhiyun surface->pixel_bytes = 1;
396*4882a593Smuzhiyun goto exit;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
400*4882a593Smuzhiyun if (result < 0) return result;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun if (channels != 1) {
403*4882a593Smuzhiyun result = -7;
404*4882a593Smuzhiyun goto exit;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun unsigned char* row = malloc(width);
408*4882a593Smuzhiyun png_uint_32 y;
409*4882a593Smuzhiyun for (y = 0; y < height; ++y) {
410*4882a593Smuzhiyun png_read_row(png_ptr, row, NULL);
411*4882a593Smuzhiyun int w = (row[1] << 8) | row[0];
412*4882a593Smuzhiyun int h = (row[3] << 8) | row[2];
413*4882a593Smuzhiyun int len = row[4];
414*4882a593Smuzhiyun char* loc = (char*)row + 5;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun if (y + 1 + h >= height || matches_locale(loc, locale)) {
417*4882a593Smuzhiyun printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun surface = malloc_surface(w * h);
420*4882a593Smuzhiyun if (surface == NULL) {
421*4882a593Smuzhiyun result = -8;
422*4882a593Smuzhiyun goto exit;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun surface->width = w;
425*4882a593Smuzhiyun surface->height = h;
426*4882a593Smuzhiyun surface->row_bytes = w;
427*4882a593Smuzhiyun surface->pixel_bytes = 1;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun int i;
430*4882a593Smuzhiyun for (i = 0; i < h; ++i, ++y) {
431*4882a593Smuzhiyun png_read_row(png_ptr, row, NULL);
432*4882a593Smuzhiyun memcpy(surface->data + i * w, row, w);
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun *pSurface = (gr_surface) surface;
436*4882a593Smuzhiyun break;
437*4882a593Smuzhiyun } else {
438*4882a593Smuzhiyun int i;
439*4882a593Smuzhiyun for (i = 0; i < h; ++i, ++y) {
440*4882a593Smuzhiyun png_read_row(png_ptr, row, NULL);
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun exit:
446*4882a593Smuzhiyun png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
447*4882a593Smuzhiyun if (result < 0 && surface != NULL) free(surface);
448*4882a593Smuzhiyun return result;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun
res_free_surface(gr_surface surface)451*4882a593Smuzhiyun void res_free_surface(gr_surface surface)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun free(surface);
454*4882a593Smuzhiyun }
455