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