322 lines
9.0 KiB
C++
322 lines
9.0 KiB
C++
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "corona.h"
|
|
#include "MemoryFile.h"
|
|
#include "Open.h"
|
|
#include "Save.h"
|
|
#include "SimpleImage.h"
|
|
|
|
|
|
namespace corona {
|
|
namespace hidden {
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
COR_EXPORT(const char*) CorGetVersion() {
|
|
return "1.0.2";
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
class FFDImpl : public FileFormatDesc {
|
|
public:
|
|
FFDImpl(FileFormat format, const char* description, const char* exts) {
|
|
m_format = format;
|
|
m_description = description;
|
|
|
|
const char* ext = exts;
|
|
while (*ext) {
|
|
m_extensions.push_back(ext);
|
|
ext += strlen(ext) + 1;
|
|
}
|
|
}
|
|
|
|
FileFormat getFormat() { return m_format; }
|
|
const char* getDescription() { return m_description.c_str(); }
|
|
size_t getExtensionCount() { return m_extensions.size(); }
|
|
const char* getExtension(size_t i) { return m_extensions[i].c_str(); }
|
|
|
|
private:
|
|
FileFormat m_format;
|
|
std::string m_description;
|
|
std::vector<std::string> m_extensions;
|
|
};
|
|
|
|
FFDImpl ffPNG (FF_PNG, "PNG Files", "png\0");
|
|
FFDImpl ffJPEG(FF_JPEG, "JPEG Files", "jpeg\0jpg\0");
|
|
FFDImpl ffPCX (FF_PCX, "PCX Files", "pcx\0");
|
|
FFDImpl ffBMP (FF_BMP, "BMP Files", "bmp\0");
|
|
FFDImpl ffTGA (FF_TGA, "TGA Files", "tga\0");
|
|
FFDImpl ffGIF (FF_GIF, "GIF Files", "gif\0");
|
|
|
|
const int MAX_FORMAT_COUNT = 64;
|
|
FileFormatDesc** g_read_formats = 0;
|
|
FileFormatDesc** g_write_formats = 0;
|
|
FileFormatDesc* g_read_array[MAX_FORMAT_COUNT + 1] = {0};
|
|
FileFormatDesc* g_write_array[MAX_FORMAT_COUNT + 1] = {0};
|
|
|
|
|
|
COR_EXPORT(FileFormatDesc**) CorGetSupportedReadFormats() {
|
|
if (!g_read_formats) {
|
|
g_read_formats = g_read_array;
|
|
FileFormatDesc** f = g_read_formats;
|
|
*f++ = &ffPNG;
|
|
*f++ = &ffPCX;
|
|
*f++ = &ffBMP;
|
|
*f++ = &ffTGA;
|
|
}
|
|
return g_read_formats;
|
|
}
|
|
|
|
|
|
COR_EXPORT(FileFormatDesc**) CorGetSupportedWriteFormats() {
|
|
if (!g_write_formats) {
|
|
g_write_formats = g_write_array;
|
|
FileFormatDesc** f = g_write_formats;
|
|
*f++ = &ffPNG;
|
|
*f++ = &ffTGA;
|
|
}
|
|
return g_write_formats;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
COR_EXPORT(Image*) CorCreateImage(
|
|
int width,
|
|
int height,
|
|
PixelFormat format)
|
|
{
|
|
return CreateImage(width, height, format, 0);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
COR_EXPORT(Image*) CorCreateImageWithPixels(
|
|
int width,
|
|
int height,
|
|
PixelFormat format,
|
|
void* pixels)
|
|
{
|
|
// this function only supports creation of non-palettized images
|
|
if (!IsDirect(format)) {
|
|
return 0;
|
|
}
|
|
|
|
int size = width * height * GetPixelSize(format);
|
|
byte* p = new byte[size];
|
|
if (pixels) {
|
|
memcpy(p, pixels, size);
|
|
} else {
|
|
memset(p, 0, size);
|
|
}
|
|
return new SimpleImage(width, height, format, p);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
COR_EXPORT(Image*) CorCreatePalettizedImage(
|
|
int width,
|
|
int height,
|
|
PixelFormat format,
|
|
int palette_size,
|
|
PixelFormat palette_format)
|
|
{
|
|
// only support creation of palettized images
|
|
if (!IsPalettized(format) || !IsDirect(palette_format)) {
|
|
return 0;
|
|
}
|
|
|
|
// make sure the palette is the right size
|
|
if (palette_size != GetPaletteSize(format)) {
|
|
return 0;
|
|
}
|
|
|
|
int size = width * height * GetPixelSize(format);
|
|
byte* pixels = new byte[size];
|
|
memset(pixels, 0, size);
|
|
|
|
int palette_bytes = palette_size * GetPixelSize(palette_format);
|
|
byte* palette = new byte[palette_bytes];
|
|
memset(palette, 0, palette_bytes);
|
|
|
|
return new SimpleImage(width, height, format, pixels,
|
|
palette, palette_size, palette_format);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
COR_EXPORT(Image*) CorCloneImage(
|
|
Image* source,
|
|
PixelFormat format)
|
|
{
|
|
if (!source) {
|
|
// we need an image to clone :)
|
|
return 0;
|
|
}
|
|
|
|
const int width = source->getWidth();
|
|
const int height = source->getHeight();
|
|
const PixelFormat source_format = source->getFormat();
|
|
|
|
const int source_pixel_size = GetPixelSize(source_format);
|
|
if (source_pixel_size == 0) {
|
|
// unknown pixel size?
|
|
return 0;
|
|
}
|
|
|
|
// duplicate the image
|
|
int image_size = width * height * source_pixel_size;
|
|
byte* pixels = new byte[image_size];
|
|
memcpy(pixels, source->getPixels(), image_size);
|
|
|
|
if (IsPalettized(source_format)) {
|
|
// clone palette
|
|
int palette_size = source->getPaletteSize();
|
|
PixelFormat palette_format = source->getPaletteFormat();
|
|
int palette_bytes = palette_size * GetPixelSize(palette_format);
|
|
byte* palette = new byte[palette_bytes];
|
|
memcpy(palette, source->getPalette(), palette_bytes);
|
|
Image* image = new SimpleImage(width, height, source_format, pixels,
|
|
palette, palette_size, palette_format);
|
|
return ConvertImage(image, format);
|
|
}
|
|
|
|
Image* image = new SimpleImage(width, height, source_format, pixels);
|
|
return ConvertImage(image, format);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
COR_EXPORT(Image*) CorOpenImage(
|
|
const char* filename,
|
|
FileFormat file_format)
|
|
{
|
|
if (!filename) {
|
|
return 0;
|
|
}
|
|
|
|
std::auto_ptr<File> file(OpenFile(filename, false));
|
|
return CorOpenImageFromFile(file.get(), file_format);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
COR_EXPORT(Image*) CorOpenImageFromFile(
|
|
File* file,
|
|
FileFormat file_format)
|
|
{
|
|
if (!file) {
|
|
return 0;
|
|
}
|
|
|
|
#define TRY_TYPE(type) \
|
|
{ \
|
|
Image* image = CorOpenImageFromFile(file, (type)); \
|
|
if (image) { return image; } \
|
|
}
|
|
|
|
file->seek(0, File::BEGIN);
|
|
switch (file_format) {
|
|
case FF_AUTODETECT: {
|
|
TRY_TYPE(FF_PNG);
|
|
TRY_TYPE(FF_PCX);
|
|
TRY_TYPE(FF_BMP);
|
|
TRY_TYPE(FF_TGA);
|
|
return 0;
|
|
}
|
|
|
|
case FF_PNG: return OpenPNG(file);
|
|
case FF_PCX: return OpenPCX(file);
|
|
case FF_BMP: return OpenBMP(file);
|
|
case FF_TGA: return OpenTGA(file);
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
int strcmp_ci(const char* a, const char* b) {
|
|
while (*a && *b) {
|
|
const int diff = tolower(*a) - tolower(*b);
|
|
if (diff != 0) {
|
|
return diff;
|
|
}
|
|
++a;
|
|
++b;
|
|
}
|
|
return tolower(*a) - tolower(*b);
|
|
}
|
|
|
|
bool ends_with(const char* str, const char* ext) {
|
|
const int str_len = strlen(str);
|
|
const int ext_len = strlen(ext);
|
|
return (str_len >= ext_len &&
|
|
strcmp_ci(str + str_len - ext_len, ext) == 0);
|
|
}
|
|
|
|
COR_EXPORT(bool) CorSaveImage(
|
|
const char* filename,
|
|
FileFormat file_format,
|
|
Image* image)
|
|
{
|
|
if (!filename) {
|
|
return false;
|
|
}
|
|
|
|
if (file_format == FF_AUTODETECT) {
|
|
if (ends_with(filename, ".png")) {
|
|
file_format = FF_PNG;
|
|
} else if (ends_with(filename, ".tga")) {
|
|
file_format = FF_TGA;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::auto_ptr<File> file(OpenFile(filename, true));
|
|
return CorSaveImageToFile(file.get(), file_format, image);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
COR_EXPORT(bool) CorSaveImageToFile(
|
|
File* file,
|
|
FileFormat file_format,
|
|
Image* image)
|
|
{
|
|
if (!file || !image) {
|
|
return false;
|
|
}
|
|
|
|
switch (file_format) {
|
|
case FF_PNG: return SavePNG(file, image);
|
|
case FF_JPEG: return false;
|
|
case FF_PCX: return false;
|
|
case FF_BMP: return false;
|
|
case FF_TGA: return SaveTGA(file, image);
|
|
case FF_GIF: return false;
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
COR_EXPORT(int) CorGetPixelSize(PixelFormat format) {
|
|
switch (format) {
|
|
case PF_R8G8B8A8: return 4;
|
|
case PF_R8G8B8: return 3;
|
|
case PF_B8G8R8A8: return 4;
|
|
case PF_B8G8R8: return 3;
|
|
case PF_I8: return 1;
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
}
|
|
}
|