diff options
Diffstat (limited to 'minui')
-rw-r--r-- | minui/resources.c | 167 |
1 files changed, 67 insertions, 100 deletions
diff --git a/minui/resources.c b/minui/resources.c index 5beb6a6..7ecfeef 100644 --- a/minui/resources.c +++ b/minui/resources.c @@ -29,97 +29,84 @@ #include <pixelflinger/pixelflinger.h> +#include <png.h> + #include "minui.h" -// File signature for BMP files. -// The letters 'BM' as a little-endian unsigned short. - -#define BMP_SIGNATURE 0x4d42 - -typedef struct { - // constant, value should equal BMP_SIGNATURE - unsigned short bfType; - // size of the file in bytes. - unsigned long bfSize; - // must always be set to zero. - unsigned short bfReserved1; - // must always be set to zero. - unsigned short bfReserved2; - // offset from the beginning of the file to the bitmap data. - unsigned long bfOffBits; - - // The BITMAPINFOHEADER: - // size of the BITMAPINFOHEADER structure, in bytes. - unsigned long biSize; - // width of the image, in pixels. - unsigned long biWidth; - // height of the image, in pixels. - unsigned long biHeight; - // number of planes of the target device, must be set to 1. - unsigned short biPlanes; - // number of bits per pixel. - unsigned short biBitCount; - // type of compression, zero means no compression. - unsigned long biCompression; - // size of the image data, in bytes. If there is no compression, - // it is valid to set this member to zero. - unsigned long biSizeImage; - // horizontal pixels per meter on the designated targer device, - // usually set to zero. - unsigned long biXPelsPerMeter; - // vertical pixels per meter on the designated targer device, - // usually set to zero. - unsigned long biYPelsPerMeter; - // number of colors used in the bitmap, if set to zero the - // number of colors is calculated using the biBitCount member. - unsigned long biClrUsed; - // number of color that are 'important' for the bitmap, - // if set to zero, all colors are important. - unsigned long biClrImportant; -} __attribute__((packed)) BitMapFileHeader; +// libpng gives "undefined reference to 'pow'" errors, and I have no +// idea how to convince the build system to link with -lm. We don't +// need this functionality (it's used for gamma adjustment) so provide +// a dummy implementation to satisfy the linker. +double pow(double x, double y) { + return x; +} int res_create_surface(const char* name, gr_surface* pSurface) { char resPath[256]; - BitMapFileHeader header; GGLSurface* surface = NULL; int result = 0; - - snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.bmp", name); + unsigned char header[8]; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + + snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); resPath[sizeof(resPath)-1] = '\0'; - int fd = open(resPath, O_RDONLY); - if (fd == -1) { + FILE* fp = fopen(resPath, "rb"); + if (fp == NULL) { result = -1; goto exit; } - size_t bytesRead = read(fd, &header, sizeof(header)); + + size_t bytesRead = fread(header, 1, sizeof(header), fp); if (bytesRead != sizeof(header)) { result = -2; goto exit; } - if (header.bfType != BMP_SIGNATURE) { - result = -3; // Not a legal header + + if (png_sig_cmp(header, 0, sizeof(header))) { + result = -3; goto exit; } - if (header.biPlanes != 1) { + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) { result = -4; goto exit; } - if (!(header.biBitCount == 24 || header.biBitCount == 32)) { + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { result = -5; goto exit; } - if (header.biCompression != 0) { + + if (setjmp(png_jmpbuf(png_ptr))) { result = -6; goto exit; } - size_t width = header.biWidth; - size_t height = header.biHeight; + + png_init_io(png_ptr, fp); + png_set_sig_bytes(png_ptr, sizeof(header)); + png_read_info(png_ptr, info_ptr); + + size_t width = info_ptr->width; + size_t height = info_ptr->height; size_t stride = 4 * width; size_t pixelSize = stride * height; - + + int color_type = info_ptr->color_type; + int bit_depth = info_ptr->bit_depth; + int channels = info_ptr->channels; + if (bit_depth != 8 || (channels != 3 && channels != 4) || + (color_type != PNG_COLOR_TYPE_RGB && + color_type != PNG_COLOR_TYPE_RGBA)) { + return -7; + goto exit; + } + surface = malloc(sizeof(GGLSurface) + pixelSize); if (surface == NULL) { - result = -7; + result = -8; goto exit; } unsigned char* pData = (unsigned char*) (surface + 1); @@ -128,63 +115,43 @@ int res_create_surface(const char* name, gr_surface* pSurface) { surface->height = height; surface->stride = width; /* Yes, pixels, not bytes */ surface->data = pData; - surface->format = (header.biBitCount == 24) ? + surface->format = (channels == 3) ? GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888; - // Source pixel bytes are stored B G R {A} - - lseek(fd, header.bfOffBits, SEEK_SET); - size_t y; - if (header.biBitCount == 24) { // RGB - size_t inputStride = (((3 * width + 3) >> 2) << 2); - for (y = 0; y < height; y++) { - unsigned char* pRow = pData + (height - (y + 1)) * stride; - bytesRead = read(fd, pRow, inputStride); - if (bytesRead != inputStride) { - result = -8; - goto exit; - } + int y; + if (channels == 3) { + for (y = 0; y < height; ++y) { + unsigned char* pRow = pData + y * stride; + png_read_row(png_ptr, pRow, NULL); + int x; for(x = width - 1; x >= 0; x--) { int sx = x * 3; int dx = x * 4; - unsigned char b = pRow[sx]; + unsigned char r = pRow[sx]; unsigned char g = pRow[sx + 1]; - unsigned char r = pRow[sx + 2]; + unsigned char b = pRow[sx + 2]; unsigned char a = 0xff; pRow[dx ] = r; // r pRow[dx + 1] = g; // g - pRow[dx + 2] = b; // b; + pRow[dx + 2] = b; // b pRow[dx + 3] = a; } } - } else { // RGBA - for (y = 0; y < height; y++) { - unsigned char* pRow = pData + (height - (y + 1)) * stride; - bytesRead = read(fd, pRow, stride); - if (bytesRead != stride) { - result = -9; - goto exit; - } - size_t x; - for(x = 0; x < width; x++) { - size_t xx = x * 4; - unsigned char b = pRow[xx]; - unsigned char g = pRow[xx + 1]; - unsigned char r = pRow[xx + 2]; - unsigned char a = pRow[xx + 3]; - pRow[xx ] = r; - pRow[xx + 1] = g; - pRow[xx + 2] = b; - pRow[xx + 3] = a; - } + } else { + for (y = 0; y < height; ++y) { + unsigned char* pRow = pData + y * stride; + png_read_row(png_ptr, pRow, NULL); } } + *pSurface = (gr_surface) surface; exit: - if (fd >= 0) { - close(fd); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + if (fp != NULL) { + fclose(fp); } if (result < 0) { if (surface) { |