2
2
#include " image.hpp"
3
3
#include " util.hpp"
4
4
#include " strtools.hpp"
5
+ #include " lwiconv.hpp"
5
6
6
7
#include < cstring>
7
8
#include < cassert>
@@ -52,16 +53,16 @@ Image::~Image() {
52
53
free (m_data);
53
54
}
54
55
55
- std::shared_ptr<Image> Image::load (const char * path) {
56
+ std::shared_ptr<Image> Image::load (const char * path, ChannelType convertOnLoad ) {
56
57
FILE* fp = fopen (path, " rb" );
57
58
if (!fp)
58
59
return nullptr ;
59
- auto img = load (fp);
60
+ auto img = load (fp, convertOnLoad );
60
61
fclose (fp);
61
62
return img;
62
63
}
63
64
64
- std::shared_ptr<Image> Image::load (FILE* fp) {
65
+ std::shared_ptr<Image> Image::load (FILE* fp, ChannelType convertOnLoad ) {
65
66
auto info = image_info (fp);
66
67
auto image = std::make_shared<Image>();
67
68
if (info.type == ChannelType::Float) {
@@ -73,9 +74,15 @@ std::shared_ptr<Image> Image::load(FILE* fp) {
73
74
else {
74
75
image->m_data = stbi_load_from_file (fp, &image->m_width , &image->m_height , &image->m_comps , info.comps );
75
76
}
77
+ image->m_type = info.type ;
76
78
77
79
if (!image->m_data )
78
80
return nullptr ;
81
+
82
+ if (convertOnLoad != ChannelType::None && convertOnLoad != info.type )
83
+ if (!image->convert (convertOnLoad))
84
+ return nullptr ; // Convert on load failed
85
+
79
86
return image;
80
87
}
81
88
@@ -86,6 +93,8 @@ void Image::clear() {
86
93
}
87
94
88
95
bool Image::save (const char * file, FileFormat format) {
96
+ using enum ChannelType;
97
+
89
98
if (!file || !m_data || (format != Tga && format != Png && format != Jpeg && format != Bmp && format != Hdr))
90
99
return false ;
91
100
@@ -97,7 +106,7 @@ bool Image::save(const char* file, FileFormat format) {
97
106
if (m_type != Float) {
98
107
dataToUse = malloc (m_width * m_height * sizeof (float ) * m_comps);
99
108
dataIsOurs = true ;
100
- if (!convert_formats (m_data, dataToUse, m_type, Float, m_comps, m_width, m_height )) {
109
+ if (!convert_formats (m_data, dataToUse, m_type, Float, m_width, m_height, m_comps, m_comps, pixel_size (), imglib::pixel_size (Float, m_comps) )) {
101
110
free (dataToUse);
102
111
return false ;
103
112
}
@@ -115,7 +124,7 @@ bool Image::save(const char* file, FileFormat format) {
115
124
if (m_type != UInt8) {
116
125
dataToUse = malloc (m_width * m_height * sizeof (uint8_t ) * m_comps);
117
126
dataIsOurs = true ;
118
- if (!convert_formats (m_data, dataToUse, m_type, UInt8, m_comps, m_width, m_height )) {
127
+ if (!convert_formats (m_data, dataToUse, m_type, UInt8, m_width, m_height, m_comps, m_comps, pixel_size (), imglib::pixel_size (UInt8, m_comps) )) {
119
128
free (dataToUse);
120
129
return false ;
121
130
}
@@ -157,10 +166,10 @@ bool Image::resize(int newW, int newH) {
157
166
158
167
VTFImageFormat Image::vtf_format () const {
159
168
switch (m_type) {
160
- case imglib ::UInt16:
161
- // @TODO: How to handle RGBA16 ? DONT i guess
162
- return IMAGE_FORMAT_RGBA16161616F ;
163
- case imglib ::Float:
169
+ case ChannelType ::UInt16:
170
+ // @TODO: How to handle RGB16 ? DONT i guess
171
+ return IMAGE_FORMAT_RGBA16161616 ;
172
+ case ChannelType ::Float:
164
173
return (m_comps == 3 ) ? IMAGE_FORMAT_RGB323232F
165
174
: (m_comps == 1 ? IMAGE_FORMAT_R32F : IMAGE_FORMAT_RGBA32323232F);
166
175
default :
@@ -170,6 +179,7 @@ VTFImageFormat Image::vtf_format() const {
170
179
171
180
bool imglib::resize (
172
181
void * indata, void ** useroutdata, ChannelType srcType, int comps, int w, int h, int newW, int newH) {
182
+ using enum ChannelType;
173
183
stbir_datatype type;
174
184
switch (srcType) {
175
185
case Float:
@@ -215,63 +225,66 @@ size_t imglib::bytes_for_image(int w, int h, ChannelType type, int comps) {
215
225
return w * h * comps * bpc;
216
226
}
217
227
218
- template <int COMPS>
219
228
bool convert_formats_internal (
220
- const void * srcData, void * dstData, ChannelType srcChanType, ChannelType dstChanType, int w, int h) {
221
- static_assert (COMPS > 0 && COMPS <= 4 , " Comps is out of range " ) ;
229
+ const void * srcData, void * dstData, ChannelType srcChanType, ChannelType dstChanType, int w, int h, int inComps, int outComps, int inStride, int outStride, const lwiconv::PixelF& pdef ) {
230
+ using enum ChannelType ;
222
231
223
232
if (srcChanType == UInt8) {
224
233
// RGBX32
225
234
if (dstChanType == Float)
226
- convert_8_to_32<COMPS >(srcData, dstData, w, h);
235
+ lwiconv::convert_generic< uint8_t , float >(srcData, dstData, w, h, inComps, outComps, inStride, outStride, pdef );
227
236
// RGBX16
228
237
else if (dstChanType == UInt16)
229
- convert_8_to_16<COMPS>(srcData, dstData, w, h);
238
+ lwiconv::convert_generic<uint8_t , uint16_t >(srcData, dstData, w, h, inComps, outComps, inStride, outStride, pdef);
239
+ // RGBX8 (just adding/removing channel(s))
240
+ else if (dstChanType == UInt8)
241
+ lwiconv::convert_generic<uint8_t , uint8_t >(srcData, dstData, w, h, inComps, outComps, inStride, outStride, pdef);
230
242
return true ;
231
243
}
232
244
// RGBX32 -> RGBX[8|16]
233
245
else if (srcChanType == Float) {
234
246
// RGBX16
235
247
if (dstChanType == UInt16)
236
- convert_32_to_16<COMPS >(srcData, dstData, w, h);
248
+ lwiconv::convert_generic< float , uint16_t >(srcData, dstData, w, h, inComps, outComps, inStride, outStride, pdef );
237
249
// RGBX8
238
250
else if (dstChanType == UInt8)
239
- convert_32_to_8<COMPS>(srcData, dstData, w, h);
251
+ lwiconv::convert_generic<float , uint8_t >(srcData, dstData, w, h, inComps, outComps, inStride, outStride, pdef);
252
+ // RGBX32 (just adding/removing channel(s))
253
+ else if (dstChanType == Float)
254
+ lwiconv::convert_generic<float , float >(srcData, dstData, w, h, inComps, outComps, inStride, outStride, pdef);
240
255
return true ;
241
256
}
242
- // RGBX16
257
+ // RGBX16 -> RGBX[8|32F]
243
258
else if (srcChanType == UInt16) {
259
+ // RGBX8
244
260
if (dstChanType == UInt8)
245
- convert_16_to_8<COMPS>(srcData, dstData, w, h);
261
+ lwiconv::convert_generic<uint16_t , uint8_t >(srcData, dstData, w, h, inComps, outComps, inStride, outStride, pdef);
262
+ // RGBX32
246
263
else if (dstChanType == Float)
247
- convert_16_to_32<COMPS>(srcData, dstData, w, h);
264
+ lwiconv::convert_generic<uint16_t , float >(srcData, dstData, w, h, inComps, outComps, inStride, outStride, pdef);
265
+ // RGBX16 (just adding/removing channel(s))
266
+ else if (dstChanType == UInt16)
267
+ lwiconv::convert_generic<uint16_t , uint16_t >(srcData, dstData, w, h, inComps, outComps, inStride, outStride, pdef);
248
268
return true ;
249
269
}
250
270
251
271
return false ;
252
272
}
253
273
254
274
bool imglib::convert_formats (
255
- const void * srcData, void * dstData, ChannelType srcChanType, ChannelType dstChanType, int comps , int w , int h ) {
275
+ const void * srcData, void * dstData, ChannelType srcChanType, ChannelType dstChanType, int w , int h , int inComps, int outComps, int inStride, int outStride, const lwiconv::PixelF& pdef ) {
256
276
// No conv needed
257
- if (srcChanType == dstChanType)
277
+ if (srcChanType == dstChanType && inComps == outComps )
258
278
return true ;
259
279
260
- if (comps == 4 )
261
- return convert_formats_internal<4 >(srcData, dstData, srcChanType, dstChanType, w, h);
262
- else if (comps == 3 )
263
- return convert_formats_internal<3 >(srcData, dstData, srcChanType, dstChanType, w, h);
264
- else if (comps == 2 )
265
- return convert_formats_internal<2 >(srcData, dstData, srcChanType, dstChanType, w, h);
266
- else if (comps == 1 )
267
- return convert_formats_internal<1 >(srcData, dstData, srcChanType, dstChanType, w, h);
268
- return false ;
280
+ return convert_formats_internal (srcData, dstData, srcChanType, dstChanType, w, h, inComps, outComps, inStride, outStride, pdef);
269
281
}
270
282
271
- bool Image::convert (ChannelType dstChanType) {
272
- void * dst = malloc (imglib::bytes_for_image (m_width, m_height, m_type, m_comps));
283
+ bool Image::convert (ChannelType dstChanType, int channels, const lwiconv::PixelF& pdef) {
284
+ channels = channels <= 0 ? m_comps : channels;
285
+ void * dst = malloc (imglib::bytes_for_image (m_width, m_height, m_type, channels));
273
286
274
- if (!convert_formats (m_data, dst, m_type, dstChanType, m_comps, m_width, m_height )) {
287
+ if (!convert_formats (m_data, dst, m_type, dstChanType, m_width, m_height, m_comps, channels, pixel_size (), channels * channel_size (dstChanType), pdef )) {
275
288
free (dst);
276
289
return false ;
277
290
}
@@ -302,6 +315,7 @@ static bool process_image_internal(void* indata, int comps, int w, int h, ProcFl
302
315
}
303
316
304
317
bool Image::process (ProcFlags flags) {
318
+ using enum ChannelType;
305
319
switch (m_type) {
306
320
case UInt8:
307
321
return process_image_internal<uint8_t >(m_data, m_comps, m_width, m_height, flags);
@@ -374,3 +388,21 @@ static ImageInfo_t image_info(FILE* fp) {
374
388
375
389
return info;
376
390
}
391
+
392
+ size_t imglib::pixel_size (ChannelType type, int channels) {
393
+ return channels * channel_size (type);
394
+ }
395
+
396
+ size_t imglib::channel_size (ChannelType type) {
397
+ switch (type) {
398
+ case imglib::ChannelType::UInt8:
399
+ return 1 ;
400
+ case imglib::ChannelType::UInt16:
401
+ return 2 ;
402
+ case imglib::ChannelType::Float:
403
+ return 4 ;
404
+ default :
405
+ assert (0 );
406
+ return 1 ;
407
+ }
408
+ }
0 commit comments