diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llimage/llimagepng.cpp | 147 | ||||
-rw-r--r-- | linden/indra/llimage/llimagepng.h | 51 | ||||
-rw-r--r-- | linden/indra/llimage/llpngwrapper.cpp | 388 | ||||
-rw-r--r-- | linden/indra/llimage/llpngwrapper.h | 102 |
4 files changed, 688 insertions, 0 deletions
diff --git a/linden/indra/llimage/llimagepng.cpp b/linden/indra/llimage/llimagepng.cpp new file mode 100644 index 0000000..d6b62a8 --- /dev/null +++ b/linden/indra/llimage/llimagepng.cpp | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * @file llimagepng.cpp | ||
3 | * @brief LLImageFormatted glue to encode / decode PNG files. | ||
4 | * | ||
5 | * Copyright (c) 2007 Peekay Semyorka. | ||
6 | * Copyright (c) 2007-2007, Linden Research, Inc. | ||
7 | * | ||
8 | * Second Life Viewer Source Code | ||
9 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
10 | * to you under the terms of the GNU General Public License, version 2.0 | ||
11 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
12 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
13 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
14 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
15 | * | ||
16 | * There are special exceptions to the terms and conditions of the GPL as | ||
17 | * it is applied to this Source Code. View the full text of the exception | ||
18 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
19 | * online at http://secondlife.com/developers/opensource/flossexception | ||
20 | * | ||
21 | * By copying, modifying or distributing this software, you acknowledge | ||
22 | * that you have read and understood your obligations described above, | ||
23 | * and agree to abide by those obligations. | ||
24 | * | ||
25 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
26 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
27 | * COMPLETENESS OR PERFORMANCE. | ||
28 | */ | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | #include "stdtypes.h" | ||
32 | #include "llerror.h" | ||
33 | |||
34 | #include "llimage.h" | ||
35 | #include "llpngwrapper.h" | ||
36 | #include "llimagepng.h" | ||
37 | |||
38 | // --------------------------------------------------------------------------- | ||
39 | // LLImagePNG | ||
40 | // --------------------------------------------------------------------------- | ||
41 | LLImagePNG::LLImagePNG() | ||
42 | : LLImageFormatted(IMG_CODEC_PNG), | ||
43 | mTmpWriteBuffer(NULL) | ||
44 | { | ||
45 | } | ||
46 | |||
47 | LLImagePNG::~LLImagePNG() | ||
48 | { | ||
49 | if (mTmpWriteBuffer) | ||
50 | { | ||
51 | delete[] mTmpWriteBuffer; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | // Virtual | ||
56 | // Parse PNG image information and set the appropriate | ||
57 | // width, height and component (channel) information. | ||
58 | BOOL LLImagePNG::updateData() | ||
59 | { | ||
60 | resetLastError(); | ||
61 | |||
62 | // Check to make sure that this instance has been initialized with data | ||
63 | if (!getData() || (0 == getDataSize())) | ||
64 | { | ||
65 | setLastError("Uninitialized instance of LLImagePNG"); | ||
66 | return FALSE; | ||
67 | } | ||
68 | |||
69 | // Decode the PNG data and extract sizing information | ||
70 | LLPngWrapper pngWrapper; | ||
71 | LLPngWrapper::ImageInfo infop; | ||
72 | if (! pngWrapper.readPng(getData(), NULL, &infop)) | ||
73 | { | ||
74 | setLastError(pngWrapper.getErrorMessage()); | ||
75 | return FALSE; | ||
76 | } | ||
77 | |||
78 | setSize(infop.mWidth, infop.mHeight, infop.mComponents); | ||
79 | |||
80 | return TRUE; | ||
81 | } | ||
82 | |||
83 | // Virtual | ||
84 | // Decode an in-memory PNG image into the raw RGB or RGBA format | ||
85 | // used within SecondLife. | ||
86 | BOOL LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time) | ||
87 | { | ||
88 | llassert_always(raw_image); | ||
89 | |||
90 | resetLastError(); | ||
91 | |||
92 | // Check to make sure that this instance has been initialized with data | ||
93 | if (!getData() || (0 == getDataSize())) | ||
94 | { | ||
95 | setLastError("LLImagePNG trying to decode an image with no data!"); | ||
96 | return FALSE; | ||
97 | } | ||
98 | |||
99 | // Decode the PNG data into the raw image | ||
100 | LLPngWrapper pngWrapper; | ||
101 | if (! pngWrapper.readPng(getData(), raw_image)) | ||
102 | { | ||
103 | setLastError(pngWrapper.getErrorMessage()); | ||
104 | return FALSE; | ||
105 | } | ||
106 | |||
107 | return TRUE; | ||
108 | } | ||
109 | |||
110 | // Virtual | ||
111 | // Encode the in memory RGB image into PNG format. | ||
112 | BOOL LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time) | ||
113 | { | ||
114 | llassert_always(raw_image); | ||
115 | |||
116 | resetLastError(); | ||
117 | |||
118 | // Image logical size | ||
119 | setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); | ||
120 | |||
121 | // Temporary buffer to hold the encoded image. Note: the final image | ||
122 | // size should be much smaller due to compression. | ||
123 | if (mTmpWriteBuffer) | ||
124 | { | ||
125 | delete[] mTmpWriteBuffer; | ||
126 | } | ||
127 | U32 bufferSize = getWidth() * getHeight() * getComponents() + 1024; | ||
128 | U8* mTmpWriteBuffer = new U8[ bufferSize ]; | ||
129 | |||
130 | // Delegate actual encoding work to wrapper | ||
131 | LLPngWrapper pngWrapper; | ||
132 | if (! pngWrapper.writePng(raw_image, mTmpWriteBuffer)) | ||
133 | { | ||
134 | setLastError(pngWrapper.getErrorMessage()); | ||
135 | return FALSE; | ||
136 | } | ||
137 | |||
138 | // Resize internal buffer and copy from temp | ||
139 | U32 encodedSize = pngWrapper.getFinalSize(); | ||
140 | allocateData(encodedSize); | ||
141 | memcpy(getData(), mTmpWriteBuffer, encodedSize); | ||
142 | |||
143 | delete[] mTmpWriteBuffer; | ||
144 | |||
145 | return TRUE; | ||
146 | } | ||
147 | |||
diff --git a/linden/indra/llimage/llimagepng.h b/linden/indra/llimage/llimagepng.h new file mode 100644 index 0000000..abdff7c --- /dev/null +++ b/linden/indra/llimage/llimagepng.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * @file llimagepng.h | ||
3 | * | ||
4 | * Copyright (c) 2007 Peekay Semyorka. | ||
5 | * Copyright (c) 2007-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * Second Life Viewer Source Code | ||
8 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
9 | * to you under the terms of the GNU General Public License, version 2.0 | ||
10 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
11 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
12 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
13 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
14 | * | ||
15 | * There are special exceptions to the terms and conditions of the GPL as | ||
16 | * it is applied to this Source Code. View the full text of the exception | ||
17 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
18 | * online at http://secondlife.com/developers/opensource/flossexception | ||
19 | * | ||
20 | * By copying, modifying or distributing this software, you acknowledge | ||
21 | * that you have read and understood your obligations described above, | ||
22 | * and agree to abide by those obligations. | ||
23 | * | ||
24 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
25 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
26 | * COMPLETENESS OR PERFORMANCE. | ||
27 | */ | ||
28 | |||
29 | #ifndef LL_LLIMAGEPNG_H | ||
30 | #define LL_LLIMAGEPNG_H | ||
31 | |||
32 | #include "stdtypes.h" | ||
33 | #include "llimage.h" | ||
34 | |||
35 | class LLImagePNG : public LLImageFormatted | ||
36 | { | ||
37 | protected: | ||
38 | ~LLImagePNG(); | ||
39 | |||
40 | public: | ||
41 | LLImagePNG(); | ||
42 | |||
43 | BOOL updateData(); | ||
44 | BOOL decode(LLImageRaw* raw_image, F32 decode_time = 0.0); | ||
45 | BOOL encode(const LLImageRaw* raw_image, F32 encode_time = 0.0); | ||
46 | |||
47 | private: | ||
48 | U8* mTmpWriteBuffer; | ||
49 | }; | ||
50 | |||
51 | #endif | ||
diff --git a/linden/indra/llimage/llpngwrapper.cpp b/linden/indra/llimage/llpngwrapper.cpp new file mode 100644 index 0000000..52616d1 --- /dev/null +++ b/linden/indra/llimage/llpngwrapper.cpp | |||
@@ -0,0 +1,388 @@ | |||
1 | /* | ||
2 | * @file llpngwrapper.cpp | ||
3 | * @brief Encapsulates libpng read/write functionality. | ||
4 | * | ||
5 | * Copyright (c) 2007 Peekay Semyorka. | ||
6 | * Copyright (c) 2007-2007, Linden Research, Inc. | ||
7 | * | ||
8 | * Second Life Viewer Source Code | ||
9 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
10 | * to you under the terms of the GNU General Public License, version 2.0 | ||
11 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
12 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
13 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
14 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
15 | * | ||
16 | * There are special exceptions to the terms and conditions of the GPL as | ||
17 | * it is applied to this Source Code. View the full text of the exception | ||
18 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
19 | * online at http://secondlife.com/developers/opensource/flossexception | ||
20 | * | ||
21 | * By copying, modifying or distributing this software, you acknowledge | ||
22 | * that you have read and understood your obligations described above, | ||
23 | * and agree to abide by those obligations. | ||
24 | * | ||
25 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
26 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
27 | * COMPLETENESS OR PERFORMANCE. | ||
28 | */ | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | #include "stdtypes.h" | ||
32 | #include "llerror.h" | ||
33 | |||
34 | #include "llimage.h" | ||
35 | #include "llpngwrapper.h" | ||
36 | |||
37 | // --------------------------------------------------------------------------- | ||
38 | // LLPngWrapper | ||
39 | // --------------------------------------------------------------------------- | ||
40 | |||
41 | LLPngWrapper::LLPngWrapper() | ||
42 | : mReadPngPtr( NULL ), | ||
43 | mReadInfoPtr( NULL ), | ||
44 | mWritePngPtr( NULL ), | ||
45 | mWriteInfoPtr( NULL ), | ||
46 | mRowPointers( NULL ), | ||
47 | mBitDepth( 0 ), | ||
48 | mColorType( 0 ), | ||
49 | mChannels( 0 ), | ||
50 | mInterlaceType( 0 ), | ||
51 | mCompressionType( 0 ), | ||
52 | mFilterMethod( 0 ), | ||
53 | mFinalSize( 0 ) | ||
54 | { | ||
55 | } | ||
56 | |||
57 | LLPngWrapper::~LLPngWrapper() | ||
58 | { | ||
59 | releaseResources(); | ||
60 | } | ||
61 | |||
62 | // Checks the src for a valid PNG header | ||
63 | BOOL LLPngWrapper::isValidPng(U8* src) | ||
64 | { | ||
65 | const int PNG_BYTES_TO_CHECK = 8; | ||
66 | |||
67 | int sig = png_sig_cmp((png_bytep)src, (png_size_t)0, PNG_BYTES_TO_CHECK); | ||
68 | if (sig != 0) | ||
69 | { | ||
70 | mErrorMessage = "Invalid or corrupt PNG file"; | ||
71 | return FALSE; | ||
72 | } | ||
73 | |||
74 | return TRUE; | ||
75 | } | ||
76 | |||
77 | // Called by the libpng library when a fatal encoding or decoding error | ||
78 | // occurs. We simply throw the error message and let our try/catch | ||
79 | // block clean up. | ||
80 | void LLPngWrapper::errorHandler(png_structp png_ptr, png_const_charp msg) | ||
81 | { | ||
82 | throw msg; | ||
83 | } | ||
84 | |||
85 | // Called by the libpng library when reading (decoding) the PNG file. We | ||
86 | // copy the PNG data from our internal buffer into the PNG's data buffer. | ||
87 | void LLPngWrapper::readDataCallback(png_structp png_ptr, png_bytep dest, png_size_t length) | ||
88 | { | ||
89 | PngDataInfo *dataInfo = (PngDataInfo *) png_get_io_ptr(png_ptr); | ||
90 | U8 *src = &dataInfo->mData[dataInfo->mOffset]; | ||
91 | memcpy(dest, src, length); | ||
92 | dataInfo->mOffset += static_cast<U32>(length); | ||
93 | } | ||
94 | |||
95 | // Called by the libpng library when writing (encoding) the PNG file. We | ||
96 | // copy the encoded result into our data buffer. | ||
97 | void LLPngWrapper::writeDataCallback(png_structp png_ptr, png_bytep src, png_size_t length) | ||
98 | { | ||
99 | PngDataInfo *dataInfo = (PngDataInfo *) png_get_io_ptr(png_ptr); | ||
100 | U8 *dest = &dataInfo->mData[dataInfo->mOffset]; | ||
101 | memcpy(dest, src, length); | ||
102 | dataInfo->mOffset += static_cast<U32>(length); | ||
103 | } | ||
104 | |||
105 | // Flush the write output pointer | ||
106 | void LLPngWrapper::writeFlush(png_structp png_ptr) | ||
107 | { | ||
108 | // no-op since we're just writing to memory | ||
109 | } | ||
110 | |||
111 | // Read the PNG file using the libpng. The low-level interface is used here | ||
112 | // because we want to do various transformations (including setting the | ||
113 | // matte background if any, and applying gama) which can't be done with | ||
114 | // the high-level interface. The scanline also begins at the bottom of | ||
115 | // the image (per SecondLife conventions) instead of at the top, so we | ||
116 | // must assign row-pointers in "reverse" order. | ||
117 | BOOL LLPngWrapper::readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop) | ||
118 | { | ||
119 | try | ||
120 | { | ||
121 | // Create and initialize the png structures | ||
122 | mReadPngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, | ||
123 | this, &errorHandler, NULL); | ||
124 | if (mReadPngPtr == NULL) | ||
125 | { | ||
126 | throw "Problem creating png read structure"; | ||
127 | } | ||
128 | |||
129 | // Allocate/initialize the memory for image information. | ||
130 | mReadInfoPtr = png_create_info_struct(mReadPngPtr); | ||
131 | |||
132 | // Set up the input control | ||
133 | PngDataInfo dataPtr; | ||
134 | dataPtr.mData = src; | ||
135 | dataPtr.mOffset = 0; | ||
136 | |||
137 | png_set_read_fn(mReadPngPtr, &dataPtr, &readDataCallback); | ||
138 | png_set_sig_bytes(mReadPngPtr, 0); | ||
139 | |||
140 | // setup low-level read and get header information | ||
141 | png_read_info(mReadPngPtr, mReadInfoPtr); | ||
142 | png_get_IHDR(mReadPngPtr, mReadInfoPtr, &mWidth, &mHeight, | ||
143 | &mBitDepth, &mColorType, &mInterlaceType, | ||
144 | &mCompressionType, &mFilterMethod); | ||
145 | |||
146 | // Normalize the image, then get updated image information | ||
147 | // after transformations have been applied | ||
148 | normalizeImage(); | ||
149 | updateMetaData(); | ||
150 | |||
151 | // If a raw object is supplied, read the PNG image into its | ||
152 | // data space | ||
153 | if (rawImage != NULL) | ||
154 | { | ||
155 | rawImage->resize(static_cast<U16>(mWidth), | ||
156 | static_cast<U16>(mHeight), mChannels); | ||
157 | U8 *dest = rawImage->getData(); | ||
158 | int offset = mWidth * mChannels; | ||
159 | |||
160 | // Set up the row pointers and read the image | ||
161 | mRowPointers = new U8* [mHeight]; | ||
162 | for (U32 i=0; i < mHeight; i++) | ||
163 | { | ||
164 | mRowPointers[i] = &dest[(mHeight-i-1)*offset]; | ||
165 | } | ||
166 | |||
167 | png_read_image(mReadPngPtr, mRowPointers); | ||
168 | |||
169 | // Finish up, ensures all metadata are updated | ||
170 | png_read_end(mReadPngPtr, NULL); | ||
171 | } | ||
172 | |||
173 | // If an info object is supplied, copy the relevant info | ||
174 | if (infop != NULL) | ||
175 | { | ||
176 | infop->mHeight = static_cast<U16>(mHeight); | ||
177 | infop->mWidth = static_cast<U16>(mWidth); | ||
178 | infop->mComponents = mChannels; | ||
179 | } | ||
180 | |||
181 | mFinalSize = dataPtr.mOffset; | ||
182 | } | ||
183 | catch (png_const_charp msg) | ||
184 | { | ||
185 | mErrorMessage = msg; | ||
186 | releaseResources(); | ||
187 | return (FALSE); | ||
188 | } | ||
189 | |||
190 | // Clean up and return | ||
191 | releaseResources(); | ||
192 | return (TRUE); | ||
193 | } | ||
194 | |||
195 | // Do transformations to normalize the input to 8-bpp RGBA | ||
196 | void LLPngWrapper::normalizeImage() | ||
197 | { | ||
198 | // 1. Expand any palettes | ||
199 | // 2. Convert grayscales to RGB | ||
200 | // 3. Create alpha layer from transparency | ||
201 | // 4. Ensure 8-bpp for all images | ||
202 | // 5. Apply background matte if any | ||
203 | // 6. Set (or guess) gamma | ||
204 | |||
205 | if (mColorType == PNG_COLOR_TYPE_PALETTE) | ||
206 | { | ||
207 | png_set_palette_to_rgb(mReadPngPtr); | ||
208 | } | ||
209 | if (mColorType == PNG_COLOR_TYPE_GRAY && mBitDepth < 8) | ||
210 | { | ||
211 | png_set_gray_1_2_4_to_8(mReadPngPtr); | ||
212 | } | ||
213 | if (mColorType == PNG_COLOR_TYPE_GRAY | ||
214 | || mColorType == PNG_COLOR_TYPE_GRAY_ALPHA) | ||
215 | { | ||
216 | png_set_gray_to_rgb(mReadPngPtr); | ||
217 | } | ||
218 | if (png_get_valid(mReadPngPtr, mReadInfoPtr, PNG_INFO_tRNS)) | ||
219 | { | ||
220 | png_set_tRNS_to_alpha(mReadPngPtr); | ||
221 | } | ||
222 | if (mBitDepth < 8) | ||
223 | { | ||
224 | png_set_packing(mReadPngPtr); | ||
225 | } | ||
226 | else if (mBitDepth == 16) | ||
227 | { | ||
228 | png_set_strip_16(mReadPngPtr); | ||
229 | } | ||
230 | mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor); | ||
231 | if (mHasBKGD) | ||
232 | { | ||
233 | png_set_background(mReadPngPtr, mBackgroundColor, | ||
234 | PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); | ||
235 | } | ||
236 | |||
237 | #if LL_DARWIN | ||
238 | const F64 SCREEN_GAMMA = 1.8; | ||
239 | #else | ||
240 | const F64 SCREEN_GAMMA = 2.2; | ||
241 | #endif | ||
242 | |||
243 | if (png_get_gAMA(mReadPngPtr, mReadInfoPtr, &mGamma)) | ||
244 | { | ||
245 | png_set_gamma(mReadPngPtr, SCREEN_GAMMA, mGamma); | ||
246 | } | ||
247 | else | ||
248 | { | ||
249 | png_set_gamma(mReadPngPtr, SCREEN_GAMMA, 1/SCREEN_GAMMA); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | // Read out the image meta-data | ||
254 | void LLPngWrapper::updateMetaData() | ||
255 | { | ||
256 | png_read_update_info(mReadPngPtr, mReadInfoPtr); | ||
257 | mWidth = png_get_image_width(mReadPngPtr, mReadInfoPtr); | ||
258 | mHeight = png_get_image_height(mReadPngPtr, mReadInfoPtr); | ||
259 | mBitDepth = png_get_bit_depth(mReadPngPtr, mReadInfoPtr); | ||
260 | mColorType = png_get_color_type(mReadPngPtr, mReadInfoPtr); | ||
261 | mChannels = png_get_channels(mReadPngPtr, mReadInfoPtr); | ||
262 | mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor); | ||
263 | } | ||
264 | |||
265 | // Method to write raw image into PNG at dest. The raw scanline begins | ||
266 | // at the bottom of the image per SecondLife conventions. | ||
267 | BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest) | ||
268 | { | ||
269 | try | ||
270 | { | ||
271 | S8 numComponents = rawImage->getComponents(); | ||
272 | switch (numComponents) | ||
273 | { | ||
274 | case 1: | ||
275 | mColorType = PNG_COLOR_TYPE_GRAY; | ||
276 | break; | ||
277 | case 2: | ||
278 | mColorType = PNG_COLOR_TYPE_GRAY_ALPHA; | ||
279 | break; | ||
280 | case 3: | ||
281 | mColorType = PNG_COLOR_TYPE_RGB; | ||
282 | break; | ||
283 | case 4: | ||
284 | mColorType = PNG_COLOR_TYPE_RGB_ALPHA; | ||
285 | break; | ||
286 | default: | ||
287 | mColorType = -1; | ||
288 | } | ||
289 | |||
290 | if (mColorType == -1) | ||
291 | { | ||
292 | throw "Unsupported image: unexpected number of channels"; | ||
293 | } | ||
294 | |||
295 | mWritePngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, | ||
296 | NULL, &errorHandler, NULL); | ||
297 | if (!mWritePngPtr) | ||
298 | { | ||
299 | throw "Problem creating png write structure"; | ||
300 | } | ||
301 | |||
302 | mWriteInfoPtr = png_create_info_struct(mWritePngPtr); | ||
303 | |||
304 | // Setup write function | ||
305 | PngDataInfo dataPtr; | ||
306 | dataPtr.mData = dest; | ||
307 | dataPtr.mOffset = 0; | ||
308 | png_set_write_fn(mWritePngPtr, &dataPtr, &writeDataCallback, &writeFlush); | ||
309 | |||
310 | // Setup image params | ||
311 | mWidth = rawImage->getWidth(); | ||
312 | mHeight = rawImage->getHeight(); | ||
313 | mBitDepth = 8; // Fixed to 8-bpp in SL | ||
314 | mChannels = numComponents; | ||
315 | mInterlaceType = PNG_INTERLACE_NONE; | ||
316 | mCompressionType = PNG_COMPRESSION_TYPE_DEFAULT; | ||
317 | mFilterMethod = PNG_FILTER_TYPE_DEFAULT; | ||
318 | |||
319 | // Write header | ||
320 | png_set_IHDR(mWritePngPtr, mWriteInfoPtr, mWidth, mHeight, | ||
321 | mBitDepth, mColorType, mInterlaceType, | ||
322 | mCompressionType, mFilterMethod); | ||
323 | |||
324 | // Get data and compute row size | ||
325 | const U8* data = rawImage->getData(); | ||
326 | int offset = mWidth * mChannels; | ||
327 | |||
328 | // Ready to write, start with the header | ||
329 | png_write_info(mWritePngPtr, mWriteInfoPtr); | ||
330 | |||
331 | // Write image (sorry, must const-cast for libpng) | ||
332 | const U8 * rowPointer; | ||
333 | for (U32 i=0; i < mHeight; i++) | ||
334 | { | ||
335 | rowPointer = &data[(mHeight-1-i)*offset]; | ||
336 | png_write_row(mWritePngPtr, const_cast<png_bytep>(rowPointer)); | ||
337 | } | ||
338 | |||
339 | // Finish up | ||
340 | png_write_end(mWritePngPtr, mWriteInfoPtr); | ||
341 | mFinalSize = dataPtr.mOffset; | ||
342 | } | ||
343 | catch (png_const_charp msg) | ||
344 | { | ||
345 | mErrorMessage = msg; | ||
346 | releaseResources(); | ||
347 | return (FALSE); | ||
348 | } | ||
349 | |||
350 | releaseResources(); | ||
351 | return TRUE; | ||
352 | } | ||
353 | |||
354 | // Cleanup various internal structures | ||
355 | void LLPngWrapper::releaseResources() | ||
356 | { | ||
357 | if (mReadPngPtr || mReadInfoPtr) | ||
358 | { | ||
359 | png_destroy_read_struct(&mReadPngPtr, &mReadInfoPtr, png_infopp_NULL); | ||
360 | mReadPngPtr = NULL; | ||
361 | mReadInfoPtr = NULL; | ||
362 | } | ||
363 | |||
364 | if (mWritePngPtr || mWriteInfoPtr) | ||
365 | { | ||
366 | png_destroy_write_struct(&mWritePngPtr, &mWriteInfoPtr); | ||
367 | mWritePngPtr = NULL; | ||
368 | mWriteInfoPtr = NULL; | ||
369 | } | ||
370 | |||
371 | if (mRowPointers) | ||
372 | { | ||
373 | delete[] mRowPointers; | ||
374 | mRowPointers = NULL; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | // Get final image size after compression | ||
379 | U32 LLPngWrapper::getFinalSize() | ||
380 | { | ||
381 | return mFinalSize; | ||
382 | } | ||
383 | |||
384 | // Get last error message, if any | ||
385 | LLString LLPngWrapper::getErrorMessage() | ||
386 | { | ||
387 | return mErrorMessage; | ||
388 | } | ||
diff --git a/linden/indra/llimage/llpngwrapper.h b/linden/indra/llimage/llpngwrapper.h new file mode 100644 index 0000000..1b5b97f --- /dev/null +++ b/linden/indra/llimage/llpngwrapper.h | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * @file llpngwrapper.h | ||
3 | * | ||
4 | * Copyright (c) 2007 Peekay Semyorka. | ||
5 | * Copyright (c) 2007-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * Second Life Viewer Source Code | ||
8 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
9 | * to you under the terms of the GNU General Public License, version 2.0 | ||
10 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
11 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
12 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
13 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
14 | * | ||
15 | * There are special exceptions to the terms and conditions of the GPL as | ||
16 | * it is applied to this Source Code. View the full text of the exception | ||
17 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
18 | * online at http://secondlife.com/developers/opensource/flossexception | ||
19 | * | ||
20 | * By copying, modifying or distributing this software, you acknowledge | ||
21 | * that you have read and understood your obligations described above, | ||
22 | * and agree to abide by those obligations. | ||
23 | * | ||
24 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
25 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
26 | * COMPLETENESS OR PERFORMANCE. | ||
27 | */ | ||
28 | |||
29 | #ifndef LL_LLPNGWRAPPER_H | ||
30 | #define LL_LLPNGWRAPPER_H | ||
31 | |||
32 | #include "libpng12/png.h" | ||
33 | #include "llimage.h" | ||
34 | |||
35 | class LLPngWrapper | ||
36 | { | ||
37 | public: | ||
38 | LLPngWrapper(); | ||
39 | virtual ~LLPngWrapper(); | ||
40 | |||
41 | public: | ||
42 | struct ImageInfo | ||
43 | { | ||
44 | U16 mWidth; | ||
45 | U16 mHeight; | ||
46 | S8 mComponents; | ||
47 | }; | ||
48 | |||
49 | BOOL isValidPng(U8* src); | ||
50 | BOOL readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop = NULL); | ||
51 | BOOL writePng(const LLImageRaw* rawImage, U8* dst); | ||
52 | U32 getFinalSize(); | ||
53 | LLString getErrorMessage(); | ||
54 | |||
55 | protected: | ||
56 | void normalizeImage(); | ||
57 | void updateMetaData(); | ||
58 | |||
59 | private: | ||
60 | |||
61 | // Structure for writing/reading PNG data to/from memory | ||
62 | // as opposed to using a file. | ||
63 | struct PngDataInfo | ||
64 | { | ||
65 | U8 *mData; | ||
66 | U32 mOffset; | ||
67 | }; | ||
68 | |||
69 | static void writeFlush(png_structp png_ptr); | ||
70 | static void errorHandler(png_structp png_ptr, png_const_charp msg); | ||
71 | static void readDataCallback(png_structp png_ptr, png_bytep dest, png_size_t length); | ||
72 | static void writeDataCallback(png_structp png_ptr, png_bytep src, png_size_t length); | ||
73 | |||
74 | void releaseResources(); | ||
75 | |||
76 | png_structp mReadPngPtr; | ||
77 | png_infop mReadInfoPtr; | ||
78 | png_structp mWritePngPtr; | ||
79 | png_infop mWriteInfoPtr; | ||
80 | |||
81 | U8 **mRowPointers; | ||
82 | |||
83 | png_uint_32 mWidth; | ||
84 | png_uint_32 mHeight; | ||
85 | S32 mBitDepth; | ||
86 | S32 mColorType; | ||
87 | S32 mChannels; | ||
88 | S32 mInterlaceType; | ||
89 | S32 mCompressionType; | ||
90 | S32 mFilterMethod; | ||
91 | |||
92 | U32 mFinalSize; | ||
93 | |||
94 | BOOL mHasBKGD; | ||
95 | png_color_16p mBackgroundColor; | ||
96 | |||
97 | F64 mGamma; | ||
98 | |||
99 | LLString mErrorMessage; | ||
100 | }; | ||
101 | |||
102 | #endif | ||