static ImgloadErrorCode IMGLOAD_CALLBACK png_read_data(ImgloadPlugin plugin, ImgloadImage img) { stbi_io_callbacks callbacks; callbacks.read = stb_read; callbacks.skip = stb_skip; callbacks.eof = stb_eof; imgload_plugin_image_seek(img, 0, SEEK_SET); int width, height, components; stbi_uc* ret = stbi_load_from_callbacks(&callbacks, img, &width, &height, &components, STBI_default); if (!ret) { return IMGLOAD_ERR_PLUGIN_ERROR; } int bpp; switch (components) { case STBI_grey: bpp = 1; break; case STBI_rgb: bpp = 3; break; case STBI_rgb_alpha: bpp = 4; break; default: return IMGLOAD_ERR_UNSUPPORTED_FORMAT; } size_t stride = width * bpp; size_t total_size = height * stride; uint8_t* buffer = (uint8_t*)imgload_plugin_realloc(plugin, NULL, total_size); if (!buffer) { stbi_image_free(ret); return IMGLOAD_ERR_OUT_OF_MEMORY; } // Copy data to our buffer memcpy(buffer, ret, total_size); stbi_image_free(ret); ImgloadImageData data; data.width = width; data.height = height; data.depth = 1; data.stride = stride; data.data_size = total_size; data.data = buffer; return imgload_plugin_image_set_image_data(img, 0, 0, &data, 1); }
Stb::ImagePtr Stb::Image::loadFromStream(std::istream & s, Format fmt) { ImagePtr image = std::static_pointer_cast<Image>(std::make_shared<Image::Wrapper>()); try { int imageFmt = UNKNOWN; image->m_Data = stbi_load_from_callbacks(&g_StbCB, &s, &image->m_Width, &image->m_Height, &imageFmt, fmt); if (!image->m_Data) throw std::runtime_error(stbi_failure_reason()); image->m_Format = static_cast<Format>(fmt == UNKNOWN ? imageFmt : fmt); if (image->m_Format == UNKNOWN) throw std::runtime_error("unable to determine pixel format for the image."); } catch (const std::exception & e) { if (image->m_Data) stbi_image_free(image->m_Data); std::clog << "Error reading image: " << e.what() << std::endl; image->m_Data = &g_DummyData; image->m_Width = 0; image->m_Height = 0; image->m_Format = UNKNOWN; } return image; }
bool LoadImage( Image* image, const char* vfsPath ) { memset(image, 0, sizeof(Image)); PHYSFS_File* file = PHYSFS_openRead(vfsPath); if(!file) { Error("Can't load '%s': %s", vfsPath, PHYSFS_getLastError()); return false; } stbi_set_flip_vertically_on_load(1); image->data = stbi_load_from_callbacks(&PhysFSCallbacks, file, &image->width, &image->height, &image->channelCount, STBI_default); PHYSFS_close(file); if(!image->data) { Error("Can't load '%s': %s", vfsPath, stbi_failure_reason()); return false; } image->type = GL_UNSIGNED_BYTE; return true; }
//bpp == the resulting bits per pixel //bpp == the source image bits per pixel //req_bpp == use this instead of the source bool load_info( QuickVec<unsigned char> &out_buffer, const char* _id, int* w, int* h, int* bpp, int* bpp_source, int req_bpp = 4 ) { //get a io file pointer to the image snow::io::iosrc* src = snow::io::iosrc_from_file(_id, "rb"); if(!src) { snow::log(1, "/ snow / cannot open image file from %s", _id); return false; } //always use callbacks because we use snow abstracted IO stbi_io_callbacks stbi_snow_callbacks = { snow_stbi_read, snow_stbi_skip, snow_stbi_eof }; unsigned char *data = stbi_load_from_callbacks(&stbi_snow_callbacks, src, w, h, bpp_source, req_bpp); //we are done with the src snow::io::close(src); snow::log(2, "/ snow / image / w:%d h:%d source bpp:%d bpp:%d\n", *w, *h, *bpp_source, req_bpp); if(data != NULL) { int _w = *w; int _h = *h; int _bpp = *bpp_source; //if a requested bpp was given, override it if(req_bpp != 0) { _bpp = req_bpp; } //actual used bpp *bpp = _bpp; //work out the total length of the buffer unsigned int length = _w * _h * _bpp; //store it out_buffer.Set(data, length); //clean up used memory stbi_image_free(data); } else { //data != NULL snow::log(1, "/ snow / image unable to be loaded by snow: %s reason: %s", _id, stbi_failure_reason()); return false; } return true; } //load_info
DeletablePixels loadStbi(const Path &path, int &w, int &h, int &channels) { InputStreamHandle in = FileUtils::openInputStream(path); if (!in) return makeVoidPixels(); return DeletablePixels(stbi_load_from_callbacks(&istreamCallback, in.get(), &w, &h, &channels, 4), stbi_image_free); }
//bpp == the resulting bits per pixel //bpp == the source image bits per pixel //req_bpp == use this instead of the source bool info_from_bytes( QuickVec<unsigned char> &out_buffer, const unsigned char* bytes, int byteOffset, int byteLength, const char* _id, int *w, int *h, int* bpp, int* bpp_source, int req_bpp = 4 ) { //get a io file pointer to the image snow::io::iosrc* src = snow::io::iosrc_from_mem( (void*)(bytes + byteOffset), byteLength ); if(!src) { snow::log(1, "/ snow / cannot open bytes from %s", _id); return false; } //always use callbacks because we use snow abstracted IO stbi_io_callbacks stbi_snow_callbacks = { snow_stbi_read, snow_stbi_skip, snow_stbi_eof }; unsigned char *data = stbi_load_from_callbacks(&stbi_snow_callbacks, src, w, h, bpp_source, req_bpp); //we are done with the src snow::io::close(src); snow::log(2, "/ snow / image / w:%d h:%d source bpp:%d bpp:%d\n", *w, *h, *bpp_source, req_bpp); if(data != NULL) { int _w = *w; int _h = *h; int _bpp = *bpp_source; //if a requested bpp was given, override it if(req_bpp != 0) { _bpp = req_bpp; } //actual used bpp *bpp = _bpp; //work out the total length of the output buffer unsigned int length = _w * _h * _bpp; //store it out_buffer.Set(data, length); //clean up used memory stbi_image_free(data); } //data != NULL return true; } //info_from_bytes
TextureResourceData* TextureLoader_stbi(ResourceDataSource &dataSource, Allocator &alloc, bool forceRGBA) { stbi_io_callbacks callbacks; callbacks.read = read; callbacks.skip = skip; callbacks.eof = eof; int x, y, bpp; auto pixels = stbi_load_from_callbacks(&callbacks, &dataSource, &x, &y, &bpp, forceRGBA ? 4 : 0); if (!pixels) { #ifdef STB_DO_ERROR_PRINT DFLOG_WARN(stbi_failure_reason()); #endif return nullptr; } auto fmt = PixelFormat::INVALID; if (bpp == STBI_rgb) { fmt = PixelFormat::RGB; } else if (bpp == STBI_rgb_alpha) { fmt = PixelFormat::RGBA; } else { DFLOG_WARN("Parsed image with an invalid bpp"); stbi_image_free(pixels); return nullptr; } if (forceRGBA) fmt = PixelFormat::RGBA; auto resource = MAKE_NEW(alloc, TextureResourceData); resource->format = fmt; resource->mipLevels.resize(1); resource->mipLevels[0].width = x; resource->mipLevels[0].height = y; int compCount = forceRGBA ? 4 : bpp; resource->mipLevels[0].pixels.resize(compCount * x * y); memcpy(resource->mipLevels[0].pixels.data(), pixels, compCount * x * y); stbi_image_free(pixels); return resource; }
bool ImageLoader::loadImageFromStream(InputStream& stream, std::vector<Uint8>& pixels, Vector2u& size) { // Clear the array (just in case) pixels.clear(); // Make sure that the stream's reading position is at the beginning stream.seek(0); // Setup the stb_image callbacks stbi_io_callbacks callbacks; callbacks.read = &read; callbacks.skip = &skip; callbacks.eof = &eof; // Load the image and get a pointer to the pixels in memory int width = 0; int height = 0; int channels = 0; unsigned char* ptr = stbi_load_from_callbacks(&callbacks, &stream, &width, &height, &channels, STBI_rgb_alpha); if (ptr) { // Assign the image properties size.x = width; size.y = height; if (width && height) { // Copy the loaded pixels to the pixel buffer pixels.resize(width * height * 4); memcpy(&pixels[0], ptr, pixels.size()); } // Free the loaded pixels (they are now in our own pixel buffer) stbi_image_free(ptr); return true; } else { // Error, failed to load the image err() << "Failed to load image from stream. Reason: " << stbi_failure_reason() << std::endl; return false; } }
/* call-seq: load_image(io, required_components = COMPONENTS_DEFAULT) => [data, width, height, components] load_image(io, required_components = COMPONENTS_DEFAULT) { |info| ... } => obj Loads an image using stb_image and returns the resulting data and its width, height, and the number of components per pixel in the data. The returned data is a packed string of unsigned 8-bit integers (8 bits per component). The length of the string will always be width * height * components. In the second form, the info array is yielded to the block if the image is successfully loaded. Otherwise, the method returns nil. This is possibly more convenient than doing an <tt>if info ... end</tt> block to check if the image was successfully loaded. === IO Objects IO objects accepted for loading data with must implement at least IO#read(length) and either IO#eof or IO#eof?. In addition, they may also implement a skip(length) method that skips length bytes and does not return any value. If the IO object does not respond to #skip, #read will be called instead and its result will be discarded. If you want to avoid unnecessary allocations, it may be wise to implement a skip method. === Components If required_components is provided and not the default value, the image data returned will have as many components as are requested. In turn, the number of components returned via the array will be the same as required_components. Valid options for required_components are: [::COMPONENTS_DEFAULT] The default value, loads as many components as are provided by the image. [::COMPONENTS_GREY] Loads only one component. [::COMPONENTS_GREY_ALPHA] Loads two components. [::COMPONENTS_RGB] Loads three components (red, green, and blue). [::COMPONENTS_RGB_ALPHA] Loads four components (red, green, blue, and alpha). === Example open('image.png') { |io| STBI.load_image(io) { |data, width, height, components| format = case components when STBI::COMPONENTS_GREY then Gl::GL_RED when STBI::COMPONENTS_GREY_ALPHA then Gl::GL_RG when STBI_COMPONENTS_RGB then Gl::RGB when STBI_COMPONENTS_RGB_ALPHA then Gl::RGBA end Gl::glTexImage2D(Gl::GL_TEXTURE_2D, 0, format, width, height, 0, format, Gl::GL_UNSIGNED_BYTE, data) } } */ static VALUE sr_load_image(int argc, VALUE *argv, VALUE sr_self) { VALUE sr_callbacks; VALUE sr_req_comp; VALUE sr_image_data = Qnil; int x = 0; int y = 0; int components[2] = { STBI_default, 0 }; rb_scan_args(argc, argv, "11", &sr_callbacks, &sr_req_comp); if (NIL_P(sr_callbacks)) { rb_raise(rb_eArgError, "IO object cannot be nil"); return Qnil; } if (RTEST(sr_req_comp)) { components[0] = FIX2INT(sr_req_comp); } if (!rb_obj_respond_to(sr_callbacks, s_read_funcid, 0) || !(rb_obj_respond_to(sr_callbacks, s_eof_funcid, 0) || rb_obj_respond_to(sr_callbacks, s_eof_qm_funcid, 0))) { rb_raise(rb_eTypeError, "IO object does not respond to either read or eof/eof?"); } stbi_uc *data = stbi_load_from_callbacks(&s_st_callbacks, &sr_callbacks, &x, &y, &components[1], components[0]); if (data) { const long length = x * y * components[!components[0]]; sr_image_data = rb_ary_new3(4, rb_external_str_new((const char *)data, length), INT2FIX(x), INT2FIX(y), INT2FIX(components[!components[0]])); stbi_image_free(data); } if (!NIL_P(sr_image_data) && rb_block_given_p()) { return rb_yield_splat(sr_image_data); } else { return sr_image_data; } }
void Gosu::loadImageFile(Gosu::Bitmap& bitmap, Reader input) { stbi_io_callbacks callbacks; callbacks.read = readCallback; callbacks.skip = skipCallback; callbacks.eof = eofCallback; int x, y, n; stbi_uc* bytes = stbi_load_from_callbacks(&callbacks, &input, &x, &y, &n, STBI_rgb_alpha); if (bytes == 0) { // TODO - stbi_failure_reason is not thread safe. Everything here should be wrapped in a mutex. throw std::runtime_error("Cannot load image: " + std::string(stbi_failure_reason())); } bitmap.resize(x, y); std::memcpy(bitmap.data(), bytes, x * y * sizeof(Gosu::Color)); stbi_image_free(bytes); }
bool ImageLoader::loadImageFromStream(InputStream& stream, std::vector<Uint8>& pixels, unsigned int& width, unsigned int& height) { // Clear the array (just in case) pixels.clear(); // Setup the stb_image callbacks stbi_io_callbacks callbacks; callbacks.read = &read; callbacks.skip = &skip; callbacks.eof = &eof; // Load the image and get a pointer to the pixels in memory int imgWidth, imgHeight, imgChannels; unsigned char* ptr = stbi_load_from_callbacks(&callbacks, &stream, &imgWidth, &imgHeight, &imgChannels, STBI_rgb_alpha); if (ptr && imgWidth && imgHeight) { // Assign the image properties width = imgWidth; height = imgHeight; // Copy the loaded pixels to the pixel buffer pixels.resize(width * height * 4); memcpy(&pixels[0], ptr, pixels.size()); // Free the loaded pixels (they are now in our own pixel buffer) stbi_image_free(ptr); return true; } else { // Error, failed to load the image err() << "Failed to load image from stream. Reason : " << stbi_failure_reason() << std::endl; return false; } }