126 lines
2.6 KiB
C++
126 lines
2.6 KiB
C++
|
|
#include <Spectre/System/File.h>
|
|
#include <Spectre/System/Path.h>
|
|
#include <Spectre/System/Log.h>
|
|
#include <Spectre/Graphics/Image.h>
|
|
#include "ImageLoader.h"
|
|
|
|
#include "Image/IcoFormat.h"
|
|
|
|
// Disable some file formats that we don't use.
|
|
#define STBI_NO_PSD
|
|
#define STBI_NO_PIC
|
|
#define STBI_NO_GIF
|
|
#define STBI_NO_HDR
|
|
#define STBI_NO_PNM
|
|
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#include "stb_image.h"
|
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
|
#include "stb_image_write.h"
|
|
|
|
#include <cstring>
|
|
#include <cstdlib>
|
|
#include <vector>
|
|
|
|
namespace sp {
|
|
|
|
bool ImageLoader::loadFromFile(const char *filename, Image& img)
|
|
{
|
|
File file(filename);
|
|
|
|
if (file.isOpen()) {
|
|
std::vector<unsigned char> buf;
|
|
file.read(buf);
|
|
|
|
if (loadFromMemory(&buf[0], buf.size(), img) == false) {
|
|
Log::warn("ImageLoader: could not load file '%s'. Reason: %s",
|
|
filename, m_error);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Log::warn("ImageLoader: could not open file '%s'. Reason: %s",
|
|
filename, file.getErrorMessage().c_str());
|
|
return false;
|
|
}
|
|
|
|
bool ImageLoader::loadFromMemory(const void *data, unsigned size, Image& img)
|
|
{
|
|
// width, height, num components.
|
|
int w, h, n_comp;
|
|
const stbi_uc *ptr = (const stbi_uc *) data;
|
|
|
|
if (ptr[0] == 0x0) {
|
|
image::IcoFormat ico;
|
|
return ico.decode(img, ptr, size);
|
|
}
|
|
|
|
unsigned char *pixels = stbi_load_from_memory(ptr, size, &w, &h, &n_comp, 4);
|
|
|
|
if (pixels) {
|
|
|
|
unsigned int len = w * h * 4;
|
|
|
|
img.create(w, h, pixels);
|
|
|
|
stbi_image_free(pixels);
|
|
|
|
return true;
|
|
}
|
|
|
|
m_error = stbi_failure_reason();
|
|
return false;
|
|
}
|
|
|
|
// TODO: Support more formats.
|
|
bool ImageLoader::saveToFile(const Image& img, const char *filename)
|
|
{
|
|
std::string ext = Path::getExtension(filename);
|
|
std::vector<unsigned char> encoded_data;
|
|
|
|
if (ext == "png") {
|
|
|
|
if (!encodePNG(img, encoded_data)) {
|
|
Log::warn("ImageLoader: failed to save file '%s'. Reason: %s",
|
|
filename, m_error);
|
|
}
|
|
|
|
} else {
|
|
Log::warn("ImageLoader: Invalid file format");
|
|
return false;
|
|
}
|
|
|
|
if (encoded_data.size() > 0) {
|
|
|
|
File file(filename, File::Access::WRITE);
|
|
if (file.isOpen()) {
|
|
file.write(encoded_data);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ImageLoader::encodePNG(const Image& img, std::vector<unsigned char>& data)
|
|
{
|
|
int buf_len;
|
|
unsigned char *raw = (unsigned char*) img.getPixels();
|
|
unsigned char *buf;
|
|
|
|
buf = stbi_write_png_to_mem(raw, img.getStride(), img.getWidth(), img.getHeight(), img.getBpp() / 8, &buf_len);
|
|
if (buf && buf_len > 0) {
|
|
|
|
data.resize(buf_len);
|
|
memcpy(&data[0], buf, buf_len);
|
|
STBIW_FREE(buf);
|
|
|
|
return true;
|
|
}
|
|
m_error = stbi_failure_reason();
|
|
return false;
|
|
}
|
|
|
|
} // namespace sp
|