/src/ogre/PlugIns/STBICodec/src/OgreSTBICodec.cpp
Line | Count | Source |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | |
29 | | #include "OgreSTBICodec.h" |
30 | | #include "OgreLogManager.h" |
31 | | #include "OgreDataStream.h" |
32 | | #include "OgreImage.h" |
33 | | |
34 | | #include "OgrePlatformInformation.h" |
35 | | #include "OgreString.h" |
36 | | |
37 | | #if __OGRE_HAVE_NEON |
38 | | #define STBI_NEON |
39 | | #endif |
40 | | |
41 | | #define STBI_NO_STDIO |
42 | | #define STB_IMAGE_IMPLEMENTATION |
43 | | #define STB_IMAGE_STATIC |
44 | | // guard against wrong image headers, limits to 16K x 16K |
45 | 6.30k | #define STBI_MAX_DIMENSIONS 16384 |
46 | | #include "stbi/stb_image.h" |
47 | | |
48 | | #ifdef HAVE_ZLIB |
49 | | #include <zlib.h> |
50 | | static Ogre::uchar* custom_zlib_compress(Ogre::uchar* data, int data_len, int* out_len, int /*quality*/) |
51 | | { |
52 | | unsigned long destLen = compressBound(data_len); |
53 | | Ogre::uchar* dest = (Ogre::uchar*)malloc(destLen); |
54 | | int ret = compress(dest, &destLen, data, data_len); // use default quality |
55 | | if (ret != Z_OK) |
56 | | { |
57 | | free(dest); |
58 | | OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "compress failed"); |
59 | | } |
60 | | |
61 | | *out_len = destLen; |
62 | | return dest; |
63 | | } |
64 | | #define STBIW_ZLIB_COMPRESS custom_zlib_compress |
65 | | #endif |
66 | | |
67 | | #define STB_IMAGE_WRITE_IMPLEMENTATION |
68 | | #define STBI_WRITE_NO_STDIO |
69 | | #include "stbi/stb_image_write.h" |
70 | | |
71 | | namespace Ogre { |
72 | | |
73 | | STBIImageCodec::RegisteredCodecList STBIImageCodec::msCodecList; |
74 | | //--------------------------------------------------------------------- |
75 | | void STBIImageCodec::startup(void) |
76 | 4.69k | { |
77 | 4.69k | stbi_convert_iphone_png_to_rgb(1); |
78 | 4.69k | stbi_set_unpremultiply_on_load(1); |
79 | | |
80 | 4.69k | LogManager::getSingleton().logMessage("stb_image - v2.30 - public domain image loader"); |
81 | | |
82 | | // Register codecs |
83 | 4.69k | String exts = "jpeg,jpg,png,bmp,psd,tga,gif,pic,ppm,pgm,hdr"; |
84 | 4.69k | StringVector extsVector = StringUtil::split(exts, ","); |
85 | 4.69k | for (auto & v : extsVector) |
86 | 51.6k | { |
87 | 51.6k | ImageCodec* codec = OGRE_NEW STBIImageCodec(v); |
88 | 51.6k | msCodecList.push_back(codec); |
89 | 51.6k | Codec::registerCodec(codec); |
90 | 51.6k | } |
91 | | |
92 | 4.69k | LogManager::getSingleton().logMessage("Supported formats: " + exts); |
93 | 4.69k | } |
94 | | //--------------------------------------------------------------------- |
95 | | void STBIImageCodec::shutdown(void) |
96 | 4.69k | { |
97 | 4.69k | for (auto & i : msCodecList) |
98 | 51.6k | { |
99 | 51.6k | Codec::unregisterCodec(i); |
100 | 51.6k | OGRE_DELETE i; |
101 | 51.6k | } |
102 | 4.69k | msCodecList.clear(); |
103 | 4.69k | } |
104 | | //--------------------------------------------------------------------- |
105 | | STBIImageCodec::STBIImageCodec(const String &type): |
106 | 51.6k | mType(type) |
107 | 51.6k | { |
108 | 51.6k | } |
109 | | //--------------------------------------------------------------------- |
110 | | DataStreamPtr STBIImageCodec::encode(const Any& input) const |
111 | 677 | { |
112 | 677 | if(mType != "png") { |
113 | 0 | OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, |
114 | 0 | "currently only encoding to PNG supported", |
115 | 0 | "STBIImageCodec::encode" ) ; |
116 | 0 | } |
117 | | |
118 | 677 | Image* image = any_cast<Image*>(input); |
119 | 677 | PixelFormat format = image->getFormat(); |
120 | 677 | uchar* inputData = image->getData(); |
121 | | |
122 | | // Convert image data to ABGR format for STBI (unless it's already compatible) |
123 | 677 | uchar* tempData = 0; |
124 | 677 | if(format != Ogre::PF_A8B8G8R8 && format != PF_B8G8R8 && format != PF_BYTE_LA && |
125 | 216 | format != PF_L8 && format != PF_R8) |
126 | 0 | { |
127 | 0 | format = Ogre::PF_A8B8G8R8; |
128 | 0 | size_t tempDataSize = PixelUtil::getMemorySize(image->getWidth(), image->getHeight(), 1, format); |
129 | 0 | tempData = OGRE_ALLOC_T(unsigned char, tempDataSize, Ogre::MEMCATEGORY_GENERAL); |
130 | 0 | Ogre::PixelBox pbOut(image->getPixelBox(), format, tempData); |
131 | 0 | PixelUtil::bulkPixelConversion(image->getPixelBox(), pbOut); |
132 | |
|
133 | 0 | inputData = tempData; |
134 | 0 | } |
135 | | |
136 | | // Save to PNG |
137 | 677 | int channels = PixelUtil::getComponentCount(format); |
138 | 677 | int len; |
139 | 677 | uchar* data = stbi_write_png_to_mem(inputData, image->getRowSpan(), image->getWidth(), image->getHeight(), channels, &len); |
140 | | |
141 | 677 | if(tempData) |
142 | 0 | { |
143 | 0 | OGRE_FREE(tempData, MEMCATEGORY_GENERAL); |
144 | 0 | } |
145 | | |
146 | 677 | if (!data) { |
147 | 0 | OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, |
148 | 0 | "Error encoding image: " + String(stbi_failure_reason()), |
149 | 0 | "STBIImageCodec::encode"); |
150 | 0 | } |
151 | | |
152 | 677 | return DataStreamPtr(new MemoryDataStream(data, len, true)); |
153 | 677 | } |
154 | | //--------------------------------------------------------------------- |
155 | | void STBIImageCodec::encodeToFile(const Any& input, const String& outFileName) const |
156 | 677 | { |
157 | 677 | #if OGRE_PLATFORM != OGRE_PLATFORM_EMSCRIPTEN |
158 | 677 | MemoryDataStreamPtr data = static_pointer_cast<MemoryDataStream>(encode(input)); |
159 | 677 | std::ofstream f(outFileName.c_str(), std::ios::out | std::ios::binary); |
160 | | |
161 | 677 | if (!f.is_open()) |
162 | 0 | { |
163 | 0 | OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "could not open file " + outFileName); |
164 | 0 | } |
165 | | |
166 | 677 | f.write((char*)data->getPtr(), data->size()); |
167 | 677 | #endif |
168 | 677 | } |
169 | | //--------------------------------------------------------------------- |
170 | | void STBIImageCodec::decode(const DataStreamPtr& input, const Any& output) const |
171 | 4.69k | { |
172 | 4.69k | auto image = any_cast<Image*>(output); |
173 | 4.69k | String contents = input->getAsString(); |
174 | | |
175 | 4.69k | int width, height, components; |
176 | 4.69k | stbi_uc* pixelData = stbi_load_from_memory((const uchar*)contents.data(), |
177 | 4.69k | static_cast<int>(contents.size()), &width, &height, &components, 0); |
178 | | |
179 | 4.69k | if (!pixelData) |
180 | 3.55k | { |
181 | 3.55k | const char* reason = stbi_failure_reason(); |
182 | 3.55k | OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, |
183 | 3.55k | "Error decoding image: " + String(reason ? reason : "no reason")); |
184 | 3.55k | } |
185 | | |
186 | 1.13k | if (width <= 0 || height <= 0) |
187 | 0 | { |
188 | 0 | stbi_image_free(pixelData); |
189 | 0 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, |
190 | 0 | StringUtil::format("Image has invalid dimensions: %dx%d", width, height)); |
191 | 0 | } |
192 | | |
193 | 1.13k | PixelFormat format = PF_UNKNOWN; |
194 | 1.13k | switch( components ) |
195 | 1.13k | { |
196 | 315 | case 1: |
197 | 315 | format = PF_BYTE_L; |
198 | 315 | break; |
199 | 9 | case 2: |
200 | 9 | format = PF_BYTE_LA; |
201 | 9 | break; |
202 | 550 | case 3: |
203 | 550 | format = PF_BYTE_RGB; |
204 | 550 | break; |
205 | 263 | case 4: |
206 | 263 | format = PF_BYTE_RGBA; |
207 | 263 | break; |
208 | 0 | default: |
209 | 0 | stbi_image_free(pixelData); |
210 | 0 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Only 1..4 channels supported"); |
211 | 0 | break; |
212 | 1.13k | } |
213 | | |
214 | 1.13k | image->loadDynamicImage(pixelData, width, height, 1, format, true); |
215 | 1.13k | } |
216 | | //--------------------------------------------------------------------- |
217 | | String STBIImageCodec::getType() const |
218 | 103k | { |
219 | 103k | return mType; |
220 | 103k | } |
221 | | |
222 | | #ifndef OGRE_STATIC_LIB |
223 | | extern "C" void _OgreSTBICodecExport dllStartPlugin(); |
224 | | extern "C" void _OgreSTBICodecExport dllStopPlugin(); |
225 | | |
226 | | extern "C" void _OgreSTBICodecExport dllStartPlugin() |
227 | | { |
228 | | STBIImageCodec::startup(); |
229 | | } |
230 | | extern "C" void _OgreSTBICodecExport dllStopPlugin() |
231 | | { |
232 | | STBIImageCodec::shutdown(); |
233 | | } |
234 | | #endif |
235 | | } |