]> git.jsancho.org Git - lugaru.git/blob - Source/Utils/ImageIO.cpp
Remove some unneeded libs & headers
[lugaru.git] / Source / Utils / ImageIO.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2017 - 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
30 #ifndef WIN32
31 #include <unistd.h>
32 #endif
33
34 /* These two are needed for screenshot */
35 extern int kContextWidth;
36 extern int kContextHeight;
37
38 static bool load_png(const char* fname, ImageRec& tex);
39 static bool load_jpg(const char* fname, ImageRec& tex);
40 static bool save_screenshot_png(const char* fname);
41
42 ImageRec::ImageRec()
43 {
44     data = (GLubyte*)malloc(1024 * 1024 * 4);
45 }
46
47 ImageRec::~ImageRec()
48 {
49     free(data);
50     data = NULL;
51 }
52
53 bool load_image(const char* file_name, ImageRec& tex)
54 {
55     Game::LoadingScreen();
56
57     if (tex.data == NULL) {
58         return false;
59     }
60
61     const char* ptr = strrchr((char*)file_name, '.');
62     if (ptr) {
63         if (strcasecmp(ptr + 1, "png") == 0) {
64             return load_png(file_name, tex);
65         } else if (strcasecmp(ptr + 1, "jpg") == 0) {
66             return load_jpg(file_name, tex);
67         }
68     }
69
70     std::cerr << "Unsupported image type" << std::endl;
71     return false;
72 }
73
74 bool save_screenshot(const char* file_name)
75 {
76     const char* ptr = strrchr((char*)file_name, '.');
77     if (ptr) {
78         if (strcasecmp(ptr + 1, "png") == 0) {
79             return save_screenshot_png((Folders::getScreenshotDir() + '/' + file_name).c_str());
80         }
81     }
82
83     std::cerr << "Unsupported image type" << std::endl;
84     return false;
85 }
86
87 struct my_error_mgr
88 {
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     errno = 0;
108     FILE* infile = fopen(file_name, "rb");
109
110     if (infile == NULL) {
111         perror((std::string("Couldn't open file ") + file_name).c_str());
112         return false;
113     }
114
115     cinfo.err = jpeg_std_error(&jerr.pub);
116     jerr.pub.error_exit = my_error_exit;
117     if (setjmp(jerr.setjmp_buffer)) {
118         jpeg_destroy_decompress(&cinfo);
119         fclose(infile);
120         return false;
121     }
122
123     jpeg_create_decompress(&cinfo);
124     jpeg_stdio_src(&cinfo, infile);
125     (void)jpeg_read_header(&cinfo, TRUE);
126
127     cinfo.out_color_space = JCS_RGB;
128     cinfo.quantize_colors = FALSE;
129     (void)jpeg_calc_output_dimensions(&cinfo);
130     (void)jpeg_start_decompress(&cinfo);
131
132     row_stride = cinfo.output_width * cinfo.output_components;
133     tex.sizeX = cinfo.output_width;
134     tex.sizeY = cinfo.output_height;
135     tex.bpp = 24;
136
137     while (cinfo.output_scanline < cinfo.output_height) {
138         buffer[0] = (JSAMPROW)(char*)tex.data +
139                     ((cinfo.output_height - 1) - cinfo.output_scanline) * row_stride;
140         (void)jpeg_read_scanlines(&cinfo, buffer, 1);
141     }
142
143     (void)jpeg_finish_decompress(&cinfo);
144     jpeg_destroy_decompress(&cinfo);
145     fclose(infile);
146
147     return true;
148 }
149
150 /* stolen from public domain example.c code in libpng distribution. */
151 static bool load_png(const char* file_name, ImageRec& tex)
152 {
153     bool hasalpha = false;
154     png_structp png_ptr = NULL;
155     png_infop info_ptr = NULL;
156     png_uint_32 width, height;
157     int bit_depth, color_type, interlace_type;
158     bool retval = false;
159     png_byte** row_pointers = NULL;
160     errno = 0;
161     FILE* fp = fopen(file_name, "rb");
162
163     if (fp == NULL) {
164         perror((std::string("Couldn't open file ") + file_name).c_str());
165         return false;
166     }
167
168     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
169     if (png_ptr == NULL) {
170         goto png_done;
171     }
172
173     info_ptr = png_create_info_struct(png_ptr);
174     if (info_ptr == NULL) {
175         goto png_done;
176     }
177
178     if (setjmp(png_jmpbuf(png_ptr))) {
179         goto png_done;
180     }
181
182     png_init_io(png_ptr, fp);
183     png_read_png(png_ptr, info_ptr,
184                  PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING,
185                  NULL);
186     png_get_IHDR(png_ptr, info_ptr, &width, &height,
187                  &bit_depth, &color_type, &interlace_type, NULL, NULL);
188
189     if (bit_depth != 8) { // transform SHOULD handle this...
190         goto png_done;
191     }
192
193     if (color_type & PNG_COLOR_MASK_PALETTE) { // !!! FIXME?
194         goto png_done;
195     }
196
197     if ((color_type & PNG_COLOR_MASK_COLOR) == 0) { // !!! FIXME?
198         goto png_done;
199     }
200
201     hasalpha = ((color_type & PNG_COLOR_MASK_ALPHA) != 0);
202     row_pointers = png_get_rows(png_ptr, info_ptr);
203     if (!row_pointers) {
204         goto png_done;
205     }
206
207     if (!hasalpha) {
208         png_byte* dst = tex.data;
209         for (int i = height - 1; i >= 0; i--) {
210             png_byte* src = row_pointers[i];
211             for (unsigned j = 0; j < width; j++) {
212                 dst[0] = src[0];
213                 dst[1] = src[1];
214                 dst[2] = src[2];
215                 dst[3] = 0xFF;
216                 src += 3;
217                 dst += 4;
218             }
219         }
220     }
221
222     else {
223         png_byte* dst = tex.data;
224         int pitch = width * 4;
225         for (int i = height - 1; i >= 0; i--, dst += pitch) {
226             memcpy(dst, row_pointers[i], pitch);
227         }
228     }
229
230     tex.sizeX = width;
231     tex.sizeY = height;
232     tex.bpp = 32;
233     retval = true;
234
235 png_done:
236     if (!retval) {
237         cerr << "There was a problem loading " << file_name << endl;
238     }
239     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
240     if (fp) {
241         fclose(fp);
242     }
243     return (retval);
244 }
245
246 static bool save_screenshot_png(const char* file_name)
247 {
248     FILE* fp = NULL;
249     png_structp png_ptr = NULL;
250     png_infop info_ptr = NULL;
251     bool retval = false;
252
253     errno = 0;
254     fp = fopen(file_name, "wb");
255     if (fp == NULL) {
256         perror((std::string("Couldn't open file ") + file_name).c_str());
257         return false;
258     }
259
260     png_bytep* row_pointers = new png_bytep[kContextHeight];
261     png_bytep screenshot = new png_byte[kContextWidth * kContextHeight * 3];
262     if ((!screenshot) || (!row_pointers)) {
263         goto save_png_done;
264     }
265
266     glGetError();
267     glReadPixels(0, 0, kContextWidth, kContextHeight,
268                  GL_RGB, GL_UNSIGNED_BYTE, screenshot);
269     if (glGetError() != GL_NO_ERROR) {
270         goto save_png_done;
271     }
272
273     for (int i = 0; i < kContextHeight; i++) {
274         row_pointers[i] = screenshot + ((kContextWidth * ((kContextHeight - 1) - i)) * 3);
275     }
276
277     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
278     if (png_ptr == NULL) {
279         goto save_png_done;
280     }
281
282     info_ptr = png_create_info_struct(png_ptr);
283     if (info_ptr == NULL) {
284         goto save_png_done;
285     }
286
287     if (setjmp(png_jmpbuf(png_ptr))) {
288         goto save_png_done;
289     }
290
291     png_init_io(png_ptr, fp);
292
293     if (setjmp(png_jmpbuf(png_ptr))) {
294         goto save_png_done;
295     }
296
297     png_set_IHDR(png_ptr, info_ptr, kContextWidth, kContextHeight,
298                  8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
299                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
300
301     png_write_info(png_ptr, info_ptr);
302
303     if (setjmp(png_jmpbuf(png_ptr))) {
304         goto save_png_done;
305     }
306
307     png_write_image(png_ptr, row_pointers);
308
309     if (setjmp(png_jmpbuf(png_ptr))) {
310         goto save_png_done;
311     }
312
313     png_write_end(png_ptr, NULL);
314     retval = true;
315
316 save_png_done:
317     png_destroy_write_struct(&png_ptr, &info_ptr);
318     delete[] screenshot;
319     delete[] row_pointers;
320     if (fp) {
321         fclose(fp);
322     }
323     if (!retval) {
324         unlink(file_name);
325     }
326     return retval;
327 }