Util: PNGWrite*A is dead, long live PNGWrite*

This commit is contained in:
Vicki Pfau 2023-04-17 02:03:15 -07:00
parent 225456a39c
commit 65f04ee408
9 changed files with 412 additions and 110 deletions

View File

@ -81,6 +81,14 @@ enum mColorFormat {
mCOLOR_ANY = -1 mCOLOR_ANY = -1
}; };
#ifndef COLOR_16_BIT
#define mCOLOR_NATIVE mCOLOR_XBGR8
#elif !defined(COLOR_5_6_5)
#define mCOLOR_NATIVE mCOLOR_BGR5
#else
#define mCOLOR_NATIVE mCOLOR_RGB565
#endif
struct mImage { struct mImage {
void* data; void* data;
unsigned width; unsigned width;

View File

@ -12,6 +12,8 @@ CXX_GUARD_START
#ifdef USE_PNG #ifdef USE_PNG
#include <mgba-util/image.h>
// png.h defines its own version of restrict which conflicts with mGBA's. // png.h defines its own version of restrict which conflicts with mGBA's.
#ifdef restrict #ifdef restrict
#undef restrict #undef restrict
@ -25,12 +27,10 @@ enum {
}; };
png_structp PNGWriteOpen(struct VFile* source); png_structp PNGWriteOpen(struct VFile* source);
png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height); png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height, enum mColorFormat);
png_infop PNGWriteHeaderA(png_structp png, unsigned width, unsigned height);
png_infop PNGWriteHeader8(png_structp png, unsigned width, unsigned height); png_infop PNGWriteHeader8(png_structp png, unsigned width, unsigned height);
bool PNGWritePalette(png_structp png, png_infop info, const uint32_t* palette, unsigned entries); bool PNGWritePalette(png_structp png, png_infop info, const uint32_t* palette, unsigned entries);
bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels); bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels, enum mColorFormat);
bool PNGWritePixelsA(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels);
bool PNGWritePixels8(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels); bool PNGWritePixels8(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels);
bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data); bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data);
void PNGWriteClose(png_structp png, png_infop info); void PNGWriteClose(png_structp png, png_infop info);

View File

@ -364,8 +364,8 @@ bool mCoreTakeScreenshotVF(struct mCore* core, struct VFile* vf) {
core->currentVideoSize(core, &width, &height); core->currentVideoSize(core, &width, &height);
core->getPixels(core, &pixels, &stride); core->getPixels(core, &pixels, &stride);
png_structp png = PNGWriteOpen(vf); png_structp png = PNGWriteOpen(vf);
png_infop info = PNGWriteHeader(png, width, height); png_infop info = PNGWriteHeader(png, width, height, mCOLOR_NATIVE);
bool success = PNGWritePixels(png, width, height, stride, pixels); bool success = PNGWritePixels(png, width, height, stride, pixels, mCOLOR_NATIVE);
PNGWriteClose(png, info); PNGWriteClose(png, info);
return success; return success;
#else #else

View File

@ -178,13 +178,13 @@ static bool _savePNGState(struct mCore* core, struct VFile* vf, struct mStateExt
unsigned width, height; unsigned width, height;
core->currentVideoSize(core, &width, &height); core->currentVideoSize(core, &width, &height);
png_structp png = PNGWriteOpen(vf); png_structp png = PNGWriteOpen(vf);
png_infop info = PNGWriteHeader(png, width, height); png_infop info = PNGWriteHeader(png, width, height, mCOLOR_NATIVE);
if (!png || !info) { if (!png || !info) {
PNGWriteClose(png, info); PNGWriteClose(png, info);
free(buffer); free(buffer);
return false; return false;
} }
PNGWritePixels(png, width, height, stride, pixels); PNGWritePixels(png, width, height, stride, pixels, mCOLOR_NATIVE);
PNGWriteCustomChunk(png, "gbAs", len, buffer); PNGWriteCustomChunk(png, "gbAs", len, buffer);
if (extdata) { if (extdata) {
uint32_t i; uint32_t i;

View File

@ -21,18 +21,18 @@ class PNG:
def write_header(self, image): def write_header(self, image):
self._png = lib.PNGWriteOpen(self._vfile.handle) self._png = lib.PNGWriteOpen(self._vfile.handle)
if self.mode == MODE_RGB: if self.mode == MODE_RGB:
self._info = lib.PNGWriteHeader(self._png, image.width, image.height) self._info = lib.PNGWriteHeader(self._png, image.width, image.height, lib.mCOLOR_XBGR8)
if self.mode == MODE_RGBA: if self.mode == MODE_RGBA:
self._info = lib.PNGWriteHeaderA(self._png, image.width, image.height) self._info = lib.PNGWriteHeader(self._png, image.width, image.height, lib.mCOLOR_ABGR8)
if self.mode == MODE_INDEX: if self.mode == MODE_INDEX:
self._info = lib.PNGWriteHeader8(self._png, image.width, image.height) self._info = lib.PNGWriteHeader8(self._png, image.width, image.height)
return self._info != ffi.NULL return self._info != ffi.NULL
def write_pixels(self, image): def write_pixels(self, image):
if self.mode == MODE_RGB: if self.mode == MODE_RGB:
return lib.PNGWritePixels(self._png, image.width, image.height, image.stride, image.buffer) return lib.PNGWritePixels(self._png, image.width, image.height, image.stride, image.buffer, lib.mCOLOR_XBGR8)
if self.mode == MODE_RGBA: if self.mode == MODE_RGBA:
return lib.PNGWritePixelsA(self._png, image.width, image.height, image.stride, image.buffer) return lib.PNGWritePixels(self._png, image.width, image.height, image.stride, image.buffer, lib.mCOLOR_ABGR8)
if self.mode == MODE_INDEX: if self.mode == MODE_INDEX:
return lib.PNGWritePixels8(self._png, image.width, image.height, image.stride, image.buffer) return lib.PNGWritePixels8(self._png, image.width, image.height, image.stride, image.buffer)
return False return False

View File

@ -731,8 +731,8 @@ static struct VDir* _makeOutDir(const char* testName) {
static void _writeImage(struct VFile* vf, const struct CInemaImage* image) { static void _writeImage(struct VFile* vf, const struct CInemaImage* image) {
png_structp png = PNGWriteOpen(vf); png_structp png = PNGWriteOpen(vf);
png_infop info = PNGWriteHeader(png, image->width, image->height); png_infop info = PNGWriteHeader(png, image->width, image->height, mCOLOR_NATIVE);
if (!PNGWritePixels(png, image->width, image->height, image->stride, image->data)) { if (!PNGWritePixels(png, image->width, image->height, image->stride, image->data, mCOLOR_NATIVE)) {
CIerr(0, "Could not write output image\n"); CIerr(0, "Could not write output image\n");
} }
PNGWriteClose(png, info); PNGWriteClose(png, info);

View File

@ -208,32 +208,13 @@ bool mImageSave(const struct mImage* image, const char* path, const char* format
#ifdef USE_PNG #ifdef USE_PNG
bool mImageSavePNG(const struct mImage* image, struct VFile* vf) { bool mImageSavePNG(const struct mImage* image, struct VFile* vf) {
if (image->format != mCOLOR_XBGR8 && image->format != mCOLOR_ABGR8) {
struct mImage* newImage;
if (mColorFormatHasAlpha(image->format)) {
newImage = mImageConvertToFormat(image, mCOLOR_ABGR8);
} else {
newImage = mImageConvertToFormat(image, mCOLOR_XBGR8);
}
bool ret = mImageSavePNG(newImage, vf);
mImageDestroy(newImage);
return ret;
}
png_structp png = PNGWriteOpen(vf); png_structp png = PNGWriteOpen(vf);
png_infop info = NULL; png_infop info = NULL;
bool ok = false; bool ok = false;
if (png) { if (png) {
if (image->format == mCOLOR_XBGR8) { info = PNGWriteHeader(png, image->width, image->height, image->format);
info = PNGWriteHeader(png, image->width, image->height);
if (info) { if (info) {
ok = PNGWritePixels(png, image->width, image->height, image->stride, image->data); ok = PNGWritePixels(png, image->width, image->height, image->stride, image->data, image->format);
}
} else {
info = PNGWriteHeaderA(png, image->width, image->height);
if (info) {
ok = PNGWritePixelsA(png, image->width, image->height, image->stride, image->data);
}
} }
PNGWriteClose(png, info); PNGWriteClose(png, info);
} }

View File

@ -51,12 +51,37 @@ static png_infop _pngWriteHeader(png_structp png, unsigned width, unsigned heigh
return info; return info;
} }
png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height) { png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height, enum mColorFormat fmt) {
return _pngWriteHeader(png, width, height, PNG_COLOR_TYPE_RGB); int type;
} switch (fmt) {
case mCOLOR_XBGR8:
png_infop PNGWriteHeaderA(png_structp png, unsigned width, unsigned height) { case mCOLOR_XRGB8:
return _pngWriteHeader(png, width, height, PNG_COLOR_TYPE_RGB_ALPHA); case mCOLOR_BGRX8:
case mCOLOR_RGBX8:
case mCOLOR_RGB5:
case mCOLOR_BGR5:
case mCOLOR_RGB565:
case mCOLOR_BGR565:
case mCOLOR_RGB8:
case mCOLOR_BGR8:
type = PNG_COLOR_TYPE_RGB;
break;
case mCOLOR_ABGR8:
case mCOLOR_ARGB8:
case mCOLOR_BGRA8:
case mCOLOR_RGBA8:
case mCOLOR_ARGB5:
case mCOLOR_ABGR5:
case mCOLOR_RGBA5:
case mCOLOR_BGRA5:
case mCOLOR_ANY:
type = PNG_COLOR_TYPE_RGB_ALPHA;
break;
case mCOLOR_L8:
type = PNG_COLOR_TYPE_GRAY;
break;
}
return _pngWriteHeader(png, width, height, type);
} }
png_infop PNGWriteHeader8(png_structp png, unsigned width, unsigned height) { png_infop PNGWriteHeader8(png_structp png, unsigned width, unsigned height) {
@ -85,90 +110,332 @@ bool PNGWritePalette(png_structp png, png_infop info, const uint32_t* palette, u
return true; return true;
} }
bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels) { static void _convertRowXBGR8(png_bytep row, const png_byte* pixelData, unsigned width) {
png_bytep row = malloc(sizeof(png_byte) * width * 3);
if (!row) {
return false;
}
const png_byte* pixelData = pixels;
if (setjmp(png_jmpbuf(png))) {
free(row);
return false;
}
unsigned i;
for (i = 0; i < height; ++i) {
unsigned x; unsigned x;
for (x = 0; x < width; ++x) { for (x = 0; x < width; ++x) {
#ifdef COLOR_16_BIT #ifdef __BIG_ENDIAN__
uint16_t c = ((uint16_t*) pixelData)[stride * i + x]; row[x * 3] = pixelData[x * 4 + 3];
#ifdef COLOR_5_6_5 row[x * 3 + 1] = pixelData[x * 4 + 2];
row[x * 3] = (c >> 8) & 0xF8; row[x * 3 + 2] = pixelData[x * 4 + 1];
row[x * 3 + 1] = (c >> 3) & 0xFC;
row[x * 3 + 2] = (c << 3) & 0xF8;
#else #else
row[x * 3] = pixelData[x * 4];
row[x * 3 + 1] = pixelData[x * 4 + 1];
row[x * 3 + 2] = pixelData[x * 4 + 2];
#endif
}
}
static void _convertRowXRGB8(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
#ifdef __BIG_ENDIAN__
row[x * 3] = pixelData[x * 4 + 1];
row[x * 3 + 1] = pixelData[x * 4 + 2];
row[x * 3 + 2] = pixelData[x * 4 + 3];
#else
row[x * 3] = pixelData[x * 4 + 2];
row[x * 3 + 1] = pixelData[x * 4 + 1];
row[x * 3 + 2] = pixelData[x * 4];
#endif
}
}
static void _convertRowBGRX8(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
#ifdef __BIG_ENDIAN__
row[x * 3] = pixelData[x * 4 + 2];
row[x * 3 + 1] = pixelData[x * 4 + 1];
row[x * 3 + 2] = pixelData[x * 4];
#else
row[x * 3] = pixelData[x * 4 + 1];
row[x * 3 + 1] = pixelData[x * 4 + 2];
row[x * 3 + 2] = pixelData[x * 4 + 3];
#endif
}
}
static void _convertRowRGBX8(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
#ifdef __BIG_ENDIAN__
row[x * 3] = pixelData[x * 4];
row[x * 3 + 1] = pixelData[x * 4 + 1];
row[x * 3 + 2] = pixelData[x * 4 + 2];
#else
row[x * 3] = pixelData[x * 4 + 3];
row[x * 3 + 1] = pixelData[x * 4 + 2];
row[x * 3 + 2] = pixelData[x * 4 + 1];
#endif
}
}
static void _convertRowABGR8(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
#ifdef __BIG_ENDIAN__
row[x * 4] = pixelData[x * 4 + 3];
row[x * 4 + 1] = pixelData[x * 4 + 2];
row[x * 4 + 2] = pixelData[x * 4 + 1];
row[x * 4 + 3] = pixelData[x * 4];
#else
row[x * 4] = pixelData[x * 4];
row[x * 4 + 1] = pixelData[x * 4 + 1];
row[x * 4 + 2] = pixelData[x * 4 + 2];
row[x * 4 + 3] = pixelData[x * 4 + 3];
#endif
}
}
static void _convertRowARGB8(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
#ifdef __BIG_ENDIAN__
row[x * 4] = pixelData[x * 4 + 1];
row[x * 4 + 1] = pixelData[x * 4 + 2];
row[x * 4 + 2] = pixelData[x * 4 + 3];
row[x * 4 + 3] = pixelData[x * 4];
#else
row[x * 4] = pixelData[x * 4 + 2];
row[x * 4 + 1] = pixelData[x * 4 + 1];
row[x * 4 + 2] = pixelData[x * 4];
row[x * 4 + 3] = pixelData[x * 4 + 3];
#endif
}
}
static void _convertRowBGRA8(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
#ifdef __BIG_ENDIAN__
row[x * 4] = pixelData[x * 4 + 2];
row[x * 4 + 1] = pixelData[x * 4 + 1];
row[x * 4 + 2] = pixelData[x * 4];
row[x * 4 + 3] = pixelData[x * 4 + 3];
#else
row[x * 4] = pixelData[x * 4 + 1];
row[x * 4 + 1] = pixelData[x * 4 + 2];
row[x * 4 + 2] = pixelData[x * 4 + 3];
row[x * 4 + 3] = pixelData[x * 4];
#endif
}
}
static void _convertRowRGBA8(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
#ifdef __BIG_ENDIAN__
row[x * 4] = pixelData[x * 4];
row[x * 4 + 1] = pixelData[x * 4 + 1];
row[x * 4 + 2] = pixelData[x * 4 + 2];
row[x * 4 + 3] = pixelData[x * 4 + 3];
#else
row[x * 4] = pixelData[x * 4 + 3];
row[x * 4 + 1] = pixelData[x * 4 + 2];
row[x * 4 + 2] = pixelData[x * 4 + 1];
row[x * 4 + 3] = pixelData[x * 4];
#endif
}
}
static void _convertRowRGB5(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
uint16_t c = ((uint16_t*) pixelData)[x];
row[x * 3] = (c >> 7) & 0xF8; row[x * 3] = (c >> 7) & 0xF8;
row[x * 3 + 1] = (c >> 2) & 0xF8; row[x * 3 + 1] = (c >> 2) & 0xF8;
row[x * 3 + 2] = (c << 3) & 0xF8; row[x * 3 + 2] = (c << 3) & 0xF8;
#endif
#else
#ifdef __BIG_ENDIAN__
row[x * 3] = pixelData[stride * i * 4 + x * 4 + 3];
row[x * 3 + 1] = pixelData[stride * i * 4 + x * 4 + 2];
row[x * 3 + 2] = pixelData[stride * i * 4 + x * 4 + 1];
#else
row[x * 3] = pixelData[stride * i * 4 + x * 4];
row[x * 3 + 1] = pixelData[stride * i * 4 + x * 4 + 1];
row[x * 3 + 2] = pixelData[stride * i * 4 + x * 4 + 2];
#endif
#endif
} }
png_write_row(png, row);
}
free(row);
return true;
} }
bool PNGWritePixelsA(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels) { static void _convertRowBGR5(png_bytep row, const png_byte* pixelData, unsigned width) {
png_bytep row = malloc(sizeof(png_byte) * width * 4);
if (!row) {
return false;
}
const png_byte* pixelData = pixels;
if (setjmp(png_jmpbuf(png))) {
free(row);
return false;
}
unsigned i;
for (i = 0; i < height; ++i) {
unsigned x; unsigned x;
for (x = 0; x < width; ++x) { for (x = 0; x < width; ++x) {
#ifdef COLOR_16_BIT uint16_t c = ((uint16_t*) pixelData)[x];
uint16_t c = ((uint16_t*) pixelData)[stride * i + x]; row[x * 3] = (c << 3) & 0xF8;
#ifdef COLOR_5_6_5 row[x * 3 + 1] = (c >> 2) & 0xF8;
row[x * 4] = (c >> 8) & 0xF8; row[x * 3 + 2] = (c >> 7) & 0xF8;
row[x * 4 + 1] = (c >> 3) & 0xFC; }
row[x * 4 + 2] = (c << 3) & 0xF8; }
row[x * 4 + 3] = 0xFF;
#else static void _convertRowARGB5(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
uint16_t c = ((uint16_t*) pixelData)[x];
row[x * 4] = (c >> 7) & 0xF8; row[x * 4] = (c >> 7) & 0xF8;
row[x * 4 + 1] = (c >> 2) & 0xF8; row[x * 4 + 1] = (c >> 2) & 0xF8;
row[x * 4 + 2] = (c << 3) & 0xF8; row[x * 4 + 2] = (c << 3) & 0xF8;
row[x * 4 + 3] = (c >> 15) * 0xFF; row[x * 4 + 3] = (c >> 15) * 0xFF;
#endif }
#else }
static void _convertRowABGR5(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
uint16_t c = ((uint16_t*) pixelData)[x];
row[x * 4] = (c << 3) & 0xF8;
row[x * 4 + 1] = (c >> 2) & 0xF8;
row[x * 4 + 2] = (c >> 7) & 0xF8;
row[x * 4 + 3] = (c >> 15) * 0xFF;
}
}
static void _convertRowRGBA5(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
uint16_t c = ((uint16_t*) pixelData)[x];
row[x * 4] = (c >> 8) & 0xF8;
row[x * 4 + 1] = (c >> 3) & 0xF8;
row[x * 4 + 2] = (c << 2) & 0xF8;
row[x * 4 + 3] = (c & 1) * 0xFF;
}
}
static void _convertRowBGRA5(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
uint16_t c = ((uint16_t*) pixelData)[x];
row[x * 4] = (c << 2) & 0xF8;
row[x * 4 + 1] = (c >> 3) & 0xF8;
row[x * 4 + 2] = (c >> 8) & 0xF8;
row[x * 4 + 3] = (c & 1) * 0xFF;
}
}
static void _convertRowRGB565(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
uint16_t c = ((uint16_t*) pixelData)[x];
row[x * 3] = (c >> 8) & 0xF8;
row[x * 3 + 1] = (c >> 3) & 0xFC;
row[x * 3 + 2] = (c << 3) & 0xF8;
}
}
static void _convertRowBGR565(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
uint16_t c = ((uint16_t*) pixelData)[x];
row[x * 3] = (c << 3) & 0xF8;
row[x * 3 + 1] = (c >> 3) & 0xFC;
row[x * 3 + 2] = (c >> 8) & 0xF8;
}
}
static void _convertRowBGR8(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
row[x * 4] = pixelData[stride * i * 4 + x * 4 + 3]; row[x * 3] = pixelData[x * 3 + 2];
row[x * 4 + 1] = pixelData[stride * i * 4 + x * 4 + 2]; row[x * 3 + 1] = pixelData[x * 3 + 1];
row[x * 4 + 2] = pixelData[stride * i * 4 + x * 4 + 1]; row[x * 3 + 2] = pixelData[x * 3];
row[x * 4 + 3] = pixelData[stride * i * 4 + x * 4];
#else #else
row[x * 4] = pixelData[stride * i * 4 + x * 4]; row[x * 3] = pixelData[x * 3];
row[x * 4 + 1] = pixelData[stride * i * 4 + x * 4 + 1]; row[x * 3 + 1] = pixelData[x * 3 + 1];
row[x * 4 + 2] = pixelData[stride * i * 4 + x * 4 + 2]; row[x * 3 + 2] = pixelData[x * 3 + 2];
row[x * 4 + 3] = pixelData[stride * i * 4 + x * 4 + 3];
#endif #endif
}
}
static void _convertRowRGB8(png_bytep row, const png_byte* pixelData, unsigned width) {
unsigned x;
for (x = 0; x < width; ++x) {
#ifdef __BIG_ENDIAN__
row[x * 3] = pixelData[x * 3];
row[x * 3 + 1] = pixelData[x * 3 + 1];
row[x * 3 + 2] = pixelData[x * 3 + 2];
#else
row[x * 3] = pixelData[x * 3 + 2];
row[x * 3 + 1] = pixelData[x * 3 + 1];
row[x * 3 + 2] = pixelData[x * 3];
#endif #endif
} }
}
bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels, enum mColorFormat fmt) {
int depth;
if (fmt == mCOLOR_L8) {
depth = 1;
} else if (mColorFormatHasAlpha(fmt)) {
depth = 4;
} else {
depth = 3;
}
png_bytep row = malloc(sizeof(png_byte) * width * depth);
if (!row) {
return false;
}
const png_byte* pixelData = pixels;
if (setjmp(png_jmpbuf(png))) {
free(row);
return false;
}
const png_byte* pixelRow = pixelData;
stride *= mColorFormatBytes(fmt);
unsigned i;
for (i = 0; i < height; ++i, pixelRow += stride) {
switch (fmt) {
case mCOLOR_XBGR8:
_convertRowXBGR8(row, pixelRow, width);
break;
case mCOLOR_XRGB8:
_convertRowXRGB8(row, pixelRow, width);
break;
case mCOLOR_BGRX8:
_convertRowBGRX8(row, pixelRow, width);
break;
case mCOLOR_RGBX8:
_convertRowRGBX8(row, pixelRow, width);
break;
case mCOLOR_ABGR8:
_convertRowABGR8(row, pixelRow, width);
break;
case mCOLOR_ARGB8:
_convertRowARGB8(row, pixelRow, width);
break;
case mCOLOR_BGRA8:
_convertRowBGRA8(row, pixelRow, width);
break;
case mCOLOR_RGBA8:
_convertRowRGBA8(row, pixelRow, width);
break;
case mCOLOR_RGB5:
_convertRowRGB5(row, pixelRow, width);
break;
case mCOLOR_BGR5:
_convertRowBGR5(row, pixelRow, width);
break;
case mCOLOR_ARGB5:
_convertRowARGB5(row, pixelRow, width);
break;
case mCOLOR_ABGR5:
_convertRowABGR5(row, pixelRow, width);
break;
case mCOLOR_RGBA5:
_convertRowRGBA5(row, pixelRow, width);
break;
case mCOLOR_BGRA5:
_convertRowBGRA5(row, pixelRow, width);
break;
case mCOLOR_RGB565:
_convertRowRGB565(row, pixelRow, width);
break;
case mCOLOR_BGR565:
_convertRowBGR565(row, pixelRow, width);
break;
case mCOLOR_BGR8:
_convertRowBGR8(row, pixelRow, width);
break;
case mCOLOR_RGB8:
_convertRowRGB8(row, pixelRow, width);
break;
case mCOLOR_L8:
memcpy(row, pixelRow, width);
break;
case mCOLOR_ANY:
// Invalid value
longjmp(png_jmpbuf(png), 1);
}
png_write_row(png, row); png_write_row(png, row);
} }
free(row); free(row);

View File

@ -551,6 +551,51 @@ M_TEST_DEFINE(savePngNonNative) {
assert_int_equal(mImageGetPixel(image, 0, 0), 0x01234567); assert_int_equal(mImageGetPixel(image, 0, 0), 0x01234567);
mImageDestroy(image); mImageDestroy(image);
} }
M_TEST_DEFINE(savePngRoundTrip) {
const enum mColorFormat formats[] = {
mCOLOR_XBGR8, mCOLOR_XRGB8,
mCOLOR_BGRX8, mCOLOR_RGBX8,
mCOLOR_ABGR8, mCOLOR_ARGB8,
mCOLOR_BGRA8, mCOLOR_RGBA8,
mCOLOR_RGB5, mCOLOR_BGR5,
mCOLOR_ARGB5, mCOLOR_ABGR5,
mCOLOR_RGBA5, mCOLOR_BGRA5,
mCOLOR_RGB565, mCOLOR_BGR565,
mCOLOR_RGB8, mCOLOR_BGR8,
0
};
int i;
for (i = 0; formats[i]; ++i) {
struct mImage* image = mImageCreate(2, 2, formats[i]);
mImageSetPixel(image, 0, 0, 0xFF181008);
mImageSetPixel(image, 1, 0, 0xFF100818);
mImageSetPixel(image, 0, 1, 0xFF081810);
mImageSetPixel(image, 1, 1, 0xFF181008);
assert_int_equal(mImageGetPixel(image, 0, 0), 0xFF181008);
assert_int_equal(mImageGetPixel(image, 1, 0), 0xFF100818);
assert_int_equal(mImageGetPixel(image, 0, 1), 0xFF081810);
assert_int_equal(mImageGetPixel(image, 1, 1), 0xFF181008);
struct VFile* vf = VFileMemChunk(NULL, 0);
assert_true(mImageSaveVF(image, vf, "png"));
mImageDestroy(image);
assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0);
assert_true(isPNG(vf));
assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0);
image = mImageLoadVF(vf);
vf->close(vf);
assert_non_null(image);
assert_int_equal(mImageGetPixel(image, 0, 0), 0xFF181008);
assert_int_equal(mImageGetPixel(image, 1, 0), 0xFF100818);
assert_int_equal(mImageGetPixel(image, 0, 1), 0xFF081810);
assert_int_equal(mImageGetPixel(image, 1, 1), 0xFF181008);
mImageDestroy(image);
}
}
#endif #endif
M_TEST_DEFINE(convert1x1) { M_TEST_DEFINE(convert1x1) {
@ -997,6 +1042,7 @@ M_TEST_SUITE_DEFINE(Image,
cmocka_unit_test(loadPng32), cmocka_unit_test(loadPng32),
cmocka_unit_test(savePngNative), cmocka_unit_test(savePngNative),
cmocka_unit_test(savePngNonNative), cmocka_unit_test(savePngNonNative),
cmocka_unit_test(savePngRoundTrip),
#endif #endif
cmocka_unit_test(convert1x1), cmocka_unit_test(convert1x1),
cmocka_unit_test(convert2x1), cmocka_unit_test(convert2x1),