1 /*
2 * OpenBOR - http://www.LavaLit.com
3 * -----------------------------------------------------------------------
4 * Licensed under the BSD license, see LICENSE in OpenBOR root for details.
5 *
6 * Copyright (c) 2004 - 2011 OpenBOR Team
7 */
8
9 #include <png.h>
10 #include "types.h"
11 #include "screen.h"
12 #include <assert.h>
13
14 #ifdef SDL
15 #include "SDL.h"
16 #endif
17
18 #if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 2 && PNG_LIBPNG_VER_RELEASE < 9
png_set_expand_gray_1_2_4_to_8(png_structp png_ptr)19 void png_set_expand_gray_1_2_4_to_8(png_structp png_ptr) { png_set_gray_1_2_4_to_8(png_ptr); }
20 #endif
21
png_warning_fn(png_structp png_ptr,png_const_charp warning_msg)22 static void png_warning_fn(png_structp png_ptr, png_const_charp warning_msg)
23 {
24 }
25
png_read_fn(png_structp pngp,png_bytep outp,png_size_t size)26 static void png_read_fn(png_structp pngp, png_bytep outp, png_size_t size)
27 {
28 char** ptr = (char**)png_get_io_ptr(pngp);
29 memcpy(outp, *ptr, size);
30 *ptr += size;
31 }
32
pngToScreen(const void * data)33 s_screen* pngToScreen(const void* data)
34 {
35 png_structp png_ptr;
36 png_infop info_ptr;
37 unsigned int sig_read = 0;
38 png_uint_32 width, height;
39 int bit_depth, color_type, interlace_type, y;
40 u32* line;
41 s_screen* image;
42
43 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
44 if(png_ptr == NULL) goto error;
45 png_set_error_fn(png_ptr, (png_voidp) NULL, (png_error_ptr) NULL, png_warning_fn);
46 info_ptr = png_create_info_struct(png_ptr);
47 if(info_ptr == NULL) goto error2;
48 if(setjmp(png_jmpbuf(png_ptr))) goto error2;
49
50 png_set_read_fn(png_ptr, &data, png_read_fn);
51 png_set_sig_bytes(png_ptr, sig_read);
52 png_read_info(png_ptr, info_ptr);
53 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
54
55 png_set_strip_16(png_ptr);
56 png_set_packing(png_ptr);
57 if(color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr);
58 if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr);
59 if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);
60 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
61
62 image = allocscreen(width, height, PIXEL_32);
63 if(image == NULL) goto error2;
64
65 line = (u32*)image->data;
66 for(y=0; y<height; y++)
67 {
68 png_read_row(png_ptr, (u8*) line, NULL);
69 line += width;
70 }
71 png_read_end(png_ptr, info_ptr);
72 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
73 return image;
74
75 error2:
76 png_destroy_read_struct(&png_ptr, NULL, NULL);
77 error:
78 return NULL;
79 }
80
81 #ifdef SDL
pngToSurface(const void * data)82 SDL_Surface* pngToSurface(const void* data)
83 {
84 unsigned char *sp;
85 char *dp;
86 int width, height, linew;
87 int h;
88 SDL_Surface* ds = NULL;
89 s_screen* src = pngToScreen(data);
90
91 if(src == NULL) return NULL;
92 assert(src->pixelformat == PIXEL_32);
93
94 width = src->width;
95 height = src->height;
96 h = height;
97
98 sp = (unsigned char*)src->data;
99 ds = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0xff, 0xff00, 0xff0000, 0);
100 dp = ds->pixels;
101
102 linew = width*4;
103
104 do{
105 memcpy(dp, sp, linew);
106 sp += linew;
107 dp += ds->pitch;
108 }while(--h);
109
110 freescreen(&src);
111
112 return ds;
113 }
114 #endif
115
116