mirror of https://github.com/mgba-emu/mgba.git
Util: Add image loading API
This commit is contained in:
parent
cdb0c4193b
commit
2cba34d83a
|
@ -90,6 +90,12 @@ struct mImage {
|
|||
enum mColorFormat format;
|
||||
};
|
||||
|
||||
struct VFile;
|
||||
struct mImage* mImageCreate(unsigned width, unsigned height, enum mColorFormat format);
|
||||
struct mImage* mImageLoad(const char* path);
|
||||
struct mImage* mImageLoadVF(struct VFile* vf);
|
||||
void mImageDestroy(struct mImage*);
|
||||
|
||||
uint32_t mImageGetPixel(const struct mImage* image, unsigned x, unsigned y);
|
||||
uint32_t mImageGetPixelRaw(const struct mImage* image, unsigned x, unsigned y);
|
||||
void mImageSetPixel(struct mImage* image, unsigned x, unsigned y, uint32_t color);
|
||||
|
|
|
@ -5,9 +5,108 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba-util/image.h>
|
||||
|
||||
#include <mgba-util/image/png-io.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
#define PIXEL(IM, X, Y) \
|
||||
(void*) (((IM)->stride * (Y) + (X)) * (IM)->depth + (uintptr_t) (IM)->data)
|
||||
|
||||
struct mImage* mImageCreate(unsigned width, unsigned height, enum mColorFormat format) {
|
||||
struct mImage* image = calloc(1, sizeof(struct mImage));
|
||||
if (!image) {
|
||||
return NULL;
|
||||
}
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
image->stride = width;
|
||||
image->format = format;
|
||||
image->depth = mColorFormatBytes(format);
|
||||
image->data = calloc(width * height, image->depth);
|
||||
if (!image->data) {
|
||||
free(image);
|
||||
return NULL;
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
struct mImage* mImageLoad(const char* path) {
|
||||
struct VFile* vf = VFileOpen(path, O_RDONLY);
|
||||
if (!vf) {
|
||||
return NULL;
|
||||
}
|
||||
struct mImage* image = mImageLoadVF(vf);
|
||||
vf->close(vf);
|
||||
return image;
|
||||
}
|
||||
|
||||
static struct mImage* mImageLoadPNG(struct VFile* vf) {
|
||||
png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES);
|
||||
png_infop info = png_create_info_struct(png);
|
||||
png_infop end = png_create_info_struct(png);
|
||||
if (!png || !info || !end) {
|
||||
PNGReadClose(png, info, end);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PNGReadHeader(png, info)) {
|
||||
PNGReadClose(png, info, end);
|
||||
return NULL;
|
||||
}
|
||||
unsigned width = png_get_image_width(png, info);
|
||||
unsigned height = png_get_image_height(png, info);
|
||||
|
||||
struct mImage* image = calloc(1, sizeof(*image));
|
||||
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
image->stride = width;
|
||||
|
||||
switch (png_get_channels(png, info)) {
|
||||
case 3:
|
||||
image->format = mCOLOR_XBGR8;
|
||||
image->depth = 4;
|
||||
image->data = malloc(width * height * 4);
|
||||
if (!PNGReadPixels(png, info, image->data, width, height, width)) {
|
||||
free(image->data);
|
||||
free(image);
|
||||
PNGReadClose(png, info, end);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
image->format = mCOLOR_ABGR8;
|
||||
image->depth = 4;
|
||||
image->data = malloc(width * height * 4);
|
||||
if (!PNGReadPixelsA(png, info, image->data, width, height, width)) {
|
||||
free(image->data);
|
||||
free(image);
|
||||
PNGReadClose(png, info, end);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Not supported yet
|
||||
free(image);
|
||||
PNGReadClose(png, info, end);
|
||||
return NULL;
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
struct mImage* mImageLoadVF(struct VFile* vf) {
|
||||
vf->seek(vf, 0, SEEK_SET);
|
||||
if (isPNG(vf)) {
|
||||
return mImageLoadPNG(vf);
|
||||
}
|
||||
vf->seek(vf, 0, SEEK_SET);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mImageDestroy(struct mImage* image) {
|
||||
free(image->data);
|
||||
free(image);
|
||||
}
|
||||
|
||||
uint32_t mImageGetPixelRaw(const struct mImage* image, unsigned x, unsigned y) {
|
||||
if (x >= image->width || y >= image->height) {
|
||||
return 0;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "util/test/suite.h"
|
||||
|
||||
#include <mgba-util/image.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
M_TEST_DEFINE(pitchRead) {
|
||||
static uint8_t buffer[12] = {
|
||||
|
@ -440,6 +441,65 @@ M_TEST_DEFINE(oobWrite) {
|
|||
assert_memory_equal(buffer, (&(uint8_t[8]) { 0xFF, 0xFF, 0xFF, 0xFF }), sizeof(buffer));
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(loadPng24) {
|
||||
const uint8_t data[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
||||
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
|
||||
0x08, 0x02, 0x00, 0x00, 0x00, 0xfd, 0xd4, 0x9a, 0x73, 0x00, 0x00, 0x00,
|
||||
0x12, 0x49, 0x44, 0x41, 0x54, 0x08, 0x99, 0x63, 0xf8, 0xff, 0xff, 0x3f,
|
||||
0x03, 0x03, 0x03, 0x03, 0x84, 0x00, 0x00, 0x2a, 0xe3, 0x04, 0xfc, 0xe8,
|
||||
0x51, 0xc0, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
|
||||
0x42, 0x60, 0x82
|
||||
};
|
||||
size_t len = 75;
|
||||
|
||||
struct VFile* vf = VFileFromConstMemory(data, len);
|
||||
struct mImage* image = mImageLoadVF(vf);
|
||||
vf->close(vf);
|
||||
|
||||
assert_non_null(image);
|
||||
assert_int_equal(image->width, 2);
|
||||
assert_int_equal(image->height, 2);
|
||||
assert_int_equal(image->format, mCOLOR_XBGR8);
|
||||
|
||||
assert_int_equal(mImageGetPixel(image, 0, 0) & 0xFFFFFF, 0xFFFFFF);
|
||||
assert_int_equal(mImageGetPixel(image, 1, 0) & 0xFFFFFF, 0x000000);
|
||||
assert_int_equal(mImageGetPixel(image, 0, 1) & 0xFFFFFF, 0xFF0000);
|
||||
assert_int_equal(mImageGetPixel(image, 1, 1) & 0xFFFFFF, 0x0000FF);
|
||||
|
||||
mImageDestroy(image);
|
||||
}
|
||||
|
||||
|
||||
M_TEST_DEFINE(loadPng32) {
|
||||
unsigned char data[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
||||
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
|
||||
0x08, 0x06, 0x00, 0x00, 0x00, 0x72, 0xb6, 0x0d, 0x24, 0x00, 0x00, 0x00,
|
||||
0x1a, 0x49, 0x44, 0x41, 0x54, 0x08, 0x99, 0x05, 0xc1, 0x31, 0x01, 0x00,
|
||||
0x00, 0x08, 0xc0, 0x20, 0x6c, 0x66, 0x25, 0xfb, 0x1f, 0x13, 0xa6, 0x0a,
|
||||
0xa7, 0x5a, 0x78, 0x58, 0x7b, 0x07, 0xac, 0xe9, 0x00, 0x3d, 0x95, 0x00,
|
||||
0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
|
||||
};
|
||||
unsigned int len = 83;
|
||||
|
||||
struct VFile* vf = VFileFromConstMemory(data, len);
|
||||
struct mImage* image = mImageLoadVF(vf);
|
||||
vf->close(vf);
|
||||
|
||||
assert_non_null(image);
|
||||
assert_int_equal(image->width, 2);
|
||||
assert_int_equal(image->height, 2);
|
||||
assert_int_equal(image->format, mCOLOR_ABGR8);
|
||||
|
||||
assert_int_equal(mImageGetPixel(image, 0, 0) >> 24, 0xFF);
|
||||
assert_int_equal(mImageGetPixel(image, 1, 0) >> 24, 0x70);
|
||||
assert_int_equal(mImageGetPixel(image, 0, 1) >> 24, 0x40);
|
||||
assert_int_equal(mImageGetPixel(image, 1, 1) >> 24, 0x00);
|
||||
|
||||
mImageDestroy(image);
|
||||
}
|
||||
|
||||
M_TEST_SUITE_DEFINE(Image,
|
||||
cmocka_unit_test(pitchRead),
|
||||
cmocka_unit_test(strideRead),
|
||||
|
@ -447,4 +507,6 @@ M_TEST_SUITE_DEFINE(Image,
|
|||
cmocka_unit_test(pitchWrite),
|
||||
cmocka_unit_test(strideWrite),
|
||||
cmocka_unit_test(oobWrite),
|
||||
cmocka_unit_test(loadPng24),
|
||||
cmocka_unit_test(loadPng32),
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue