mirror of
https://github.com/SFML/SFML.git
synced 2024-11-28 22:31:09 +08:00
Manually inline all of sf::priv::ImageLoader
This layer of indirection was unnecessary. All of its functions were only used once somewhere inside of Image.cpp. The code is shorter and simpler and easier to reason about if we put the implementations of these functions directly in Image.cpp.
This commit is contained in:
parent
13dd9f59cf
commit
5d0996906b
@ -21,8 +21,6 @@ set(SRC
|
||||
${SRCROOT}/GLExtensions.cpp
|
||||
${SRCROOT}/Image.cpp
|
||||
${INCROOT}/Image.hpp
|
||||
${SRCROOT}/ImageLoader.cpp
|
||||
${SRCROOT}/ImageLoader.hpp
|
||||
${INCROOT}/PrimitiveType.hpp
|
||||
${INCROOT}/Rect.hpp
|
||||
${INCROOT}/Rect.inl
|
||||
@ -134,8 +132,8 @@ endif()
|
||||
# add preprocessor symbols
|
||||
target_compile_definitions(sfml-graphics PRIVATE "STBI_FAILURE_USERMSG")
|
||||
|
||||
# ImageLoader.cpp must be compiled with the -fno-strict-aliasing
|
||||
# Image.cpp must be compiled with the -fno-strict-aliasing
|
||||
# when gcc is used; otherwise saving PNGs may crash in stb_image_write
|
||||
if(SFML_COMPILER_GCC)
|
||||
set_source_files_properties(${SRCROOT}/ImageLoader.cpp PROPERTIES COMPILE_FLAGS -fno-strict-aliasing)
|
||||
set_source_files_properties(${SRCROOT}/Image.cpp PROPERTIES COMPILE_FLAGS -fno-strict-aliasing)
|
||||
endif()
|
||||
|
@ -26,12 +26,19 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Graphics/ImageLoader.hpp>
|
||||
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/System/InputStream.hpp>
|
||||
#include <SFML/System/Utils.hpp>
|
||||
#ifdef SFML_SYSTEM_ANDROID
|
||||
#include <SFML/System/Android/ResourceStream.hpp>
|
||||
#endif
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb_image_write.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
|
||||
@ -39,6 +46,38 @@
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// stb_image callbacks that operate on a sf::InputStream
|
||||
int read(void* user, char* data, int size)
|
||||
{
|
||||
auto& stream = *static_cast<sf::InputStream*>(user);
|
||||
return static_cast<int>(stream.read(data, size));
|
||||
}
|
||||
|
||||
void skip(void* user, int size)
|
||||
{
|
||||
auto& stream = *static_cast<sf::InputStream*>(user);
|
||||
if (stream.seek(stream.tell() + size) == -1)
|
||||
sf::err() << "Failed to seek image loader input stream" << std::endl;
|
||||
}
|
||||
|
||||
int eof(void* user)
|
||||
{
|
||||
auto& stream = *static_cast<sf::InputStream*>(user);
|
||||
return stream.tell() >= stream.getSize();
|
||||
}
|
||||
|
||||
// stb_image callback for constructing a buffer
|
||||
void bufferFromCallback(void* context, void* data, int size)
|
||||
{
|
||||
const auto* source = static_cast<std::uint8_t*>(data);
|
||||
auto* dest = static_cast<std::vector<std::uint8_t>*>(context);
|
||||
std::copy(source, source + size, std::back_inserter(*dest));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -109,7 +148,36 @@ bool Image::loadFromFile(const std::filesystem::path& filename)
|
||||
{
|
||||
#ifndef SFML_SYSTEM_ANDROID
|
||||
|
||||
return priv::ImageLoader::getInstance().loadImageFromFile(filename, m_pixels, m_size);
|
||||
// Clear the array (just in case)
|
||||
m_pixels.clear();
|
||||
|
||||
// Load the image and get a pointer to the pixels in memory
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int channels = 0;
|
||||
auto* ptr = stbi_load(filename.string().c_str(), &width, &height, &channels, STBI_rgb_alpha);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
// Assign the image properties
|
||||
m_size = Vector2u(Vector2i(width, height));
|
||||
|
||||
// Copy the loaded pixels to the pixel buffer
|
||||
m_pixels.assign(ptr, ptr + width * height * 4);
|
||||
|
||||
// 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\n"
|
||||
<< formatDebugPathInfo(filename) << "\nReason: " << stbi_failure_reason() << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@ -123,27 +191,182 @@ bool Image::loadFromFile(const std::filesystem::path& filename)
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::loadFromMemory(const void* data, std::size_t size)
|
||||
{
|
||||
return priv::ImageLoader::getInstance().loadImageFromMemory(data, size, m_pixels, m_size);
|
||||
// Check input parameters
|
||||
if (data && size)
|
||||
{
|
||||
// Clear the array (just in case)
|
||||
m_pixels.clear();
|
||||
|
||||
// Load the image and get a pointer to the pixels in memory
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int channels = 0;
|
||||
const auto* buffer = static_cast<const unsigned char*>(data);
|
||||
auto* ptr = stbi_load_from_memory(buffer, static_cast<int>(size), &width, &height, &channels, STBI_rgb_alpha);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
// Assign the image properties
|
||||
m_size = Vector2u(Vector2i(width, height));
|
||||
|
||||
// Copy the loaded pixels to the pixel buffer
|
||||
m_pixels.assign(ptr, ptr + width * height * 4);
|
||||
|
||||
// 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 memory. Reason: " << stbi_failure_reason() << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Failed to load image from memory, no data provided" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::loadFromStream(InputStream& stream)
|
||||
{
|
||||
return priv::ImageLoader::getInstance().loadImageFromStream(stream, m_pixels, m_size);
|
||||
// Clear the array (just in case)
|
||||
m_pixels.clear();
|
||||
|
||||
// Make sure that the stream's reading position is at the beginning
|
||||
if (stream.seek(0) == -1)
|
||||
{
|
||||
err() << "Failed to seek image stream" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
auto* ptr = stbi_load_from_callbacks(&callbacks, &stream, &width, &height, &channels, STBI_rgb_alpha);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
// Assign the image properties
|
||||
m_size = Vector2u(Vector2i(width, height));
|
||||
|
||||
// Copy the loaded pixels to the pixel buffer
|
||||
m_pixels.assign(ptr, ptr + width * height * 4);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::saveToFile(const std::filesystem::path& filename) const
|
||||
{
|
||||
return priv::ImageLoader::getInstance().saveImageToFile(filename, m_pixels, m_size);
|
||||
// Make sure the image is not empty
|
||||
if (!m_pixels.empty() && m_size.x > 0 && m_size.y > 0)
|
||||
{
|
||||
// Deduce the image type from its extension
|
||||
|
||||
// Extract the extension
|
||||
const std::filesystem::path extension = filename.extension();
|
||||
const Vector2i convertedSize = Vector2i(m_size);
|
||||
|
||||
if (extension == ".bmp")
|
||||
{
|
||||
// BMP format
|
||||
if (stbi_write_bmp(filename.string().c_str(), convertedSize.x, convertedSize.y, 4, m_pixels.data()))
|
||||
return true;
|
||||
}
|
||||
else if (extension == ".tga")
|
||||
{
|
||||
// TGA format
|
||||
if (stbi_write_tga(filename.string().c_str(), convertedSize.x, convertedSize.y, 4, m_pixels.data()))
|
||||
return true;
|
||||
}
|
||||
else if (extension == ".png")
|
||||
{
|
||||
// PNG format
|
||||
if (stbi_write_png(filename.string().c_str(), convertedSize.x, convertedSize.y, 4, m_pixels.data(), 0))
|
||||
return true;
|
||||
}
|
||||
else if (extension == ".jpg" || extension == ".jpeg")
|
||||
{
|
||||
// JPG format
|
||||
if (stbi_write_jpg(filename.string().c_str(), convertedSize.x, convertedSize.y, 4, m_pixels.data(), 90))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Image file extension " << extension << " not supported\n";
|
||||
}
|
||||
}
|
||||
|
||||
err() << "Failed to save image\n" << formatDebugPathInfo(filename) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
std::optional<std::vector<std::uint8_t>> Image::saveToMemory(std::string_view format) const
|
||||
{
|
||||
return priv::ImageLoader::getInstance().saveImageToMemory(std::string(format), m_pixels, m_size);
|
||||
// Make sure the image is not empty
|
||||
if (!m_pixels.empty() && m_size.x > 0 && m_size.y > 0)
|
||||
{
|
||||
// Choose function based on format
|
||||
const std::string specified = toLower(std::string(format));
|
||||
const Vector2i convertedSize = Vector2i(m_size);
|
||||
|
||||
std::vector<std::uint8_t> buffer;
|
||||
|
||||
if (specified == "bmp")
|
||||
{
|
||||
// BMP format
|
||||
if (stbi_write_bmp_to_func(bufferFromCallback, &buffer, convertedSize.x, convertedSize.y, 4, m_pixels.data()))
|
||||
return buffer;
|
||||
}
|
||||
else if (specified == "tga")
|
||||
{
|
||||
// TGA format
|
||||
if (stbi_write_tga_to_func(bufferFromCallback, &buffer, convertedSize.x, convertedSize.y, 4, m_pixels.data()))
|
||||
return buffer;
|
||||
}
|
||||
else if (specified == "png")
|
||||
{
|
||||
// PNG format
|
||||
if (stbi_write_png_to_func(bufferFromCallback, &buffer, convertedSize.x, convertedSize.y, 4, m_pixels.data(), 0))
|
||||
return buffer;
|
||||
}
|
||||
else if (specified == "jpg" || specified == "jpeg")
|
||||
{
|
||||
// JPG format
|
||||
if (stbi_write_jpg_to_func(bufferFromCallback, &buffer, convertedSize.x, convertedSize.y, 4, m_pixels.data(), 90))
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
err() << "Failed to save image with format " << std::quoted(format) << std::endl;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,328 +0,0 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2023 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/ImageLoader.hpp>
|
||||
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/System/InputStream.hpp>
|
||||
#include <SFML/System/Utils.hpp>
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb_image_write.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <iomanip>
|
||||
#include <iterator>
|
||||
#include <ostream>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// stb_image callbacks that operate on a sf::InputStream
|
||||
int read(void* user, char* data, int size)
|
||||
{
|
||||
auto* stream = static_cast<sf::InputStream*>(user);
|
||||
return static_cast<int>(stream->read(data, size));
|
||||
}
|
||||
void skip(void* user, int size)
|
||||
{
|
||||
auto* stream = static_cast<sf::InputStream*>(user);
|
||||
|
||||
if (stream->seek(stream->tell() + size) == -1)
|
||||
sf::err() << "Failed to seek image loader input stream" << std::endl;
|
||||
}
|
||||
int eof(void* user)
|
||||
{
|
||||
auto* stream = static_cast<sf::InputStream*>(user);
|
||||
return stream->tell() >= stream->getSize();
|
||||
}
|
||||
|
||||
// stb_image callback for constructing a buffer
|
||||
void bufferFromCallback(void* context, void* data, int size)
|
||||
{
|
||||
auto* source = static_cast<std::uint8_t*>(data);
|
||||
auto* dest = static_cast<std::vector<std::uint8_t>*>(context);
|
||||
std::copy(source, source + size, std::back_inserter(*dest));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
ImageLoader& ImageLoader::getInstance()
|
||||
{
|
||||
static ImageLoader instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
ImageLoader::ImageLoader() = default;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ImageLoader::loadImageFromFile(const std::filesystem::path& filename, std::vector<std::uint8_t>& pixels, Vector2u& size)
|
||||
{
|
||||
// Clear the array (just in case)
|
||||
pixels.clear();
|
||||
|
||||
// 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(filename.string().c_str(), &width, &height, &channels, STBI_rgb_alpha);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
// Assign the image properties
|
||||
size.x = static_cast<unsigned int>(width);
|
||||
size.y = static_cast<unsigned int>(height);
|
||||
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
// Copy the loaded pixels to the pixel buffer
|
||||
pixels.resize(static_cast<std::size_t>(width * height * 4));
|
||||
std::memcpy(pixels.data(), 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\n"
|
||||
<< formatDebugPathInfo(filename) << "\nReason: " << stbi_failure_reason() << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ImageLoader::loadImageFromMemory(const void* data, std::size_t dataSize, std::vector<std::uint8_t>& pixels, Vector2u& size)
|
||||
{
|
||||
// Check input parameters
|
||||
if (data && dataSize)
|
||||
{
|
||||
// Clear the array (just in case)
|
||||
pixels.clear();
|
||||
|
||||
// Load the image and get a pointer to the pixels in memory
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int channels = 0;
|
||||
const auto* buffer = static_cast<const unsigned char*>(data);
|
||||
unsigned char* ptr = stbi_load_from_memory(buffer, static_cast<int>(dataSize), &width, &height, &channels, STBI_rgb_alpha);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
// Assign the image properties
|
||||
size.x = static_cast<unsigned int>(width);
|
||||
size.y = static_cast<unsigned int>(height);
|
||||
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
// Copy the loaded pixels to the pixel buffer
|
||||
pixels.resize(static_cast<std::size_t>(width * height * 4));
|
||||
std::memcpy(pixels.data(), 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 memory. Reason: " << stbi_failure_reason() << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Failed to load image from memory, no data provided" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ImageLoader::loadImageFromStream(InputStream& stream, std::vector<std::uint8_t>& pixels, Vector2u& size)
|
||||
{
|
||||
// Clear the array (just in case)
|
||||
pixels.clear();
|
||||
|
||||
// Make sure that the stream's reading position is at the beginning
|
||||
if (stream.seek(0) == -1)
|
||||
{
|
||||
err() << "Failed to seek image stream" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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 = static_cast<unsigned int>(width);
|
||||
size.y = static_cast<unsigned int>(height);
|
||||
|
||||
if (width && height)
|
||||
{
|
||||
// Copy the loaded pixels to the pixel buffer
|
||||
pixels.resize(static_cast<std::size_t>(width * height * 4));
|
||||
std::memcpy(pixels.data(), 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ImageLoader::saveImageToFile(const std::filesystem::path& filename,
|
||||
const std::vector<std::uint8_t>& pixels,
|
||||
const Vector2u& size)
|
||||
{
|
||||
// Make sure the image is not empty
|
||||
if (!pixels.empty() && (size.x > 0) && (size.y > 0))
|
||||
{
|
||||
// Deduce the image type from its extension
|
||||
|
||||
// Extract the extension
|
||||
const std::filesystem::path extension = filename.extension();
|
||||
const Vector2i convertedSize = Vector2i(size);
|
||||
|
||||
if (extension == ".bmp")
|
||||
{
|
||||
// BMP format
|
||||
if (stbi_write_bmp(filename.string().c_str(), convertedSize.x, convertedSize.y, 4, pixels.data()))
|
||||
return true;
|
||||
}
|
||||
else if (extension == ".tga")
|
||||
{
|
||||
// TGA format
|
||||
if (stbi_write_tga(filename.string().c_str(), convertedSize.x, convertedSize.y, 4, pixels.data()))
|
||||
return true;
|
||||
}
|
||||
else if (extension == ".png")
|
||||
{
|
||||
// PNG format
|
||||
if (stbi_write_png(filename.string().c_str(), convertedSize.x, convertedSize.y, 4, pixels.data(), 0))
|
||||
return true;
|
||||
}
|
||||
else if (extension == ".jpg" || extension == ".jpeg")
|
||||
{
|
||||
// JPG format
|
||||
if (stbi_write_jpg(filename.string().c_str(), convertedSize.x, convertedSize.y, 4, pixels.data(), 90))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Image file extension " << extension << " not supported\n";
|
||||
}
|
||||
}
|
||||
|
||||
err() << "Failed to save image\n" << formatDebugPathInfo(filename) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
std::optional<std::vector<std::uint8_t>> ImageLoader::saveImageToMemory(const std::string& format,
|
||||
const std::vector<std::uint8_t>& pixels,
|
||||
const Vector2u& size)
|
||||
{
|
||||
// Make sure the image is not empty
|
||||
if (!pixels.empty() && (size.x > 0) && (size.y > 0))
|
||||
{
|
||||
// Choose function based on format
|
||||
const std::string specified = toLower(format);
|
||||
const Vector2i convertedSize = Vector2i(size);
|
||||
|
||||
std::vector<std::uint8_t> buffer;
|
||||
|
||||
if (specified == "bmp")
|
||||
{
|
||||
// BMP format
|
||||
if (stbi_write_bmp_to_func(bufferFromCallback, &buffer, convertedSize.x, convertedSize.y, 4, pixels.data()))
|
||||
return buffer;
|
||||
}
|
||||
else if (specified == "tga")
|
||||
{
|
||||
// TGA format
|
||||
if (stbi_write_tga_to_func(&bufferFromCallback, &buffer, convertedSize.x, convertedSize.y, 4, pixels.data()))
|
||||
return buffer;
|
||||
}
|
||||
else if (specified == "png")
|
||||
{
|
||||
// PNG format
|
||||
if (stbi_write_png_to_func(&bufferFromCallback, &buffer, convertedSize.x, convertedSize.y, 4, pixels.data(), 0))
|
||||
return buffer;
|
||||
}
|
||||
else if (specified == "jpg" || specified == "jpeg")
|
||||
{
|
||||
// JPG format
|
||||
if (stbi_write_jpg_to_func(&bufferFromCallback, &buffer, convertedSize.x, convertedSize.y, 4, pixels.data(), 90))
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
err() << "Failed to save image with format " << std::quoted(format) << std::endl;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace sf::priv
|
@ -1,146 +0,0 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2023 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Config.hpp>
|
||||
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class InputStream;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load/save image files
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class ImageLoader
|
||||
{
|
||||
public:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Deleted copy constructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
ImageLoader(const ImageLoader&) = delete;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Deleted copy assignment
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
ImageLoader& operator=(const ImageLoader&) = delete;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the unique instance of the class
|
||||
///
|
||||
/// \return Reference to the ImageLoader instance
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static ImageLoader& getInstance();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load an image from a file on disk
|
||||
///
|
||||
/// \param filename Path of image file to load
|
||||
/// \param pixels Array of pixels to fill with loaded image
|
||||
/// \param size Size of loaded image, in pixels
|
||||
///
|
||||
/// \return True if loading was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool loadImageFromFile(const std::filesystem::path& filename, std::vector<std::uint8_t>& pixels, Vector2u& size);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load an image from a file in memory
|
||||
///
|
||||
/// \param data Pointer to the file data in memory
|
||||
/// \param dataSize Size of the data to load, in bytes
|
||||
/// \param pixels Array of pixels to fill with loaded image
|
||||
/// \param size Size of loaded image, in pixels
|
||||
///
|
||||
/// \return True if loading was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool loadImageFromMemory(const void* data, std::size_t dataSize, std::vector<std::uint8_t>& pixels, Vector2u& size);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load an image from a custom stream
|
||||
///
|
||||
/// \param stream Source stream to read from
|
||||
/// \param pixels Array of pixels to fill with loaded image
|
||||
/// \param size Size of loaded image, in pixels
|
||||
///
|
||||
/// \return True if loading was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool loadImageFromStream(InputStream& stream, std::vector<std::uint8_t>& pixels, Vector2u& size);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Save an array of pixels as an image file
|
||||
///
|
||||
/// \param filename Path of image file to save
|
||||
/// \param pixels Array of pixels to save to image
|
||||
/// \param size Size of image to save, in pixels
|
||||
///
|
||||
/// \return True if saving was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool saveImageToFile(const std::filesystem::path& filename, const std::vector<std::uint8_t>& pixels, const Vector2u& size);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Save an array of pixels as an encoded image buffer
|
||||
///
|
||||
/// \param format Must be "bmp", "png", "tga" or "jpg"/"jpeg".
|
||||
/// \param pixels Array of pixels to save to image
|
||||
/// \param size Size of image to save, in pixels
|
||||
///
|
||||
/// \return Buffer with encoded data if saving was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
std::optional<std::vector<std::uint8_t>> saveImageToMemory(const std::string& format,
|
||||
const std::vector<std::uint8_t>& pixels,
|
||||
const Vector2u& size);
|
||||
|
||||
private:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
ImageLoader();
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
Loading…
Reference in New Issue
Block a user