1 /************************************************************************
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
28 static void user_read_fn(png_structp png_ptr
, png_bytep buffer
, png_size_t size
)
30 file_t
*data
= png_get_io_ptr(png_ptr
);
31 if( data
->len
&& (data
->pos
+ size
) > data
->len
)
33 png_error(png_ptr
, "read error loading image");
37 memcpy(buffer
, data
->data
+ data
->pos
, size
);
41 /* is it a png image? */
42 int image_is_png(file_t
*f
)
44 return png_check_sig(f
->data
, 4);
47 /* load a png image to pixel data */
48 int image_load_png(file_t
*f
, image_t
*p
)
52 unsigned int sig_read
= 0;
53 png_uint_32 width
, height
;
60 png_bytep
*row_pointers
;
62 png_ptr
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
66 png_set_error_fn(png_ptr
, NULL
, NULL
, NULL
);
67 png_set_read_fn(png_ptr
, (png_voidp
)f
, user_read_fn
);
68 info_ptr
= png_create_info_struct(png_ptr
);
70 png_destroy_read_struct(&png_ptr
, NULL
, NULL
);
74 /* this is libpng's error handling, if something goes bad we'll
75 * end up jumping back here where we can exit gracefullyish */
76 if (setjmp(png_jmpbuf(png_ptr
))) {
77 png_destroy_read_struct(&png_ptr
, &info_ptr
, NULL
);
81 png_init_io(png_ptr
, (FILE*)f
);
82 png_set_sig_bytes(png_ptr
, sig_read
);
83 png_read_info(png_ptr
, info_ptr
);
84 png_get_IHDR(png_ptr
, info_ptr
, &width
, &height
, &bit_depth
, &color_type
, &interlace_type
, NULL
, NULL
);
89 if (color_type
== PNG_COLOR_TYPE_PALETTE
)
90 png_set_expand(png_ptr
);
91 if (color_type
== PNG_COLOR_TYPE_GRAY
&& bit_depth
< 8)
92 png_set_expand(png_ptr
);
93 if (png_get_valid(png_ptr
, info_ptr
, PNG_INFO_tRNS
))
94 png_set_expand(png_ptr
);
96 png_read_update_info(png_ptr
, info_ptr
);
98 /* get the size of image rows in bytes */
99 rowbytes
= png_get_rowbytes(png_ptr
, info_ptr
);
100 bpp
= rowbytes
/width
;
102 p
->pixels
= malloc(sizeof(png_byte
)*(rowbytes
* height
));
104 png_destroy_read_struct(&png_ptr
, &info_ptr
, NULL
);
108 /* libpng reads by row, not by chunk, so we need row pointers to load to */
109 row_pointers
= alloca(sizeof(png_bytep
)*height
);
111 png_destroy_read_struct(&png_ptr
, &info_ptr
, NULL
);
116 /* and this ensures the rows point to the correct place in the pixel data */
117 for (i
=0; i
< height
; ++i
) {
118 row_pointers
[i
] = p
->pixels
+ i
* rowbytes
;
121 /* finally let libpng read everything in */
122 png_read_image(png_ptr
, row_pointers
);
124 png_destroy_read_struct(&png_ptr
, &info_ptr
, NULL
);
126 /* check for a 32bit RGBA image */
128 /* convert 24bit RGB to 32bit RGBA */
131 int m
= rowbytes
*height
;
132 unsigned char *px
= p
->pixels
;
133 p
->pixels
= malloc(p
->w
*p
->h
*4);
134 for (i
=0; i
<m
; i
+=3) {
135 p
->pixels
[j
++] = px
[i
];
136 p
->pixels
[j
++] = px
[i
+1];
137 p
->pixels
[j
++] = px
[i
+2];
138 p
->pixels
[j
++] = 255;
141 /* unsupported image */
143 vlprintf("PNG: unsupported image format: %dbpp",bpp
);
152 /* write pixel data to a png image */
153 int image_save_png(image_t
*p
, char* file
)
161 png_bytep
*row_pointers
;
163 if (!path_get(NULL
,file
,0,buff
,2048))
165 f
= fopen(buff
,"wb");
169 png_ptr
= png_create_write_struct(PNG_LIBPNG_VER_STRING
,NULL
,NULL
,NULL
);
175 /* Allocate/initialize the image information data. REQUIRED */
176 info_ptr
= png_create_info_struct(png_ptr
);
179 png_destroy_write_struct(&png_ptr
, (png_infopp
)NULL
);
183 /* this is libpng's error handling, if something goes bad we'll
184 * end up jumping back here where we can exit gracefullyish */
185 if (setjmp(png_jmpbuf(png_ptr
))) {
187 png_destroy_write_struct(&png_ptr
, (png_infopp
)NULL
);
191 png_init_io(png_ptr
, f
);
193 png_set_compression_level(png_ptr
, 9);
201 PNG_COLOR_TYPE_RGB_ALPHA
,
203 PNG_COMPRESSION_TYPE_BASE
,
207 /* Write the file header information */
208 png_write_info(png_ptr
, info_ptr
);
210 /* create rows for later writing */
211 row_pointers
= alloca(sizeof(png_bytep
)*p
->h
);
214 png_destroy_write_struct(&png_ptr
, (png_infopp
)NULL
);
218 /* and this ensures the rows point to the correct place in the pixel data */
219 for (i
=0; i
<p
->h
; ++i
) {
220 row_pointers
[i
] = p
->pixels
+ (i
* rb
);
222 png_write_image(png_ptr
, row_pointers
);
224 png_write_end(png_ptr
, info_ptr
);
227 png_destroy_write_struct(&png_ptr
, (png_infopp
)NULL
);