24 #define STB_IMAGE_STATIC
25 #define STB_IMAGE_IMPLEMENTATION
30 #define STBI_ONLY_JPEG
41 #ifndef HAVE_SOFTIMAGE_PIC
55 #define STBI_FAILURE_USERMSG
61 #include "stb_image.h"
67 static const char *
const stb_extensions[] = {
69 #if !defined(HAVE_JPEG) && !defined(ANDROID)
81 #ifndef HAVE_SOFTIMAGE_PIC
93 static const int num_stb_extensions =
sizeof(stb_extensions) /
sizeof(
const char *);
96 static int cb_read(
void *user,
char *data,
int size) {
97 istream *in = (istream *)user;
98 nassertr(in !=
nullptr, 0);
100 in->read(data, size);
104 in->clear(ios::eofbit);
107 return (
int)in->gcount();
110 static void cb_skip(
void *user,
int n) {
111 istream *in = (istream *)user;
112 nassertv(in !=
nullptr);
114 in->seekg(n, ios::cur);
117 if (in->fail() && n > 0) {
123 static int cb_eof(
void *user) {
124 istream *in = (istream *)user;
125 nassertr(in !=
nullptr, 1);
135 class StbImageReader :
public PNMReader {
137 StbImageReader(
PNMFileType *type, istream *file,
bool owns_file,
string magic_number);
145 stbi__context _context;
146 unsigned char _buffer[1024];
154 PNMFileTypeStbImage::
155 PNMFileTypeStbImage() {
161 string PNMFileTypeStbImage::
170 int PNMFileTypeStbImage::
171 get_num_extensions()
const {
172 return num_stb_extensions;
179 string PNMFileTypeStbImage::
180 get_extension(
int n)
const {
181 nassertr(n >= 0 && n < num_stb_extensions,
string());
182 return stb_extensions[n];
189 bool PNMFileTypeStbImage::
190 has_magic_number()
const {
199 bool PNMFileTypeStbImage::
200 matches_magic_number(
const string &magic_number)
const {
210 make_reader(istream *file,
bool owns_file,
const string &magic_number) {
212 return new StbImageReader(
this, file, owns_file, magic_number);
219 StbImageReader(
PNMFileType *type, istream *file,
bool owns_file,
string magic_number) :
224 _context.io.read = cb_read;
225 _context.io.skip = cb_skip;
226 _context.io.eof = cb_eof;
227 _context.io_user_data = (
void *)file;
228 _context.buflen =
sizeof(_context.buffer_start);
229 _context.read_from_callbacks = 1;
230 _context.img_buffer = _buffer;
231 _context.img_buffer_original = _buffer;
236 memcpy(_buffer, magic_number.data(), magic_number.size());
237 file->read((
char *)_buffer + magic_number.size(),
sizeof(_buffer) - magic_number.size());
240 file->clear(ios::eofbit);
243 size_t length = file->gcount() + magic_number.size();
244 _context.img_buffer_end = _buffer + length;
245 _context.img_buffer_original_end = _context.img_buffer_end;
253 if (magic_number[0] ==
'#' && magic_number[1] ==
'?' &&
254 stbi__hdr_info(&_context, &_x_size, &_y_size, &_num_channels)) {
259 }
else if (magic_number[0] ==
'\x89' && magic_number[1] ==
'P' &&
260 stbi__png_info_raw(&png, &_x_size, &_y_size, &_num_channels)) {
263 if (png.depth == 16) {
269 }
else if (stbi__info_main(&_context, &_x_size, &_y_size, &_num_channels)) {
275 <<
"stb_info failure: " << stbi_failure_reason() <<
"\n";
284 bool StbImageReader::
285 is_floating_point() {
293 bool StbImageReader::
300 if (_context.img_buffer_end == _context.img_buffer_original_end) {
302 stbi__rewind(&_context);
306 _file->seekg(0, ios::beg);
307 if (_file->tellg() != (std::streampos)0) {
309 <<
"Could not reposition file pointer to the beginning.\n";
313 stbi__start_callbacks(&_context, &io_callbacks, (
void *)_file);
316 nassertr(_num_channels == 3,
false);
320 char buffer[STBI__HDR_BUFLEN];
326 unsigned char count, value;
327 int i, j, k, c1, c2, z;
328 const char *headerToken;
331 headerToken = stbi__hdr_gettoken(&_context, buffer);
332 if (strcmp(headerToken,
"#?RADIANCE") != 0 && strcmp(headerToken,
"#?RGBE") != 0) {
334 <<
"Missing #?RADIANCE or #?RGBE header.\n";
340 token = stbi__hdr_gettoken(&_context, buffer);
341 if (token[0] == 0)
break;
342 if (strcmp(token,
"FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
346 pnmimage_cat.error() <<
"Unsupported HDR format.\n";
352 token = stbi__hdr_gettoken(&_context, buffer);
353 if (strncmp(token,
"-Y ", 3)) {
354 pnmimage_cat.error() <<
"Unsupported HDR data layout.\n";
358 height = (int) strtol(token, &token, 10);
359 while (*token ==
' ') ++token;
360 if (strncmp(token,
"+X ", 3)) {
361 pnmimage_cat.error() <<
"Unsupported HDR data layout.\n";
365 width = (int) strtol(token,
nullptr, 10);
368 pfm.
clear(width, height, 3);
371 float *hdr_data = (
float *)&table[0];
375 if (width < 8 || width >= 32768) {
377 for (j = 0; j < height; ++j) {
378 for (i = 0; i < width; ++i) {
381 stbi__getn(&_context, rgbe, 4);
382 stbi__hdr_convert(hdr_data + j * width * 3 + i * 3, rgbe, 3);
389 for (j = 0; j < height; ++j) {
390 c1 = stbi__get8(&_context);
391 c2 = stbi__get8(&_context);
392 len = stbi__get8(&_context);
393 if (c1 != 2 || c2 != 2 || (len & 0x80)) {
397 rgbe[0] = (stbi_uc) c1;
398 rgbe[1] = (stbi_uc) c2;
399 rgbe[2] = (stbi_uc) len;
400 rgbe[3] = (stbi_uc) stbi__get8(&_context);
401 stbi__hdr_convert(hdr_data, rgbe, 3);
405 goto main_decode_loop;
408 len |= stbi__get8(&_context);
410 pnmimage_cat.error() <<
"Corrupt HDR: invalid decoded scanline length.\n";
414 if (scanline ==
nullptr) {
415 scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);
417 pnmimage_cat.error() <<
"Out of memory while reading HDR file.\n";
423 for (k = 0; k < 4; ++k) {
426 while ((nleft = width - i) > 0) {
427 count = stbi__get8(&_context);
430 value = stbi__get8(&_context);
433 pnmimage_cat.error() <<
"Bad RLE data in HDR file.\n";
437 for (z = 0; z < count; ++z) {
438 scanline[i++ * 4 + k] = value;
443 pnmimage_cat.error() <<
"Bad RLE data in HDR file.\n";
447 for (z = 0; z < count; ++z) {
448 scanline[i++ * 4 + k] = stbi__get8(&_context);
453 for (i = 0; i < width; ++i) {
454 stbi__hdr_convert(hdr_data+(j*width + i)*3, scanline + i*4, 3);
476 read_data(
xel *array, xelval *alpha) {
482 if (_context.img_buffer_end == _context.img_buffer_original_end) {
484 stbi__rewind(&_context);
488 _file->seekg(0, ios::beg);
489 if (_file->tellg() != (std::streampos)0) {
491 <<
"Could not reposition file pointer to the beginning.\n";
495 stbi__start_callbacks(&_context, &io_callbacks, (
void *)_file);
500 int comp = _num_channels;
502 if (_maxval != 65535) {
503 data = stbi__load_and_postprocess_8bit(&_context, &cols, &rows, &comp, _num_channels);
505 data = stbi__load_and_postprocess_16bit(&_context, &cols, &rows, &comp, _num_channels);
508 if (data ==
nullptr) {
510 <<
"stbi_load failure: " << stbi_failure_reason() <<
"\n";
514 nassertr(cols == _x_size, 0);
515 nassertr(comp == _num_channels, 0);
517 size_t pixels = (size_t)_x_size * (
size_t)rows;
518 if (_maxval != 65535) {
519 uint8_t *ptr = (uint8_t *)data;
520 switch (_num_channels) {
522 for (
size_t i = 0; i < pixels; ++i) {
523 PPM_ASSIGN(array[i], ptr[i], ptr[i], ptr[i]);
528 for (
size_t i = 0; i < pixels; ++i) {
529 PPM_ASSIGN(array[i], ptr[0], ptr[0], ptr[0]);
536 for (
size_t i = 0; i < pixels; ++i) {
537 PPM_ASSIGN(array[i], ptr[0], ptr[1], ptr[2]);
543 for (
size_t i = 0; i < pixels; ++i) {
544 PPM_ASSIGN(array[i], ptr[0], ptr[1], ptr[2]);
551 uint16_t *ptr = (uint16_t *)data;
552 switch (_num_channels) {
554 for (
size_t i = 0; i < pixels; ++i) {
555 PPM_ASSIGN(array[i], ptr[i], ptr[i], ptr[i]);
560 for (
size_t i = 0; i < pixels; ++i) {
561 PPM_ASSIGN(array[i], ptr[0], ptr[0], ptr[0]);
568 memcpy(array, ptr, pixels *
sizeof(uint16_t) * 3);
572 for (
size_t i = 0; i < pixels; ++i) {
573 PPM_ASSIGN(array[i], ptr[0], ptr[1], ptr[2]);
581 stbi_image_free(data);
588 void PNMFileTypeStbImage::
589 register_with_read_factory() {
591 register_factory(get_class_type(), make_PNMFileTypeStbImage);
607 #endif // HAVE_STB_IMAGE