From 469954fe3d7c3d729e500512ab911a037b90cc77 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Fri, 7 Mar 2014 09:21:25 -0800 Subject: change how recovery animation is implemented Instead of one 'base' installing image and a number of overlay images that are drawn on top of it, we represent the installing animation with one PNG that contains all the animation frames, interlaced by row. The PNG is expected to have a text chunk with the keyword 'Frames' and a value that's the number of frames (as an ascii string). This representation provides better compression, removes the need to subclass ScreenRecoveryUI just to change the position of the overlay or number of frames, and doesn't require gr_blit() to support an alpha channel. We also remove the 'indeterminate' progress bar used when wiping data and/or cache. The main animation serves the same purpose (showing that the device is still alive); the spinning progress bar has been redundant for a while. This changes the default recovery animation to include the antenna-wiggling and gear-turning that's used in the Nexus 5 recovery animation. Change-Id: I51930a76035ac09969a25472f4e572b289418729 Conflicts: screen_ui.cpp screen_ui.h --- minui/resources.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 179 insertions(+), 3 deletions(-) (limited to 'minui/resources.c') diff --git a/minui/resources.c b/minui/resources.c index c0a9ccacb..5ad9b1d05 100644 --- a/minui/resources.c +++ b/minui/resources.c @@ -181,6 +181,182 @@ exit: return result; } +int res_create_multi_surface(const char* name, int* frames, gr_surface** pSurface) { + char resPath[256]; + int result = 0; + unsigned char header[8]; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + int i; + GGLSurface** surface = NULL; + + *pSurface = NULL; + *frames = -1; + + snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); + resPath[sizeof(resPath)-1] = '\0'; + FILE* fp = fopen(resPath, "rb"); + if (fp == NULL) { + result = -1; + goto exit; + } + + size_t bytesRead = fread(header, 1, sizeof(header), fp); + if (bytesRead != sizeof(header)) { + result = -2; + goto exit; + } + + if (png_sig_cmp(header, 0, sizeof(header))) { + result = -3; + goto exit; + } + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) { + result = -4; + goto exit; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + result = -5; + goto exit; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + result = -6; + goto exit; + } + + png_init_io(png_ptr, fp); + png_set_sig_bytes(png_ptr, sizeof(header)); + png_read_info(png_ptr, info_ptr); + + int color_type, bit_depth; + png_uint_32 width, height; + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, + &color_type, NULL, NULL, NULL); + + int channels = png_get_channels(png_ptr, info_ptr); + + if (!(bit_depth == 8 && + ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || + (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) || + (channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE || + color_type == PNG_COLOR_TYPE_GRAY))))) { + return -7; + goto exit; + } + + *frames = 1; + png_textp text; + int num_text; + if (png_get_text(png_ptr, info_ptr, &text, &num_text)) { + for (i = 0; i < num_text; ++i) { + if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) { + *frames = atoi(text[i].text); + break; + } + } + printf(" found frames = %d\n", *frames); + } + + if (height % *frames != 0) { + printf("bad height (%d) for frame count (%d)\n", height, *frames); + result = -9; + goto exit; + } + + size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width; + size_t pixelSize = stride * height / *frames; + + surface = malloc(*frames * sizeof(GGLSurface*)); + if (surface == NULL) { + result = -8; + goto exit; + } + for (i = 0; i < *frames; ++i) { + surface[i] = malloc(sizeof(GGLSurface) + pixelSize); + surface[i]->version = sizeof(GGLSurface); + surface[i]->width = width; + surface[i]->height = height / *frames; + surface[i]->stride = width; /* Yes, pixels, not bytes */ + surface[i]->data = (unsigned char*) (surface[i] + 1); + + if (channels == 3) { + surface[i]->format = GGL_PIXEL_FORMAT_RGBX_8888; + } else if (color_type == PNG_COLOR_TYPE_PALETTE) { + surface[i]->format = GGL_PIXEL_FORMAT_RGBA_8888; + } else if (channels == 1) { + surface[i]->format = GGL_PIXEL_FORMAT_L_8; + } else { + surface[i]->format = GGL_PIXEL_FORMAT_RGBA_8888; + } + } + + int alpha = (channels == 4); + if (color_type == PNG_COLOR_TYPE_PALETTE) { + png_set_palette_to_rgb(png_ptr); + } + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + png_set_tRNS_to_alpha(png_ptr); + alpha = 1; + } + if (color_type == PNG_COLOR_TYPE_GRAY) { + alpha = 1; + } + + png_uint_32 y; + if (channels == 3 || (channels == 1 && !alpha)) { + for (y = 0; y < height; ++y) { + int fy = y / *frames; + int fr = y % *frames; + unsigned char* pRow = surface[fr]->data + fy * 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 r = pRow[sx]; + unsigned char g = pRow[sx + 1]; + 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 + 3] = a; + } + } + } else { + for (y = 0; y < height; ++y) { + int fy = y / *frames; + int fr = y % *frames; + unsigned char* pRow = surface[fr]->data + fy * stride; + png_read_row(png_ptr, pRow, NULL); + } + } + + *pSurface = (gr_surface*) surface; + +exit: + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + if (fp != NULL) { + fclose(fp); + } + if (result < 0) { + if (surface) { + for (i = 0; i < *frames; ++i) { + if (surface[i]) free(surface[i]); + } + free(surface); + } + } + return result; +} + static int matches_locale(const char* loc) { if (locale == NULL) return 0; @@ -249,7 +425,7 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { png_read_info(png_ptr, info_ptr); int color_type, bit_depth; - size_t width, height; + png_uint_32 width, height; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); int channels = png_get_channels(png_ptr, info_ptr); @@ -261,13 +437,13 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { } unsigned char* row = malloc(width); - int y; + png_uint_32 y; for (y = 0; y < height; ++y) { png_read_row(png_ptr, row, NULL); int w = (row[1] << 8) | row[0]; int h = (row[3] << 8) | row[2]; int len = row[4]; - char* loc = row+5; + char* loc = (char*)row+5; if (y+1+h >= height || matches_locale(loc)) { printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y); -- cgit v1.2.3 From 16f97c3961f08e5db7930d99e592f0a9f752df46 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Thu, 6 Mar 2014 16:16:05 -0800 Subject: remove pixelflinger from recovery Recovery now draws directly to the framebuffer by rolling its own graphics code, rather than depending on libpixelflinger. The recovery UI is modified slightly to eliminate operations that are slow with the software implementation: when the text display / menu is turned on, it now appears on a black background instead of a dimmed version of the recovery icon. There's probably substantial room for optimization of the graphics operations. Bug: 12131110 Change-Id: Iab6520e0a7aaec39e2ce39377c10aef82ae0c595 Conflicts: minui/resources.c --- minui/resources.c | 97 +++++++++++++++++++------------------------------------ 1 file changed, 33 insertions(+), 64 deletions(-) (limited to 'minui/resources.c') diff --git a/minui/resources.c b/minui/resources.c index 5ad9b1d05..df813cb1e 100644 --- a/minui/resources.c +++ b/minui/resources.c @@ -27,25 +27,26 @@ #include #include -#include - #include #include "minui.h" extern char* locale; -// 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 * y; +#define SURFACE_DATA_ALIGNMENT 8 + +static gr_surface malloc_surface(size_t data_size) { + unsigned char* temp = malloc(sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT); + if (temp == NULL) return NULL; + gr_surface surface = (gr_surface) temp; + surface->data = temp + sizeof(GRSurface) + + (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT)); + return surface; } int res_create_surface(const char* name, gr_surface* pSurface) { char resPath[256]; - GGLSurface* surface = NULL; + gr_surface surface = NULL; int result = 0; unsigned char header[8]; png_structp png_ptr = NULL; @@ -100,9 +101,8 @@ int res_create_surface(const char* name, gr_surface* pSurface) { int channels = png_get_channels(png_ptr, info_ptr); - if (!(bit_depth == 8 && + if (!(bit_depth <= 8 && ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || - (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) || (channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY))))) { return -7; @@ -110,30 +110,20 @@ int res_create_surface(const char* name, gr_surface* pSurface) { } size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width; - size_t pixelSize = stride * height; - surface = malloc(sizeof(GGLSurface) + pixelSize); + surface = malloc_surface(stride * height); if (surface == NULL) { result = -8; goto exit; } - unsigned char* pData = (unsigned char*) (surface + 1); - surface->version = sizeof(GGLSurface); + unsigned char* pData = surface->data; surface->width = width; surface->height = height; - surface->stride = width; /* Yes, pixels, not bytes */ - surface->data = pData; - surface->format = (channels == 3) ? GGL_PIXEL_FORMAT_RGBX_8888 : - ((color_type == PNG_COLOR_TYPE_PALETTE ? GGL_PIXEL_FORMAT_RGBA_8888 : GGL_PIXEL_FORMAT_L_8)); + surface->row_bytes = stride; + surface->pixel_bytes = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4); - int alpha = 0; - if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png_ptr); - } - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - png_set_tRNS_to_alpha(png_ptr); - alpha = 1; - } + int alpha = (channels == 4); + png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY) { alpha = 1; } @@ -188,7 +178,7 @@ int res_create_multi_surface(const char* name, int* frames, gr_surface** pSurfac png_structp png_ptr = NULL; png_infop info_ptr = NULL; int i; - GGLSurface** surface = NULL; + gr_surface* surface = NULL; *pSurface = NULL; *frames = -1; @@ -240,9 +230,8 @@ int res_create_multi_surface(const char* name, int* frames, gr_surface** pSurfac int channels = png_get_channels(png_ptr, info_ptr); - if (!(bit_depth == 8 && + if (!(bit_depth <= 8 && ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || - (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) || (channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY))))) { return -7; @@ -271,38 +260,21 @@ int res_create_multi_surface(const char* name, int* frames, gr_surface** pSurfac size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width; size_t pixelSize = stride * height / *frames; - surface = malloc(*frames * sizeof(GGLSurface*)); + surface = malloc(*frames * sizeof(gr_surface)); if (surface == NULL) { result = -8; goto exit; } for (i = 0; i < *frames; ++i) { - surface[i] = malloc(sizeof(GGLSurface) + pixelSize); - surface[i]->version = sizeof(GGLSurface); + surface[i] = malloc_surface(pixelSize); surface[i]->width = width; surface[i]->height = height / *frames; - surface[i]->stride = width; /* Yes, pixels, not bytes */ - surface[i]->data = (unsigned char*) (surface[i] + 1); - - if (channels == 3) { - surface[i]->format = GGL_PIXEL_FORMAT_RGBX_8888; - } else if (color_type == PNG_COLOR_TYPE_PALETTE) { - surface[i]->format = GGL_PIXEL_FORMAT_RGBA_8888; - } else if (channels == 1) { - surface[i]->format = GGL_PIXEL_FORMAT_L_8; - } else { - surface[i]->format = GGL_PIXEL_FORMAT_RGBA_8888; - } + surface[i]->row_bytes = stride; + surface[i]->pixel_bytes = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4); } int alpha = (channels == 4); - if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png_ptr); - } - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - png_set_tRNS_to_alpha(png_ptr); - alpha = 1; - } + png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY) { alpha = 1; } @@ -376,7 +348,7 @@ static int matches_locale(const char* loc) { int res_create_localized_surface(const char* name, gr_surface* pSurface) { char resPath[256]; - GGLSurface* surface = NULL; + gr_surface surface = NULL; int result = 0; unsigned char header[8]; png_structp png_ptr = NULL; @@ -430,12 +402,14 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { &color_type, NULL, NULL, NULL); int channels = png_get_channels(png_ptr, info_ptr); - if (!(bit_depth == 8 && + if (!(bit_depth <= 8 && (channels == 1 && color_type == PNG_COLOR_TYPE_GRAY))) { return -7; goto exit; } + png_set_expand(png_ptr); + unsigned char* row = malloc(width); png_uint_32 y; for (y = 0; y < height; ++y) { @@ -448,19 +422,17 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { if (y+1+h >= height || matches_locale(loc)) { printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y); - surface = malloc(sizeof(GGLSurface)); + surface = malloc_surface(w*h); if (surface == NULL) { result = -8; goto exit; } - unsigned char* pData = malloc(w*h); + unsigned char* pData = surface->data; - surface->version = sizeof(GGLSurface); surface->width = w; surface->height = h; - surface->stride = w; /* Yes, pixels, not bytes */ - surface->data = pData; - surface->format = GGL_PIXEL_FORMAT_A_8; + surface->row_bytes = w; + surface->pixel_bytes = 1; int i; for (i = 0; i < h; ++i, ++y) { @@ -493,8 +465,5 @@ exit: } void res_free_surface(gr_surface surface) { - GGLSurface* pSurface = (GGLSurface*) surface; - if (pSurface) { - free(pSurface); - } + free(surface); } -- cgit v1.2.3 From f3bb31c32fa879ccce358c15c93b7bd8582d1756 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Fri, 14 Mar 2014 09:39:48 -0700 Subject: Recovery 64-bit compile issues Change-Id: I92d5abd1a628feab3b0246924fab7f97ba3b9d34 --- minui/resources.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'minui/resources.c') diff --git a/minui/resources.c b/minui/resources.c index df813cb1e..a6528b357 100644 --- a/minui/resources.c +++ b/minui/resources.c @@ -95,7 +95,7 @@ int res_create_surface(const char* name, gr_surface* pSurface) { png_read_info(png_ptr, info_ptr); int color_type, bit_depth; - size_t width, height; + png_uint_32 width, height; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); -- cgit v1.2.3 From a418aa7dd5e94cbf1ab2a6fa1c63f60e5e087d42 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Mon, 17 Mar 2014 12:10:02 -0700 Subject: refactor image resource loading code in minui Reduce the number of copies of libpng boilerplate. Rename res_create_* functions to be more clear. Make explicit the use of the framebuffer pixel format for images, and handle more combinations of input and output (eg, loading a grayscale image for display rather than use as a text alpha channel). Change-Id: I3d41c800a8f4c22b2f0167967ce6ee4d6b2b8846 --- minui/resources.c | 440 +++++++++++++++++++++++++----------------------------- 1 file changed, 207 insertions(+), 233 deletions(-) (limited to 'minui/resources.c') diff --git a/minui/resources.c b/minui/resources.c index a6528b357..69fd14bee 100644 --- a/minui/resources.c +++ b/minui/resources.c @@ -44,15 +44,11 @@ static gr_surface malloc_surface(size_t data_size) { return surface; } -int res_create_surface(const char* name, gr_surface* pSurface) { +static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr, + png_uint_32* width, png_uint_32* height, png_byte* channels) { char resPath[256]; - gr_surface surface = NULL; - int result = 0; unsigned char header[8]; - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - - *pSurface = NULL; + int result = 0; snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); resPath[sizeof(resPath)-1] = '\0'; @@ -73,170 +69,182 @@ int res_create_surface(const char* name, gr_surface* pSurface) { goto exit; } - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) { + *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!*png_ptr) { result = -4; goto exit; } - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { + *info_ptr = png_create_info_struct(*png_ptr); + if (!*info_ptr) { result = -5; goto exit; } - if (setjmp(png_jmpbuf(png_ptr))) { + if (setjmp(png_jmpbuf(*png_ptr))) { result = -6; goto exit; } - png_init_io(png_ptr, fp); - png_set_sig_bytes(png_ptr, sizeof(header)); - png_read_info(png_ptr, info_ptr); + png_init_io(*png_ptr, fp); + png_set_sig_bytes(*png_ptr, sizeof(header)); + png_read_info(*png_ptr, *info_ptr); int color_type, bit_depth; - png_uint_32 width, height; - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, + png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth, &color_type, NULL, NULL, NULL); - int channels = png_get_channels(png_ptr, info_ptr); - - if (!(bit_depth <= 8 && - ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || - (channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE || - color_type == PNG_COLOR_TYPE_GRAY))))) { - return -7; + *channels = png_get_channels(*png_ptr, *info_ptr); + + if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) { + // 8-bit RGB images: great, nothing to do. + } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) { + // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. + png_set_expand_gray_1_2_4_to_8(*png_ptr); + } else if (bit_depth == 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) { + // paletted images: expand to 8-bit RGB. Note that we DON'T + // currently expand the tRNS chunk (if any) to an alpha + // channel, because minui doesn't support alpha channels in + // general. + png_set_palette_to_rgb(*png_ptr); + *channels = 3; + } else { + fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n", + bit_depth, (int) channels, color_type); + result = -7; goto exit; } - size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width; + return result; - surface = malloc_surface(stride * height); - if (surface == NULL) { - result = -8; - goto exit; + exit: + if (result < 0) { + png_destroy_read_struct(png_ptr, info_ptr, NULL); + } + if (fp != NULL) { + fclose(fp); } - unsigned char* pData = surface->data; + + return result; +} + +// "display" surfaces are transformed into the framebuffer's required +// pixel format (currently only RGBX is supported) at load time, so +// gr_blit() can be nothing more than a memcpy() for each row. The +// next two functions are the only ones that know anything about the +// framebuffer pixel format; they need to be modified if the +// framebuffer format changes (but nothing else should). + +// Allocate and return a gr_surface sufficient for storing an image of +// the indicated size in the framebuffer pixel format. +static gr_surface init_display_surface(png_uint_32 width, png_uint_32 height) { + gr_surface surface; + + surface = malloc_surface(width * height * 4); + if (surface == NULL) return NULL; + surface->width = width; surface->height = height; - surface->row_bytes = stride; - surface->pixel_bytes = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4); + surface->row_bytes = width * 4; + surface->pixel_bytes = 4; - int alpha = (channels == 4); - png_set_expand(png_ptr); - if (color_type == PNG_COLOR_TYPE_GRAY) { - alpha = 1; - } + return surface; +} - unsigned int y; - if (channels == 3 || (channels == 1 && !alpha)) { - 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 r = pRow[sx]; - unsigned char g = pRow[sx + 1]; - 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 + 3] = a; +// Copy 'input_row' to 'output_row', transforming it to the +// framebuffer pixel format. The input format depends on the value of +// 'channels': +// +// 1 - input is 8-bit grayscale +// 3 - input is 24-bit RGB +// 4 - input is 32-bit RGBA/RGBX +// +// 'width' is the number of pixels in the row. +static void transform_rgb_to_draw(unsigned char* input_row, + unsigned char* output_row, + int channels, int width) { + int x; + unsigned char* ip = input_row; + unsigned char* op = output_row; + + switch (channels) { + case 1: + // expand gray level to RGBX + for (x = 0; x < width; ++x) { + *op++ = *ip; + *op++ = *ip; + *op++ = *ip; + *op++ = 0xff; + ip++; } - } - } else { - for (y = 0; y < height; ++y) { - unsigned char* pRow = pData + y * stride; - png_read_row(png_ptr, pRow, NULL); - } - } - - *pSurface = (gr_surface) surface; + break; -exit: - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + case 3: + // expand RGBA to RGBX + for (x = 0; x < width; ++x) { + *op++ = *ip++; + *op++ = *ip++; + *op++ = *ip++; + *op++ = 0xff; + } + break; - if (fp != NULL) { - fclose(fp); - } - if (result < 0) { - if (surface) { - free(surface); - } + case 4: + // copy RGBA to RGBX + memcpy(output_row, input_row, width*4); + break; } - return result; } -int res_create_multi_surface(const char* name, int* frames, gr_surface** pSurface) { - char resPath[256]; +int res_create_display_surface(const char* name, gr_surface* pSurface) { + gr_surface surface = NULL; int result = 0; - unsigned char header[8]; png_structp png_ptr = NULL; png_infop info_ptr = NULL; - int i; - gr_surface* surface = NULL; + png_uint_32 width, height; + png_byte channels; *pSurface = NULL; - *frames = -1; - snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); - resPath[sizeof(resPath)-1] = '\0'; - FILE* fp = fopen(resPath, "rb"); - if (fp == NULL) { - result = -1; - goto exit; - } - - size_t bytesRead = fread(header, 1, sizeof(header), fp); - if (bytesRead != sizeof(header)) { - result = -2; - goto exit; - } - - if (png_sig_cmp(header, 0, sizeof(header))) { - result = -3; - goto exit; - } + result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); + if (result < 0) return result; - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) { - result = -4; + surface = init_display_surface(width, height); + if (surface == NULL) { + result = -8; goto exit; } - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - result = -5; - goto exit; + unsigned char* p_row = malloc(width * 4); + unsigned int y; + for (y = 0; y < height; ++y) { + png_read_row(png_ptr, p_row, NULL); + transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width); } + free(p_row); - if (setjmp(png_jmpbuf(png_ptr))) { - result = -6; - goto exit; - } + *pSurface = surface; - png_init_io(png_ptr, fp); - png_set_sig_bytes(png_ptr, sizeof(header)); - png_read_info(png_ptr, info_ptr); + exit: + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + if (result < 0 && surface != NULL) free(surface); + return result; +} - int color_type, bit_depth; +int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface) { + gr_surface* surface = NULL; + int result = 0; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; png_uint_32 width, height; - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, - &color_type, NULL, NULL, NULL); + png_byte channels; + int i; - int channels = png_get_channels(png_ptr, info_ptr); + *pSurface = NULL; + *frames = -1; - if (!(bit_depth <= 8 && - ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || - (channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE || - color_type == PNG_COLOR_TYPE_GRAY))))) { - return -7; - goto exit; - } + result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); + if (result < 0) return result; *frames = 1; png_textp text; @@ -257,67 +265,35 @@ int res_create_multi_surface(const char* name, int* frames, gr_surface** pSurfac goto exit; } - size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width; - size_t pixelSize = stride * height / *frames; - surface = malloc(*frames * sizeof(gr_surface)); if (surface == NULL) { result = -8; goto exit; } for (i = 0; i < *frames; ++i) { - surface[i] = malloc_surface(pixelSize); - surface[i]->width = width; - surface[i]->height = height / *frames; - surface[i]->row_bytes = stride; - surface[i]->pixel_bytes = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4); - } - - int alpha = (channels == 4); - png_set_expand(png_ptr); - if (color_type == PNG_COLOR_TYPE_GRAY) { - alpha = 1; + surface[i] = init_display_surface(width, height / *frames); + if (surface[i] == NULL) { + result = -8; + goto exit; + } } - png_uint_32 y; - if (channels == 3 || (channels == 1 && !alpha)) { - for (y = 0; y < height; ++y) { - int fy = y / *frames; - int fr = y % *frames; - unsigned char* pRow = surface[fr]->data + fy * 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 r = pRow[sx]; - unsigned char g = pRow[sx + 1]; - 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 + 3] = a; - } - } - } else { - for (y = 0; y < height; ++y) { - int fy = y / *frames; - int fr = y % *frames; - unsigned char* pRow = surface[fr]->data + fy * stride; - png_read_row(png_ptr, pRow, NULL); - } + unsigned char* p_row = malloc(width * 4); + unsigned int y; + for (y = 0; y < height; ++y) { + png_read_row(png_ptr, p_row, NULL); + int frame = y % *frames; + unsigned char* out_row = surface[frame]->data + + (y / *frames) * surface[frame]->row_bytes; + transform_rgb_to_draw(p_row, out_row, channels, width); } + free(p_row); *pSurface = (gr_surface*) surface; exit: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - if (fp != NULL) { - fclose(fp); - } if (result < 0) { if (surface) { for (i = 0; i < *frames; ++i) { @@ -329,7 +305,50 @@ exit: return result; } -static int matches_locale(const char* loc) { +int res_create_alpha_surface(const char* name, gr_surface* pSurface) { + gr_surface surface = NULL; + int result = 0; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_uint_32 width, height; + png_byte channels; + + *pSurface = NULL; + + result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); + if (result < 0) return result; + + if (channels != 1) { + result = -7; + goto exit; + } + + surface = malloc_surface(width * height); + if (surface == NULL) { + result = -8; + goto exit; + } + surface->width = width; + surface->height = height; + surface->row_bytes = width; + surface->pixel_bytes = 1; + + unsigned char* p_row; + unsigned int y; + for (y = 0; y < height; ++y) { + p_row = surface->data + y * surface->row_bytes; + png_read_row(png_ptr, p_row, NULL); + } + + *pSurface = surface; + + exit: + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + if (result < 0 && surface != NULL) free(surface); + return result; +} + +static int matches_locale(const char* loc, const char* locale) { if (locale == NULL) return 0; if (strcmp(loc, locale) == 0) return 1; @@ -346,70 +365,35 @@ static int matches_locale(const char* loc) { return (strncmp(locale, loc, i) == 0 && locale[i] == '_'); } -int res_create_localized_surface(const char* name, gr_surface* pSurface) { - char resPath[256]; +int res_create_localized_alpha_surface(const char* name, + const char* locale, + gr_surface* pSurface) { gr_surface surface = NULL; int result = 0; - unsigned char header[8]; png_structp png_ptr = NULL; png_infop info_ptr = NULL; + png_uint_32 width, height; + png_byte channels; *pSurface = NULL; - snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); - resPath[sizeof(resPath)-1] = '\0'; - FILE* fp = fopen(resPath, "rb"); - if (fp == NULL) { - result = -1; - goto exit; - } - - size_t bytesRead = fread(header, 1, sizeof(header), fp); - if (bytesRead != sizeof(header)) { - result = -2; - goto exit; - } - - if (png_sig_cmp(header, 0, sizeof(header))) { - result = -3; - goto exit; - } - - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) { - result = -4; - goto exit; - } - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - result = -5; - goto exit; - } - - if (setjmp(png_jmpbuf(png_ptr))) { - result = -6; + if (locale == NULL) { + surface = malloc_surface(0); + surface->width = 0; + surface->height = 0; + surface->row_bytes = 0; + surface->pixel_bytes = 1; goto exit; } - png_init_io(png_ptr, fp); - png_set_sig_bytes(png_ptr, sizeof(header)); - png_read_info(png_ptr, info_ptr); - - int color_type, bit_depth; - png_uint_32 width, height; - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, - &color_type, NULL, NULL, NULL); - int channels = png_get_channels(png_ptr, info_ptr); + result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); + if (result < 0) return result; - if (!(bit_depth <= 8 && - (channels == 1 && color_type == PNG_COLOR_TYPE_GRAY))) { - return -7; + if (channels != 1) { + result = -7; goto exit; } - png_set_expand(png_ptr); - unsigned char* row = malloc(width); png_uint_32 y; for (y = 0; y < height; ++y) { @@ -419,7 +403,7 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { int len = row[4]; char* loc = (char*)row+5; - if (y+1+h >= height || matches_locale(loc)) { + if (y+1+h >= height || matches_locale(loc, locale)) { printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y); surface = malloc_surface(w*h); @@ -427,8 +411,6 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { result = -8; goto exit; } - unsigned char* pData = surface->data; - surface->width = w; surface->height = h; surface->row_bytes = w; @@ -437,7 +419,7 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { int i; for (i = 0; i < h; ++i, ++y) { png_read_row(png_ptr, row, NULL); - memcpy(pData + i*w, row, w); + memcpy(surface->data + i*w, row, w); } *pSurface = (gr_surface) surface; @@ -452,15 +434,7 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { exit: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - - if (fp != NULL) { - fclose(fp); - } - if (result < 0) { - if (surface) { - free(surface); - } - } + if (result < 0 && surface != NULL) free(surface); return result; } -- cgit v1.2.3 From a388a769760af4d8999558f38f81dafa63cc0bfb Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Mon, 17 Mar 2014 16:51:47 -0700 Subject: fix error log statement We were printing the address of channels instead of the value there. Change-Id: I652340c7c1a0abaf01af555e54d2c0366d21ad78 --- minui/resources.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'minui/resources.c') diff --git a/minui/resources.c b/minui/resources.c index 69fd14bee..a0c621b71 100644 --- a/minui/resources.c +++ b/minui/resources.c @@ -110,7 +110,7 @@ static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr, *channels = 3; } else { fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n", - bit_depth, (int) channels, color_type); + bit_depth, *channels, color_type); result = -7; goto exit; } -- cgit v1.2.3 From 577a1304352c12d968c11a667f50cd45498cae17 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Thu, 20 Mar 2014 08:27:01 -0700 Subject: restore minui support for paletted images with < 8 bits The PNG image loaders should support images that use palettes requiring fewer than 8 bits. Change-Id: Ibcb0ff6f04aea8de54b03c0efa7a79e9b3635146 --- minui/resources.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'minui/resources.c') diff --git a/minui/resources.c b/minui/resources.c index a0c621b71..2bae4ded0 100644 --- a/minui/resources.c +++ b/minui/resources.c @@ -101,7 +101,7 @@ static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr, } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) { // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. png_set_expand_gray_1_2_4_to_8(*png_ptr); - } else if (bit_depth == 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) { + } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) { // paletted images: expand to 8-bit RGB. Note that we DON'T // currently expand the tRNS chunk (if any) to an alpha // channel, because minui doesn't support alpha channels in -- cgit v1.2.3