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 PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual int read_data(xel *array, xelval *alpha)
Reads in an entire image all at once, storing it in the pre-allocated _x_size * _y_size array and alp...
virtual bool is_floating_point()
Returns true if this PNMFileType represents a floating-point image type, false if it is a normal,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Base class for objects that can be written to and read from Bam files.
This is the base class of a family of classes that represent particular image file types that PNMImag...
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
virtual bool read_pfm(PfmFile &pfm)
Reads floating-point data directly into the indicated PfmFile.
void swap_table(vector_float &table)
This is a very low-level function that completely exchanges the PfmFile's internal table of floating-...
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component,...
An instance of this class is passed to the Factory when requesting it to do its business and construc...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e....
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is an abstract base class that defines the interface for reading image files of various types.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
TypeHandle is the identifier used to differentiate C++ class types.
void clear()
Eliminates all data in the file.