]> Dogcows Code - chaz/yoink/blob - src/Moof/Image.cc
bugfix: win32 packaging script temp directories
[chaz/yoink] / src / Moof / Image.cc
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
9 *
10 **************************************************************************/
11
12 #include <cstdio> // FILE
13 #include <cstring> // strncmp
14
15 #include <boost/algorithm/string.hpp>
16
17 #include <png.h>
18 #include <SDL/SDL.h>
19
20 #include "Backend.hh"
21 #include "Error.hh"
22 #include "Image.hh"
23 #include "Log.hh"
24 #include "Manager.hh"
25
26
27 namespace Mf {
28
29
30 class Image::Impl : public Manager<Impl>
31 {
32 public:
33
34 explicit Impl() :
35 mContext(0),
36 mPixels(0) {}
37
38 ~Impl()
39 {
40 SDL_FreeSurface(mContext);
41 delete[] mPixels;
42 }
43
44
45 void flip()
46 {
47 unsigned char* pixels = (Uint8*)(mContext->pixels);
48
49 unsigned pitch = mContext->pitch;
50 unsigned char line[pitch];
51
52 int yBegin = 0;
53 int yEnd = mContext->h - 1;
54
55 if (SDL_MUSTLOCK(mContext)) SDL_LockSurface(mContext);
56 while (yBegin < yEnd)
57 {
58 memcpy(line, pixels + pitch * yBegin, pitch);
59 memcpy(pixels + pitch * yBegin, pixels + pitch * yEnd, pitch);
60 memcpy(pixels + pitch * yEnd, line, pitch);
61 yBegin++;
62 yEnd--;
63 }
64 if (SDL_MUSTLOCK(mContext)) SDL_UnlockSurface(mContext);
65 }
66
67 void setAsIcon() const
68 {
69 SDL_WM_SetIcon(mContext, 0);
70 }
71
72
73 void init(const std::string& name, bool flipped = false)
74 {
75 std::string path(name);
76
77 FILE* fp = Image::openFile(path);
78 if (!fp) return;
79
80 png_byte signature[8];
81 size_t bytesRead;
82
83 png_infop pngInfo = 0;
84 png_infop pngInfoEnd = 0;
85 png_structp pngObj = 0;
86
87 int width;
88 int height;
89 int pitch;
90 int bpp;
91 int channels;
92
93 png_byte colors;
94 png_bytepp rows = 0;
95
96 png_textp texts = 0;
97 int numTexts;
98
99 bytesRead = fread(signature, 1, sizeof(signature), fp);
100 if (bytesRead < sizeof(signature) ||
101 png_sig_cmp(signature, 0, sizeof(signature)) != 0) goto cleanup;
102
103 pngObj = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
104 if (!pngObj) goto cleanup;
105
106 pngInfo = png_create_info_struct(pngObj);
107 if (!pngInfo) goto cleanup;
108
109 pngInfoEnd = png_create_info_struct(pngObj);
110 if (!pngInfoEnd) goto cleanup;
111
112 if (setjmp(png_jmpbuf(pngObj))) goto cleanup;
113
114 png_init_io(pngObj, fp);
115 png_set_sig_bytes(pngObj, sizeof(signature));
116 png_read_info(pngObj, pngInfo);
117
118 bpp = png_get_bit_depth(pngObj, pngInfo);
119 colors = png_get_color_type(pngObj, pngInfo);
120 switch (colors)
121 {
122 case PNG_COLOR_TYPE_PALETTE:
123 png_set_palette_to_rgb(pngObj);
124 break;
125
126 case PNG_COLOR_TYPE_GRAY:
127 if (bpp < 8) png_set_expand(pngObj);
128 break;
129
130 case PNG_COLOR_TYPE_GRAY_ALPHA:
131 png_set_gray_to_rgb(pngObj);
132 break;
133 }
134
135 if (bpp == 16) png_set_strip_16(pngObj);
136
137 png_read_update_info(pngObj, pngInfo);
138
139 bpp = png_get_bit_depth(pngObj, pngInfo);
140 channels = png_get_channels(pngObj, pngInfo);
141 mDepth = bpp * channels;
142
143 if (channels == 3) mColorMode = GL_RGB;
144 else mColorMode = GL_RGBA;
145
146 // read comments
147 png_get_text(pngObj, pngInfo, &texts, &numTexts);
148 for (int i = 0; i < numTexts; ++i)
149 {
150 if (strncmp(texts[i].key, "TextureInfo", 11) == 0)
151 {
152 mComment = texts[i].text;
153 break;
154 }
155 }
156
157 width = png_get_image_width(pngObj, pngInfo);
158 height = png_get_image_height(pngObj, pngInfo);
159
160 pitch = png_get_rowbytes(pngObj, pngInfo);
161 mPixels = new char[width * pitch];
162
163 rows = new png_bytep[height];
164 if (flipped)
165 {
166 for (int i = 0; i < height; ++i)
167 {
168 rows[height - 1 - i] = (png_bytep)(mPixels +
169 i * channels * width);
170 }
171 }
172 else
173 {
174 for (int i = 0; i < height; ++i)
175 {
176 rows[i] = (png_bytep)(mPixels + i * channels * width);
177 }
178 }
179
180 png_read_image(pngObj, rows);
181 png_read_end(pngObj, 0);
182
183 mContext = SDL_CreateRGBSurfaceFrom
184 (
185 mPixels,
186 width,
187 height,
188 bpp * channels,
189 pitch,
190 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
191 0x000000FF,
192 0x0000FF00,
193 0x00FF0000,
194 0xFF000000
195 #else
196 0xFF000000,
197 0x00FF0000,
198 0x0000FF00,
199 0x000000FF
200 #endif
201 );
202
203 cleanup:
204
205 delete[] rows;
206 png_destroy_read_struct(pngObj ? &pngObj : 0,
207 pngInfo ? &pngInfo : 0,
208 pngInfoEnd ? &pngInfoEnd : 0);
209 fclose(fp);
210 }
211
212
213 SDL_Surface* mContext;
214 char* mPixels;
215
216 unsigned mDepth;
217 GLuint mColorMode;
218
219 std::string mComment;
220
221 private:
222
223 Backend mBackend;
224 };
225
226
227 Image::Image(const std::string& name) :
228 // pass through
229 mImpl(Image::Impl::getInstance(name)) {}
230
231
232 bool Image::isValid() const
233 {
234 return mImpl->mContext;
235 }
236
237 int Image::getWidth() const
238 {
239 return mImpl->mContext->w;
240 }
241
242 int Image::getHeight() const
243 {
244 return mImpl->mContext->h;
245 }
246
247 unsigned Image::getDepth() const
248 {
249 return mImpl->mDepth;
250 }
251
252 unsigned Image::getPitch() const
253 {
254 return mImpl->mContext->pitch;
255 }
256
257 GLuint Image::getMode() const
258 {
259 return mImpl->mColorMode;
260 }
261
262 std::string Image::getComment() const
263 {
264 return mImpl->mComment;
265 }
266
267 const char* Image::getPixels() const
268 {
269 return mImpl->mPixels;
270 }
271
272 char* Image::getPixels()
273 {
274 return mImpl->mPixels;
275 }
276
277
278 void Image::flip()
279 {
280 // pass through
281 mImpl->flip();
282 }
283
284 void Image::setAsIcon() const
285 {
286 // pass through
287 mImpl->setAsIcon();
288 }
289
290
291 bool Image::getPath(std::string& name)
292 {
293 return Resource::getPath(name, "images/", "png");
294 }
295
296 FILE* Image::openFile(std::string& name)
297 {
298 return Resource::openFile(name, "images/", "png");
299 }
300
301
302 } // namespace Mf
303
This page took 0.044053 seconds and 4 git commands to generate.