]> git.jsancho.org Git - lugaru.git/blob - Source/Utils/ImageIO.cpp
Removed useless STUBBED define
[lugaru.git] / Source / Utils / ImageIO.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
4
5 This file is part of Lugaru.
6
7 Lugaru is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 Lugaru is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "Utils/ImageIO.hpp"
22
23 #include "Game.hpp"
24 #include "Utils/Folders.hpp"
25
26 #include <jpeglib.h>
27 #include <png.h>
28 #include <stdio.h>
29 #include <zlib.h>
30
31 extern bool visibleloading;
32
33 /* These two are needed for screenshot */
34 extern int kContextWidth;
35 extern int kContextHeight;
36
37 static bool load_png(const char * fname, ImageRec & tex);
38 static bool load_jpg(const char * fname, ImageRec & tex);
39 static bool save_screenshot_png(const char * fname);
40
41 ImageRec::ImageRec()
42 {
43     data = ( GLubyte* )malloc( 1024 * 1024 * 4 );
44 }
45
46 ImageRec::~ImageRec()
47 {
48     free(data);
49     data = NULL;
50 }
51
52 bool load_image(const char *file_name, ImageRec &tex)
53 {
54     if (visibleloading) {
55         Game::LoadingScreen();
56     }
57
58     if ( tex.data == NULL ) {
59         return false;
60     }
61
62     const char *ptr = strrchr((char *)file_name, '.');
63     if (ptr) {
64         if (strcasecmp(ptr + 1, "png") == 0) {
65             return load_png(file_name, tex);
66         } else if (strcasecmp(ptr + 1, "jpg") == 0) {
67             return load_jpg(file_name, tex);
68         }
69     }
70
71     std::cerr << "Unsupported image type" << std::endl;
72     return false;
73 }
74
75 bool save_screenshot(const char *file_name)
76 {
77     const char *ptr = strrchr((char *)file_name, '.');
78     if (ptr) {
79         if (strcasecmp(ptr + 1, "png") == 0) {
80             return save_screenshot_png((Folders::getScreenshotDir() + '/' + file_name).c_str());
81         }
82     }
83
84     std::cerr << "Unsupported image type" << std::endl;
85     return false;
86 }
87
88 struct my_error_mgr {
89     struct jpeg_error_mgr pub; /* "public" fields */
90     jmp_buf setjmp_buffer; /* for return to caller */
91 };
92 typedef struct my_error_mgr * my_error_ptr;
93
94 static void my_error_exit(j_common_ptr cinfo)
95 {
96     struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err;
97     longjmp(err->setjmp_buffer, 1);
98 }
99
100 /* stolen from public domain example.c code in libjpg distribution. */
101 static bool load_jpg(const char *file_name, ImageRec &tex)
102 {
103     struct jpeg_decompress_struct cinfo;
104     struct my_error_mgr jerr;
105     JSAMPROW buffer[1]; /* Output row buffer */
106     int row_stride; /* physical row width in output buffer */
107     FILE *infile = fopen(file_name, "rb");
108
109     if (infile == NULL)
110         return false;
111
112     cinfo.err = jpeg_std_error(&jerr.pub);
113     jerr.pub.error_exit = my_error_exit;
114     if (setjmp(jerr.setjmp_buffer)) {
115         jpeg_destroy_decompress(&cinfo);
116         fclose(infile);
117         return false;
118     }
119
120     jpeg_create_decompress(&cinfo);
121     jpeg_stdio_src(&cinfo, infile);
122     (void) jpeg_read_header(&cinfo, TRUE);
123
124     cinfo.out_color_space = JCS_RGB;
125     cinfo.quantize_colors = 0;
126     (void) jpeg_calc_output_dimensions(&cinfo);
127     (void) jpeg_start_decompress(&cinfo);
128
129     row_stride = cinfo.output_width * cinfo.output_components;
130     tex.sizeX = cinfo.output_width;
131     tex.sizeY = cinfo.output_height;
132     tex.bpp = 24;
133
134     while (cinfo.output_scanline < cinfo.output_height) {
135         buffer[0] = (JSAMPROW)(char *)tex.data +
136                     ((cinfo.output_height - 1) - cinfo.output_scanline) * row_stride;
137         (void) jpeg_read_scanlines(&cinfo, buffer, 1);
138     }
139
140     (void) jpeg_finish_decompress(&cinfo);
141     jpeg_destroy_decompress(&cinfo);
142     fclose(infile);
143
144     return true;
145 }
146
147 /* stolen from public domain example.c code in libpng distribution. */
148 static bool load_png(const char *file_name, ImageRec &tex)
149 {
150     bool hasalpha = false;
151     png_structp png_ptr = NULL;
152     png_infop info_ptr = NULL;
153     png_uint_32 width, height;
154     int bit_depth, color_type, interlace_type;
155     bool retval = false;
156     png_byte **row_pointers = NULL;
157     FILE *fp = fopen(file_name, "rb");
158
159     if (fp == NULL) {
160         cerr << file_name << " not found" << endl;
161         return false;
162     }
163
164     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
165     if (png_ptr == NULL)
166         goto png_done;
167
168     info_ptr = png_create_info_struct(png_ptr);
169     if (info_ptr == NULL)
170         goto png_done;
171
172     if (setjmp(png_jmpbuf(png_ptr)))
173         goto png_done;
174
175     png_init_io(png_ptr, fp);
176     png_read_png(png_ptr, info_ptr,
177                  PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING,
178                  NULL);
179     png_get_IHDR(png_ptr, info_ptr, &width, &height,
180                  &bit_depth, &color_type, &interlace_type, NULL, NULL);
181
182     if (bit_depth != 8)  // transform SHOULD handle this...
183         goto png_done;
184
185     if (color_type & PNG_COLOR_MASK_PALETTE)  // !!! FIXME?
186         goto png_done;
187
188     if ((color_type & PNG_COLOR_MASK_COLOR) == 0)  // !!! FIXME?
189         goto png_done;
190
191     hasalpha = ((color_type & PNG_COLOR_MASK_ALPHA) != 0);
192     row_pointers = png_get_rows(png_ptr, info_ptr);
193     if (!row_pointers)
194         goto png_done;
195
196     if (!hasalpha) {
197         png_byte *dst = tex.data;
198         for (int i = height - 1; i >= 0; i--) {
199             png_byte *src = row_pointers[i];
200             for (unsigned j = 0; j < width; j++) {
201                 dst[0] = src[0];
202                 dst[1] = src[1];
203                 dst[2] = src[2];
204                 dst[3] = 0xFF;
205                 src += 3;
206                 dst += 4;
207             }
208         }
209     }
210
211     else {
212         png_byte *dst = tex.data;
213         int pitch = width * 4;
214         for (int i = height - 1; i >= 0; i--, dst += pitch)
215             memcpy(dst, row_pointers[i], pitch);
216     }
217
218     tex.sizeX = width;
219     tex.sizeY = height;
220     tex.bpp = 32;
221     retval = true;
222
223 png_done:
224     if (!retval) {
225         cerr << "There was a problem loading " << file_name << endl;
226     }
227     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
228     if (fp)
229         fclose(fp);
230     return (retval);
231 }
232
233 static bool save_screenshot_png(const char *file_name)
234 {
235     FILE *fp = NULL;
236     png_structp png_ptr = NULL;
237     png_infop info_ptr = NULL;
238     bool retval = false;
239
240     fp = fopen(file_name, "wb");
241     if (fp == NULL)
242         return false;
243
244     png_bytep *row_pointers = new png_bytep[kContextHeight];
245     png_bytep screenshot = new png_byte[kContextWidth * kContextHeight * 3];
246     if ((!screenshot) || (!row_pointers))
247         goto save_png_done;
248
249     glGetError();
250     glReadPixels(0, 0, kContextWidth, kContextHeight,
251                  GL_RGB, GL_UNSIGNED_BYTE, screenshot);
252     if (glGetError() != GL_NO_ERROR)
253         goto save_png_done;
254
255     for (int i = 0; i < kContextHeight; i++)
256         row_pointers[i] = screenshot + ((kContextWidth * ((kContextHeight - 1) - i)) * 3);
257
258     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
259     if (png_ptr == NULL)
260         goto save_png_done;
261
262     info_ptr = png_create_info_struct(png_ptr);
263     if (info_ptr == NULL)
264         goto save_png_done;
265
266     if (setjmp(png_jmpbuf(png_ptr)))
267         goto save_png_done;
268
269     png_init_io(png_ptr, fp);
270
271     if (setjmp(png_jmpbuf(png_ptr)))
272         goto save_png_done;
273
274     png_set_IHDR(png_ptr, info_ptr, kContextWidth, kContextHeight,
275                  8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
276                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
277
278     png_write_info(png_ptr, info_ptr);
279
280     if (setjmp(png_jmpbuf(png_ptr)))
281         goto save_png_done;
282
283     png_write_image(png_ptr, row_pointers);
284
285     if (setjmp(png_jmpbuf(png_ptr)))
286         goto save_png_done;
287
288     png_write_end(png_ptr, NULL);
289     retval = true;
290
291 save_png_done:
292     png_destroy_write_struct(&png_ptr, &info_ptr);
293     delete[] screenshot;
294     delete[] row_pointers;
295     if (fp)
296         fclose(fp);
297     if (!retval)
298         unlink(file_name);
299     return retval;
300 }