Browse Source

Added PNG reading/writing

Thomas Buck 9 years ago
parent
commit
504b3ae06f
8 changed files with 264 additions and 1 deletions
  1. 3
    0
      ChangeLog.md
  2. 2
    1
      README.md
  3. 1
    0
      TODO.md
  4. 1
    0
      include/config.h.in
  5. 32
    0
      include/utils/png.h
  6. 14
    0
      src/CMakeLists.txt
  7. 4
    0
      src/utils/CMakeLists.txt
  8. 207
    0
      src/utils/png.cpp

+ 3
- 0
ChangeLog.md View File

@@ -2,6 +2,9 @@
2 2
 
3 3
 ## OpenRaider (0.1.3) xythobuz <xythobuz@xythobuz.de>
4 4
 
5
+    [ 20140622 ]
6
+    * Wrote simple image reader/writer utilizing libpng
7
+
5 8
     [ 20140621 ]
6 9
     * Created StaticMesh class replacing model_mesh_t stuff
7 10
     * Simplified StaticMesh’s data storage

+ 2
- 1
README.md View File

@@ -30,10 +30,11 @@ Basically, OpenRaider depends on the following:
30 30
 
31 31
 * OpenGL
32 32
 * SDL2
33
-* SDL2-TTF (if you want to use TTF fonts)
33
+* SDL2-TTF (optional, needed if you want to use TTF fonts)
34 34
 * OpenAL & ALUT
35 35
 * zlib
36 36
 * cmake as build system
37
+* libpng (optional)
37 38
 
38 39
 On Mac OS X 10.9 with [XCode](https://developer.apple.com/xcode/) and [MacPorts](http://www.macports.org) installed, the following should be enough to get all dependencies that are available as port:
39 40
 

+ 1
- 0
TODO.md View File

@@ -10,6 +10,7 @@
10 10
     * Rewrite Console and use operator << to write to the console?
11 11
 * SDL_TTF 2.0.12+ can do line breaks, use it: http://stackoverflow.com/questions/17847818/how-to-do-line-breaks-and-line-wrapping-with-sdl-ttf/18418688#18418688
12 12
 * Mesh has 2 different approaches of storing the same data (eg. mColors and mColorArray), but half of ‘em isn’t implemented. Unify this, probably even reusing the Mesh class for the model_meshes...
13
+* glTexImage2D has alignment requirements?!?! https://www.khronos.org/opengles/sdk/1.1/docs/man/glTexImage2D.xml
13 14
 
14 15
 ## Changes
15 16
 

+ 1
- 0
include/config.h.in View File

@@ -12,6 +12,7 @@
12 12
 #define BUILD_HOST "@OpenRaider_BUILD_HOST@ @OpenRaider_HOSTNAME@"
13 13
 
14 14
 #cmakedefine USING_AL
15
+#cmakedefine USING_PNG
15 16
 
16 17
 #cmakedefine HAVE_EXECINFO_H
17 18
 #cmakedefine HAVE_BACKTRACE

+ 32
- 0
include/utils/png.h View File

@@ -0,0 +1,32 @@
1
+/*!
2
+ * \file include/utils/png.h
3
+ * \brief PNG image reader
4
+ *
5
+ * \author xythobuz
6
+ */
7
+
8
+#ifndef _UTILS_PNG_H_
9
+#define _UTILS_PNG_H_
10
+
11
+/*!
12
+ * \brief Load a PNG image file into an RGBA buffer
13
+ * \param filename path of file to read
14
+ * \param image place where allocated buffer of size (width * height * 4) will be allocated
15
+ * \param width place where image width will be stored
16
+ * \param height place where image height will be stored
17
+ * \returns 0 on success
18
+ */
19
+int pngLoad(const char *filename, unsigned char **image, unsigned int *width, unsigned int *height);
20
+
21
+/*!
22
+ * \brief Create a PNG image file from an RGBA buffer
23
+ * \param filename path of file to create
24
+ * \param image buffer of size (width * height * 4)
25
+ * \param width image width
26
+ * \param height image height
27
+ * \returns 0 on success
28
+ */
29
+int pngSave(const char *filename, unsigned char *image, unsigned int width, unsigned int height);
30
+
31
+#endif
32
+

+ 14
- 0
src/CMakeLists.txt View File

@@ -36,6 +36,14 @@ if (OPENAL_FOUND)
36 36
     endif (ALUT_FOUND)
37 37
 endif (OPENAL_FOUND)
38 38
 
39
+# Add PNG Library
40
+find_package (PNG)
41
+if (PNG_FOUND)
42
+    include_directories (SYSTEM ${PNG_INCLUDE_DIRS})
43
+    set (LIBS ${LIBS} ${PNG_LIBRARIES})
44
+    add_definitions (${PNG_DEFINITIONS})
45
+endif (PNG_FOUND)
46
+
39 47
 #################################################################
40 48
 
41 49
 # Set Source files
@@ -87,6 +95,12 @@ else (SDL2_FOUND)
87 95
     message (FATAL_ERROR "SDL2 is required at the moment!")
88 96
 endif (SDL2_FOUND)
89 97
 
98
+if (PNG_FOUND)
99
+    set (USING_PNG TRUE)
100
+else (PNG_FOUND)
101
+    set (USING_PNG FALSE)
102
+endif (PNG_FOUND)
103
+
90 104
 #################################################################
91 105
 
92 106
 # Check for header/function presence

+ 4
- 0
src/utils/CMakeLists.txt View File

@@ -4,6 +4,10 @@ set (UTIL_SRCS ${UTIL_SRCS} "strings.cpp")
4 4
 set (UTIL_SRCS ${UTIL_SRCS} "tga.cpp")
5 5
 set (UTIL_SRCS ${UTIL_SRCS} "time.cpp")
6 6
 
7
+if (USING_PNG)
8
+    set (UTIL_SRCS ${UTIL_SRCS} "png.cpp")
9
+endif (USING_PNG)
10
+
7 11
 # Include directory
8 12
 include_directories ("${PROJECT_SOURCE_DIR}/include")
9 13
 

+ 207
- 0
src/utils/png.cpp View File

@@ -0,0 +1,207 @@
1
+/*!
2
+ * \file src/utils/png.cpp
3
+ * \brief PNG image reader
4
+ *
5
+ * https://github.com/DavidEGrayson/ahrs-visualizer/blob/master/png_texture.cpp
6
+ * http://zarb.org/~gc/html/libpng.html
7
+ *
8
+ * \author xythobuz
9
+ */
10
+
11
+#include <png.h>
12
+#include <cstdio>
13
+
14
+#include "global.h"
15
+#include "utils/png.h"
16
+
17
+#ifdef DEBUG
18
+#include "Console.h"
19
+#define pngPrint getConsole().print
20
+#else
21
+void pngPrint(...) { }
22
+#endif
23
+
24
+int pngLoad(const char *filename, unsigned char **image, unsigned int *width, unsigned int *height) {
25
+    png_byte header[8];
26
+
27
+    assert(filename != NULL);
28
+    assert(filename[0] != '\0');
29
+    assert(image != NULL);
30
+    assert(width != NULL);
31
+    assert(height != NULL);
32
+
33
+    FILE *fp = fopen(filename, "rb");
34
+    if (fp == NULL) {
35
+        pngPrint("Could not open %s", filename);
36
+        return -1;
37
+    }
38
+
39
+    fread(header, 1, 8, fp);
40
+
41
+    if (png_sig_cmp(header, 0, 8)) {
42
+        pngPrint("File %s is not a PNG.", filename);
43
+        fclose(fp);
44
+        return -2;
45
+    }
46
+
47
+    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
48
+    if (!png_ptr) {
49
+        pngPrint("png_create_read_struct returned 0.");
50
+        fclose(fp);
51
+        return -3;
52
+    }
53
+
54
+    png_infop info_ptr = png_create_info_struct(png_ptr);
55
+    if (!info_ptr) {
56
+        pngPrint("png_create_info_struct returned 0.");
57
+        png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
58
+        fclose(fp);
59
+        return -4;
60
+    }
61
+
62
+    png_infop end_info = png_create_info_struct(png_ptr);
63
+    if (!end_info) {
64
+        pngPrint("png_create_info_struct returned 0.");
65
+        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
66
+        fclose(fp);
67
+        return -5;
68
+    }
69
+
70
+    if (setjmp(png_jmpbuf(png_ptr))) {
71
+        pngPrint("Error from libpng");
72
+        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
73
+        fclose(fp);
74
+        return -6;
75
+    }
76
+
77
+    png_init_io(png_ptr, fp);
78
+    png_set_sig_bytes(png_ptr, 8);
79
+    png_read_info(png_ptr, info_ptr);
80
+
81
+    int bit_depth, color_type;
82
+
83
+    png_get_IHDR(png_ptr, info_ptr, width, height, &bit_depth, &color_type,
84
+            NULL, NULL, NULL);
85
+
86
+    if (bit_depth != 8) {
87
+        pngPrint("%s: Unsupported bit depth %d.  Must be 8.", filename, bit_depth);
88
+        return -7;
89
+    }
90
+
91
+    png_read_update_info(png_ptr, info_ptr);
92
+
93
+    int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
94
+
95
+    png_byte *image_data = new png_byte[(rowbytes * *height) + 15];
96
+    png_bytep *row_pointers = new png_bytep[*height];
97
+
98
+    for (unsigned int i = 0; i < *height; i++)
99
+        row_pointers[*height - 1 - i] = image_data + i * rowbytes;
100
+
101
+    png_read_image(png_ptr, row_pointers);
102
+
103
+    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
104
+    delete [] row_pointers;
105
+    fclose(fp);
106
+
107
+    if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
108
+        *image = image_data;
109
+    } else {
110
+        *image = new unsigned char[*width * *height * 4];
111
+        if (color_type == PNG_COLOR_TYPE_RGB) {
112
+            for (unsigned int i = 0; i < (*width * *height); i++) {
113
+                *image[i * 4] = image_data[i * 3];
114
+                *image[(i * 4) + 1] = image_data[(i * 3) + 1];
115
+                *image[(i * 4) + 2] = image_data[(i * 3) + 2];
116
+                *image[(i * 4) + 3] = 255;
117
+            }
118
+        } else {
119
+            pngPrint("%s: Unknown libpng color type %d.", filename, color_type);
120
+            delete [] image_data;
121
+            delete [] *image;
122
+            *image = NULL;
123
+            return -8;
124
+        }
125
+        delete [] image_data;
126
+    }
127
+
128
+    return 0;
129
+}
130
+
131
+int pngSave(const char *filename, unsigned char *image, unsigned int width, unsigned int height) {
132
+    assert(filename != NULL);
133
+    assert(filename[0] != '\0');
134
+    assert(image != NULL);
135
+    assert(width > 0);
136
+    assert(height > 0);
137
+
138
+    FILE *fp = fopen(filename, "wb");
139
+    if (!fp) {
140
+        pngPrint("File %s could not be opened for writing", filename);
141
+        return -1;
142
+    }
143
+
144
+    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
145
+
146
+    if (!png_ptr) {
147
+        pngPrint("png_create_write_struct failed");
148
+        fclose(fp);
149
+        return -2;
150
+    }
151
+
152
+    png_infop info_ptr = png_create_info_struct(png_ptr);
153
+    if (!info_ptr) {
154
+        pngPrint("png_create_info_struct failed");
155
+        fclose(fp);
156
+        return -3;
157
+    }
158
+
159
+    if (setjmp(png_jmpbuf(png_ptr))) {
160
+        pngPrint("Error during init_io");
161
+        fclose(fp);
162
+        return -4;
163
+    }
164
+
165
+    png_init_io(png_ptr, fp);
166
+
167
+    if (setjmp(png_jmpbuf(png_ptr))) {
168
+        pngPrint("Error during writing header");
169
+        fclose(fp);
170
+        return -5;
171
+    }
172
+
173
+    png_set_IHDR(png_ptr, info_ptr, width, height,
174
+            8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
175
+            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
176
+
177
+    png_write_info(png_ptr, info_ptr);
178
+
179
+    png_bytep *row_pointers = new png_bytep[height];
180
+
181
+    for (unsigned int i = 0; i < height; i++)
182
+        row_pointers[height - 1 - i] = image + (i * width * 4);
183
+
184
+    if (setjmp(png_jmpbuf(png_ptr))) {
185
+        pngPrint("Error during writing bytes");
186
+        delete [] row_pointers;
187
+        fclose(fp);
188
+        return -6;
189
+    }
190
+
191
+    png_write_image(png_ptr, row_pointers);
192
+
193
+    if (setjmp(png_jmpbuf(png_ptr))) {
194
+        pngPrint("Error during end of write");
195
+        delete [] row_pointers;
196
+        fclose(fp);
197
+        return -7;
198
+    }
199
+
200
+    png_write_end(png_ptr, NULL);
201
+
202
+    delete [] row_pointers;
203
+    fclose(fp);
204
+
205
+    return 0;
206
+}
207
+

Loading…
Cancel
Save