From e02ff26569e34afd743d679bd1775cbc2fd608fd Mon Sep 17 00:00:00 2001 From: Seven Du Date: Sun, 15 Feb 2015 13:49:43 +0800 Subject: [PATCH] FS-7500: libpng 1.6.0 has much simpler APIs, also add a new switch_img_patch_png to possible patch a transparent png to an img While this is not optimal, we should cache the png: 1) cache the whole buffer, with comes with RGBARGBA pixel formats 2) Allow switch_image_t to be other formats e.g. VPX_IMG_FMT_ARGB, VPX_IMG_FMT_ARGB_LE, or VPX_IMG_FMT_444A those can have alpha channels so we can check the alpha channel before we patch Note all PNG are created equel, or maybe a bug in libpng since for some PNG files with alpha the returned buffer not seems like RGBARGBA... while docs says it should default be RGBA --- src/include/switch_core_video.h | 1 + src/switch_core_video.c | 141 ++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) diff --git a/src/include/switch_core_video.h b/src/include/switch_core_video.h index 6101fe2a3e..4b92ae8b45 100644 --- a/src/include/switch_core_video.h +++ b/src/include/switch_core_video.h @@ -210,6 +210,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_txt_handle_render(switch_img_txt_hand SWITCH_DECLARE(void) switch_img_patch_hole(switch_image_t *IMG, switch_image_t *img, int x, int y, switch_image_rect_t *rect); SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name); SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char* file_name); +SWITCH_DECLARE(switch_status_t) switch_img_patch_png(switch_image_t *img, int x, int y, const char *file_name); SWITCH_DECLARE(void) switch_img_get_yuv_pixel(switch_image_t *img, switch_yuv_color_t *yuv, int x, int y); diff --git a/src/switch_core_video.c b/src/switch_core_video.c index 5a556451cd..f700be8022 100644 --- a/src/switch_core_video.c +++ b/src/switch_core_video.c @@ -722,6 +722,109 @@ SWITCH_DECLARE(void) switch_img_patch_hole(switch_image_t *IMG, switch_image_t * #define PNG_SKIP_SETJMP_CHECK #include +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* available from libpng 1.6.0 */ + +SWITCH_DECLARE(switch_status_t) switch_img_patch_png(switch_image_t *img, int x, int y, const char *file_name) +{ + png_image png = { 0 }; + png_bytep buffer = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_rgb_color_t *rgb_color; + switch_yuv_color_t yuv_color; + uint8_t alpha; + int i, j; + + png.version = PNG_IMAGE_VERSION; + + if (!png_image_begin_read_from_file(&png, file_name)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read PNG %s\n", file_name); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + + // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "png format: %d, size: %dx%d\n", png.format, png.width, png.height); + // if (png.format | PNG_FORMAT_FLAG_ALPHA) { + // printf("Alpha\n"); + // } + + png.format = PNG_FORMAT_RGBA; + + buffer = malloc(PNG_IMAGE_SIZE(png)); + switch_assert(buffer); + + if (!png_image_finish_read(&png, NULL/*background*/, buffer, 0, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read PNG %s\n", file_name); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + + for (i = 0; i < png.height; i++) { + for (j = 0; j < png.width; j++) { + alpha = buffer[i * png.width * 4 + j * 4 + 3]; + // printf("%d, %d alpha: %d\n", j, i, alpha); + + if (alpha) { // todo, mux alpha with the underlying pixel + rgb_color = (switch_rgb_color_t *)(buffer + i * png.width * 4 + j * 4); + switch_color_rgb2yuv(rgb_color, &yuv_color); + switch_img_draw_pixel(img, x + j, i, &yuv_color); + } + } + } + +end: + png_image_free(&png); + switch_safe_free(buffer); + return status; +} + +SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name) +{ + png_image png = { 0 }; + png_bytep buffer = NULL; + switch_image_t *img = NULL; + + png.version = PNG_IMAGE_VERSION; + + if (!png_image_begin_read_from_file(&png, file_name)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error open png: %s\n", file_name); + goto err; + } + + png.format = PNG_FORMAT_RGB; + buffer = malloc(PNG_IMAGE_SIZE(png)); + switch_assert(buffer); + + if (!png_image_finish_read(&png, NULL/*background*/, buffer, 0, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read png: %s\n", file_name); + goto err; + } + + if (png.width > SWITCH_IMG_MAX_WIDTH || png.height > SWITCH_IMG_MAX_HEIGHT) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PNG is too large! %dx%d\n", png.width, png.height); + goto err; + } + + img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, png.width, png.height, 1); + switch_assert(img); + + RAWToI420(buffer, png.width * 3, + img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y], + img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U], + img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V], + png.width, png.height); + +err: + png_image_free(&png); + switch_safe_free(buffer); + return img; +} + +#else /* libpng < 1.6.0 */ + +SWITCH_DECLARE(switch_status_t) switch_img_patch_png(switch_image_t *img, int x, int y, const char *file_name) +{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This function is not implemented on libpng < 1.6.0\n"); + return SWITCH_STATUS_FALSE; +} + // ref: most are out-dated, man libpng :) // http://zarb.org/~gc/html/libpng.html // http://www.libpng.org/pub/png/book/toc.html @@ -958,6 +1061,42 @@ end: return img; } +#endif + + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED /* available from libpng 1.6.0 */ + +SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char* file_name) +{ + png_image png = { 0 }; + png_bytep buffer = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + + buffer = malloc(img->d_w * img->d_h * 3); + switch_assert(buffer); + + I420ToRAW( img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y], + img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U], + img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V], + buffer, img->d_w * 3, + img->d_w, img->d_h); + + png.version = PNG_IMAGE_VERSION; + png.format = PNG_FORMAT_RGB; + png.width = img->d_w; + png.height = img->d_h; + + if (!png_image_write_to_file(&png, file_name, 0, buffer, 0, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error write PNG %s\n", file_name); + status = SWITCH_STATUS_FALSE; + } + + switch_safe_free(buffer); + return status; +} + +#else + SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char* file_name) { int width, height; @@ -1063,6 +1202,8 @@ end: return status; } +#endif + SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width, int height) { switch_image_t *src, *tmp = NULL;