Coverage Report

Created: 2026-08-13 06:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}