]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7500: libpng 1.6.0 has much simpler APIs, also add a new switch_img_patch_png...
authorSeven Du <dujinfang@gmail.com>
Sun, 15 Feb 2015 05:49:43 +0000 (13:49 +0800)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:47:02 +0000 (12:47 -0500)
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
src/switch_core_video.c

index 6101fe2a3efba7a7d17daf326bdb8c769ad5f3b7..4b92ae8b4594698a8cd766ed51fe1e350b3c4600 100644 (file)
@@ -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);
 
index 5a556451cd785790c1feeeabfa0716b19989a064..f700be80221bc4a35044d0f81f2335fbacb31b05 100644 (file)
@@ -722,6 +722,109 @@ SWITCH_DECLARE(void) switch_img_patch_hole(switch_image_t *IMG, switch_image_t *
 #define PNG_SKIP_SETJMP_CHECK
 #include <png.h>
 
+#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;