From 2448d32c0fc63f1971acdb397f23b12787f5e7e3 Mon Sep 17 00:00:00 2001 From: Seven Du Date: Wed, 6 Mar 2019 12:00:15 +0800 Subject: [PATCH] [core] add jpg data_url support with stb_image --- src/include/switch_core_video.h | 3 +- src/switch_core_video.c | 84 +++++++++++++++++++++++++++++++++ tests/unit/switch_core_video.c | 26 ++++++++++ 3 files changed, 112 insertions(+), 1 deletion(-) diff --git a/src/include/switch_core_video.h b/src/include/switch_core_video.h index 4fb7d824c0..1af0dec7ac 100644 --- a/src/include/switch_core_video.h +++ b/src/include/switch_core_video.h @@ -395,13 +395,14 @@ SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char * SWITCH_DECLARE(switch_status_t) switch_png_open(switch_png_t **pngP, const char *file_name); SWITCH_DECLARE(void) switch_png_free(switch_png_t **pngP); SWITCH_DECLARE(switch_status_t) switch_img_data_url_png(switch_image_t *img, char **urlP); +SWITCH_DECLARE(switch_status_t) switch_img_data_url(switch_image_t *img, char **urlP, const char *type, int quality); /*!\brief Read an image file to switch_image_t */ SWITCH_DECLARE(switch_image_t *) switch_img_read_from_file(const char *file_name, switch_img_fmt_t img_fmt); /*!\brief Write an image file, supported formats png,jpg,bmp,tga,hdr * \param[in] img The image descriptor * \param[in] file_name The file_name to write -* \param[in] quality Only used in jpg, 0 ~ 100 +* \param[in] quality Only used in jpg, 1 ~ 100 */ SWITCH_DECLARE(switch_status_t) switch_img_write_to_file(switch_image_t *img, const char* file_name, int quality); diff --git a/src/switch_core_video.c b/src/switch_core_video.c index ee44223f64..6a9351cdaa 100644 --- a/src/switch_core_video.c +++ b/src/switch_core_video.c @@ -3211,6 +3211,90 @@ SWITCH_DECLARE(switch_status_t) switch_img_write_to_file(switch_image_t *img, co return ret ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; } +typedef struct data_url_context_s { + const char *type; + char **urlP; +} data_url_context_t; + +static void data_url_write_func(void *context, void *data, int size) +{ + switch_buffer_t *buffer = (switch_buffer_t *)context; + switch_buffer_write(buffer, data, size); +} + +SWITCH_DECLARE(switch_status_t) switch_img_data_url(switch_image_t *img, char **urlP, const char *type, int quality) +{ + int comp = STBI_rgb; + unsigned char *data = NULL; + int stride_in_bytes = 0; + int ret = 0; + switch_buffer_t *buffer = NULL; + const char *header = NULL; + int header_len = 0; + + if (!type) return SWITCH_STATUS_FALSE; + + if (img->fmt == SWITCH_IMG_FMT_I420) { + comp = STBI_rgb; + stride_in_bytes = img->d_w * 3; + + data = malloc(stride_in_bytes * img->d_h); + switch_assert(data); + + 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], + data, stride_in_bytes, + img->d_w, img->d_h); + } else if (img->fmt == SWITCH_IMG_FMT_ARGB) { + comp = STBI_rgb_alpha; + stride_in_bytes = img->d_w * 4; + + data = malloc(stride_in_bytes * img->d_h); + switch_assert(data); + +#if SWITCH_BYTE_ORDER == __BIG_ENDIAN + ARGBToRGBA(img->planes[SWITCH_PLANE_PACKED], stride_in_bytes, data, stride_in_bytes, img->d_w, img->d_h); +#else + ARGBToABGR(img->planes[SWITCH_PLANE_PACKED], stride_in_bytes, data, stride_in_bytes, img->d_w, img->d_h); +#endif + } else { + return SWITCH_STATUS_FALSE; + } + + switch_buffer_create_dynamic(&buffer, 1024, 1024, 0); + + if (!strcmp(type, "png")) { + header = "data:image/png;base64,"; + ret = stbi_write_png_to_func(data_url_write_func, (void *)buffer, img->d_w, img->d_h, comp, (const void *)data, stride_in_bytes); + } else if (!strcmp(type, "jpeg") || !strcmp(type, "jpeg")) { + header = "data:image/jpeg;base64,"; + ret = stbi_write_jpg_to_func(data_url_write_func, (void *)buffer, img->d_w, img->d_h, comp, (const void *)data, quality); + } else { + ret = 0; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unsupported file format [%s]\n", type); + } + + if (ret && switch_buffer_inuse(buffer) > 0) { + switch_size_t blen = switch_buffer_inuse(buffer); + switch_size_t olen = blen * 4 + strlen(header) + 1; + uint8_t *data = switch_buffer_get_head_pointer(buffer); + unsigned char *out = NULL; + + switch_zmalloc(out, olen); + header_len = strlen(header); + memcpy(out, header, header_len); + switch_b64_encode(data, blen, out + header_len, olen - header_len); + *urlP = (char *)out; + } + + free(data); + switch_buffer_destroy(&buffer); + + return ret ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; +} + + SWITCH_DECLARE(switch_status_t) switch_img_letterbox(switch_image_t *img, switch_image_t **imgP, int width, int height, const char *color) { int img_w = 0, img_h = 0; diff --git a/tests/unit/switch_core_video.c b/tests/unit/switch_core_video.c index 219a0acb63..ec30a43a05 100644 --- a/tests/unit/switch_core_video.c +++ b/tests/unit/switch_core_video.c @@ -200,6 +200,32 @@ FST_CORE_BEGIN("./conf") } FST_TEST_END() + FST_TEST_BEGIN(stb_data_url) + { + switch_image_t *img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, 120, 60, 1); + switch_image_t *argb_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_ARGB, 120, 60, 1); + switch_rgb_color_t color = { 0 }; + color.r = 255; + // color.g = 255; + // color.b = 255; + char *data_url = NULL; + + switch_img_fill(img, 0, 0, img->d_w, img->d_h, &color); + switch_img_add_text(img->planes[0], img->d_w, 10, 10, "-1234567890"); + + switch_img_data_url(img, &data_url, "png", 0); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "PNG: %s\n", data_url); + free(data_url); + data_url = NULL; + + switch_img_data_url(img, &data_url, "jpeg", 50); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "JPG: %s\n", data_url); + + free(data_url); + switch_img_free(&img); + } + FST_TEST_END() + FST_TEST_BEGIN(read_from_file) { switch_image_t *img;