2014-08-03 19:13:24 +00:00
|
|
|
/*
|
|
|
|
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
|
|
|
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
|
|
|
|
*
|
|
|
|
* Version: MPL 1.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Seven Du <dujinfang@gmail.com>
|
|
|
|
* Portions created by the Initial Developer are Copyright (C)
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
2015-02-11 20:07:06 +00:00
|
|
|
* Anthony Minessale II <anthm@freeswitch.org>
|
2014-08-03 19:13:24 +00:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* switch_core_video.c -- Core Video
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <switch.h>
|
2015-02-11 20:07:06 +00:00
|
|
|
#include <switch_utf8.h>
|
2014-08-03 19:13:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
SWITCH_DECLARE(switch_image_t *)switch_img_alloc(switch_image_t *img,
|
|
|
|
switch_img_fmt_t fmt,
|
|
|
|
unsigned int d_w,
|
|
|
|
unsigned int d_h,
|
|
|
|
unsigned int align)
|
|
|
|
{
|
|
|
|
return (switch_image_t *)vpx_img_alloc((vpx_image_t *)img, (vpx_img_fmt_t)fmt, d_w, d_h, align);
|
|
|
|
}
|
|
|
|
|
|
|
|
SWITCH_DECLARE(switch_image_t *)switch_img_wrap(switch_image_t *img,
|
|
|
|
switch_img_fmt_t fmt,
|
|
|
|
unsigned int d_w,
|
|
|
|
unsigned int d_h,
|
|
|
|
unsigned int align,
|
|
|
|
unsigned char *img_data)
|
|
|
|
{
|
|
|
|
return (switch_image_t *)vpx_img_wrap((vpx_image_t *)img, (vpx_img_fmt_t)fmt, d_w, d_h, align, img_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
SWITCH_DECLARE(int) switch_img_set_rect(switch_image_t *img,
|
|
|
|
unsigned int x,
|
|
|
|
unsigned int y,
|
|
|
|
unsigned int w,
|
|
|
|
unsigned int h)
|
|
|
|
{
|
|
|
|
return vpx_img_set_rect((vpx_image_t *)img, x, y, w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
SWITCH_DECLARE(void) switch_img_flip(switch_image_t *img)
|
|
|
|
{
|
|
|
|
vpx_img_flip((vpx_image_t *)img);
|
|
|
|
}
|
|
|
|
|
2014-11-25 21:01:52 +00:00
|
|
|
SWITCH_DECLARE(void) switch_img_free(switch_image_t **img)
|
2014-08-03 19:13:24 +00:00
|
|
|
{
|
2014-11-25 21:01:52 +00:00
|
|
|
if (img && *img) {
|
|
|
|
vpx_img_free((vpx_image_t *)*img);
|
2015-01-29 00:42:17 +00:00
|
|
|
*img = NULL;
|
2014-11-25 21:01:52 +00:00
|
|
|
}
|
2014-08-03 19:13:24 +00:00
|
|
|
}
|
|
|
|
|
2015-02-08 01:23:47 +00:00
|
|
|
#ifndef MIN
|
|
|
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
|
|
#endif
|
|
|
|
|
2015-02-05 02:23:17 +00:00
|
|
|
// simple implementation to patch a small img to a big IMG at position x,y
|
|
|
|
SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y)
|
|
|
|
{
|
2015-02-08 01:23:47 +00:00
|
|
|
int i, len;
|
2015-02-05 02:23:17 +00:00
|
|
|
|
|
|
|
switch_assert(img->fmt == SWITCH_IMG_FMT_I420);
|
|
|
|
switch_assert(IMG->fmt == SWITCH_IMG_FMT_I420);
|
|
|
|
|
2015-02-08 01:23:47 +00:00
|
|
|
len = MIN(img->d_w, IMG->d_w - x);
|
|
|
|
if (len <= 0) return;
|
2015-02-05 02:23:17 +00:00
|
|
|
|
2015-02-08 01:23:47 +00:00
|
|
|
for (i = y; i < (y + img->d_h) && i < IMG->d_h; i++) {
|
|
|
|
memcpy(IMG->planes[SWITCH_PLANE_Y] + IMG->stride[SWITCH_PLANE_Y] * i + x, img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * (i - y), len);
|
2015-02-05 02:23:17 +00:00
|
|
|
}
|
|
|
|
|
2015-02-08 01:23:47 +00:00
|
|
|
len /= 2;
|
2015-02-05 02:23:17 +00:00
|
|
|
|
2015-02-08 01:23:47 +00:00
|
|
|
for (i = y; i < (y + img->d_h) && i < IMG->d_h; i += 2) {
|
|
|
|
memcpy(IMG->planes[SWITCH_PLANE_U] + IMG->stride[SWITCH_PLANE_U] * i / 2 + x / 2, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * (i - y) / 2, len);
|
|
|
|
memcpy(IMG->planes[SWITCH_PLANE_V] + IMG->stride[SWITCH_PLANE_V] * i / 2 + x / 2, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * (i - y) / 2, len);
|
|
|
|
}
|
|
|
|
}
|
2015-02-05 02:23:17 +00:00
|
|
|
|
2015-01-17 17:32:17 +00:00
|
|
|
SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_img)
|
|
|
|
{
|
2015-02-05 02:23:17 +00:00
|
|
|
int i = 0;
|
2015-01-28 03:14:51 +00:00
|
|
|
|
2015-01-17 17:32:17 +00:00
|
|
|
switch_assert(img);
|
2015-01-28 00:21:19 +00:00
|
|
|
switch_assert(new_img);
|
2015-01-17 17:32:17 +00:00
|
|
|
|
|
|
|
if (!img->fmt == SWITCH_IMG_FMT_I420) return;
|
|
|
|
|
2015-01-28 00:21:19 +00:00
|
|
|
if (*new_img != NULL) {
|
|
|
|
if (img->d_w != (*new_img)->d_w || img->d_h != (*new_img)->d_w) {
|
|
|
|
switch_img_free(new_img);
|
|
|
|
}
|
2015-01-17 17:32:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (*new_img == NULL) {
|
2015-01-28 01:58:05 +00:00
|
|
|
*new_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, img->d_w, img->d_h, 1);
|
2015-01-17 17:32:17 +00:00
|
|
|
}
|
2015-01-28 08:41:36 +00:00
|
|
|
|
2015-01-17 17:32:17 +00:00
|
|
|
switch_assert(*new_img);
|
2015-01-28 01:58:05 +00:00
|
|
|
|
2015-01-28 08:41:36 +00:00
|
|
|
for (i = 0; i < (*new_img)->h; i++) {
|
|
|
|
memcpy((*new_img)->planes[SWITCH_PLANE_Y] + (*new_img)->stride[SWITCH_PLANE_Y] * i, img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * i, img->d_w);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < (*new_img)->h / 2; i++) {
|
2015-01-28 16:52:21 +00:00
|
|
|
memcpy((*new_img)->planes[SWITCH_PLANE_U] + (*new_img)->stride[SWITCH_PLANE_U] * i, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * i, img->d_w / 2);
|
|
|
|
memcpy((*new_img)->planes[SWITCH_PLANE_V] + (*new_img)->stride[SWITCH_PLANE_V] * i, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * i, img->d_w /2);
|
2015-01-28 01:58:05 +00:00
|
|
|
}
|
2015-02-05 02:23:17 +00:00
|
|
|
|
2015-01-17 17:32:17 +00:00
|
|
|
}
|
|
|
|
|
2015-02-10 03:30:31 +00:00
|
|
|
SWITCH_DECLARE(switch_image_t *) switch_img_copy_rect(switch_image_t *img, int x, int y, int w, int h)
|
|
|
|
{
|
|
|
|
switch_image_t *new_img = NULL;
|
|
|
|
int i = 0;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
switch_assert(img);
|
|
|
|
switch_assert(x >= 0 && y >= 0 && w >= 0 && h >= 0);
|
|
|
|
|
|
|
|
if (!img->fmt == SWITCH_IMG_FMT_I420) return NULL;
|
|
|
|
|
|
|
|
new_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, w, h, 1);
|
|
|
|
if (new_img == NULL) return NULL;
|
|
|
|
|
|
|
|
len = MIN(img->d_w - x, w);
|
|
|
|
if (len <= 0) return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < (img->d_h - y) && i < h; i++) {
|
|
|
|
memcpy(new_img->planes[SWITCH_PLANE_Y] + new_img->stride[SWITCH_PLANE_Y] * i, img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * (y + i) + x, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
len /= 2;
|
|
|
|
|
|
|
|
for (i = 0; i < (img->d_h - y) && i < h; i += 2) {
|
|
|
|
memcpy(new_img->planes[SWITCH_PLANE_U] + new_img->stride[SWITCH_PLANE_U] * i / 2, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * (y + i) / 2 + x / 2, len);
|
|
|
|
memcpy(new_img->planes[SWITCH_PLANE_V] + new_img->stride[SWITCH_PLANE_V] * i / 2, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * (y + i) / 2 + x / 2, len);
|
|
|
|
}
|
|
|
|
return new_img;
|
|
|
|
}
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
SWITCH_DECLARE(void) switch_img_draw_pixel(switch_image_t *img, int x, int y, switch_yuv_color_t *color)
|
2015-02-10 03:30:31 +00:00
|
|
|
{
|
|
|
|
if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
img->planes[SWITCH_PLANE_Y][y * img->stride[SWITCH_PLANE_Y] + x] = color->y;
|
2015-02-10 03:30:31 +00:00
|
|
|
|
|
|
|
if (((x & 0x1) == 0) && ((y & 0x1) == 0)) {// only draw on even position
|
2015-02-12 07:03:45 +00:00
|
|
|
img->planes[SWITCH_PLANE_U][y / 2 * img->stride[SWITCH_PLANE_U] + x / 2] = color->u;
|
|
|
|
img->planes[SWITCH_PLANE_V][y / 2 * img->stride[SWITCH_PLANE_V] + x / 2] = color->v;
|
2015-02-10 03:30:31 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-06 17:41:15 +00:00
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
SWITCH_DECLARE(void) switch_img_fill(switch_image_t *img, int x, int y, int w, int h, switch_rgb_color_t *color)
|
2015-02-11 06:57:02 +00:00
|
|
|
{
|
|
|
|
int len, i;
|
2015-02-12 07:03:45 +00:00
|
|
|
switch_yuv_color_t yuv_color;
|
2015-02-11 06:57:02 +00:00
|
|
|
|
|
|
|
if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
switch_color_rgb2yuv(color, &yuv_color);
|
|
|
|
|
2015-02-11 06:57:02 +00:00
|
|
|
len = MIN(w, img->d_w - x);
|
|
|
|
if (len <= 0) return;
|
|
|
|
|
|
|
|
for (i = y; i < (y + h) && i < img->d_h; i++) {
|
2015-02-12 07:03:45 +00:00
|
|
|
memset(img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * i + x, yuv_color.y, len);
|
2015-02-11 06:57:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
len /= 2;
|
|
|
|
|
|
|
|
for (i = y; i < (y + h) && i < img->d_h; i += 2) {
|
2015-02-12 07:03:45 +00:00
|
|
|
memset(img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * i / 2 + x / 2, yuv_color.u, len);
|
|
|
|
memset(img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * i / 2 + x / 2, yuv_color.v, len);
|
2015-02-11 06:57:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-06 17:41:15 +00:00
|
|
|
static uint8_t scv_art[14][16] = {
|
|
|
|
{0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00},
|
|
|
|
{0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00},
|
|
|
|
{0x00, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7E, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00},
|
|
|
|
{0x00, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7E, 0x00},
|
|
|
|
{0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00},
|
|
|
|
{0x00, 0x7E, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7E, 0x00},
|
|
|
|
{0x00, 0x7E, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00},
|
|
|
|
{0x00, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00},
|
|
|
|
{0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00},
|
|
|
|
{0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7E, 0x00},
|
|
|
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00}, /*.*/
|
|
|
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*:*/
|
|
|
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*-*/
|
|
|
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* */
|
|
|
|
};
|
|
|
|
|
|
|
|
static void scv_tag(void *buffer, int w, int x, int y, uint8_t n)
|
|
|
|
{
|
|
|
|
int i = 0, j=0;
|
|
|
|
uint8_t *p = buffer;
|
|
|
|
|
|
|
|
if (n < 0 || n > 13) return;
|
|
|
|
|
|
|
|
for(i=0; i<8; i++) {
|
|
|
|
for (j=0; j<16; j++) {
|
|
|
|
*( p + (y + j) * w + (x + i)) = (scv_art[n][j] & 0x80 >> i) ? 0xFF : 0x00;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SWITCH_DECLARE(void) switch_img_add_text(void *buffer, int w, int x, int y, char *s)
|
|
|
|
{
|
|
|
|
while (*s) {
|
|
|
|
int index;
|
|
|
|
|
|
|
|
if (x > w - 8) break;
|
|
|
|
|
|
|
|
switch (*s) {
|
|
|
|
case '.': index = 10; break;
|
|
|
|
case ':': index = 11; break;
|
|
|
|
case '-': index = 12; break;
|
|
|
|
case ' ': index = 13; break;
|
|
|
|
default:
|
|
|
|
index = *s - 0x30;
|
|
|
|
}
|
|
|
|
|
|
|
|
scv_tag(buffer, w, x, y, index);
|
|
|
|
x += 8;
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
SWITCH_DECLARE(void) switch_color_set_rgb(switch_rgb_color_t *color, const char *str)
|
2015-02-10 03:30:31 +00:00
|
|
|
{
|
2015-02-12 07:03:45 +00:00
|
|
|
if (zstr(str)) return;
|
|
|
|
|
|
|
|
if ((*str) == '#' && strlen(str) == 7) {
|
|
|
|
unsigned int r, g, b;
|
|
|
|
sscanf(str, "#%02x%02x%02x", &r, &g, &b);
|
|
|
|
color->r = r;
|
|
|
|
color->g = g;
|
|
|
|
color->b = b;
|
|
|
|
} else {
|
|
|
|
if (!strcmp(str, "red")) {
|
|
|
|
color->r = 255;
|
|
|
|
color->g = 0;
|
|
|
|
color->b = 0;
|
|
|
|
} else if (!strcmp(str, "green")) {
|
|
|
|
color->r = 0;
|
|
|
|
color->g = 255;
|
|
|
|
color->b = 0;
|
|
|
|
} else if (!strcmp(str, "blue")) {
|
|
|
|
color->r = 0;
|
|
|
|
color->g = 0;
|
|
|
|
color->b = 255;
|
2015-02-11 20:07:06 +00:00
|
|
|
}
|
2015-02-10 03:30:31 +00:00
|
|
|
}
|
2015-02-12 07:03:45 +00:00
|
|
|
}
|
2015-02-10 03:30:31 +00:00
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
SWITCH_DECLARE(void) switch_color_rgb2yuv(switch_rgb_color_t *rgb, switch_yuv_color_t *yuv)
|
|
|
|
{
|
|
|
|
yuv->y = (uint8_t)(((rgb->r * 4897) >> 14) + ((rgb->g * 9611) >> 14) + ((rgb->b * 1876) >> 14));
|
|
|
|
yuv->u = (uint8_t)(- ((rgb->r * 2766) >> 14) - ((5426 * rgb->g) >> 14) + rgb->b / 2 + 128);
|
|
|
|
yuv->v = (uint8_t)(rgb->r / 2 -((6855 * rgb->b) >> 14) - ((rgb->b * 1337) >> 14) + 128);
|
|
|
|
}
|
|
|
|
|
|
|
|
SWITCH_DECLARE(void) switch_color_set_yuv(switch_yuv_color_t *color, const char *str)
|
|
|
|
{
|
|
|
|
switch_rgb_color_t rgb = { 0 };
|
|
|
|
|
|
|
|
switch_color_set_rgb(&rgb, str);
|
|
|
|
switch_color_rgb2yuv(&rgb, color);
|
2015-02-10 03:30:31 +00:00
|
|
|
}
|
2015-02-06 17:41:15 +00:00
|
|
|
|
2015-02-11 20:07:06 +00:00
|
|
|
#include <ft2build.h>
|
|
|
|
#include FT_FREETYPE_H
|
|
|
|
#include FT_GLYPH_H
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
#define MAX_GRADIENT 8
|
|
|
|
|
2015-02-11 20:07:06 +00:00
|
|
|
struct switch_img_txt_handle_s {
|
|
|
|
FT_Library library;
|
|
|
|
FT_Face face;
|
|
|
|
char *font_family;
|
|
|
|
double angle;
|
|
|
|
uint16_t font_size;
|
2015-02-12 07:03:45 +00:00
|
|
|
switch_rgb_color_t color;
|
|
|
|
switch_rgb_color_t bgcolor;
|
2015-02-11 20:07:06 +00:00
|
|
|
switch_image_t *img;
|
|
|
|
switch_memory_pool_t *pool;
|
|
|
|
int free_pool;
|
2015-02-12 07:03:45 +00:00
|
|
|
switch_yuv_color_t gradient_table[MAX_GRADIENT];
|
|
|
|
switch_bool_t use_bgcolor;
|
2015-02-11 20:07:06 +00:00
|
|
|
};
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
static void init_gradient_table(switch_img_txt_handle_t *handle)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
switch_rgb_color_t color;
|
|
|
|
|
|
|
|
switch_rgb_color_t *c1 = &handle->bgcolor;
|
|
|
|
switch_rgb_color_t *c2 = &handle->color;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_GRADIENT; i++) {
|
|
|
|
color.r = c1->r + (c2->r - c1->r) * i / MAX_GRADIENT;
|
|
|
|
color.g = c1->g + (c2->g - c1->g) * i / MAX_GRADIENT;
|
|
|
|
color.b = c1->b + (c2->b - c1->b) * i / MAX_GRADIENT;
|
|
|
|
|
|
|
|
switch_color_rgb2yuv(&color, &handle->gradient_table[i]);
|
|
|
|
}
|
|
|
|
}
|
2015-02-11 20:07:06 +00:00
|
|
|
|
2015-02-12 03:38:37 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_img_txt_handle_create(switch_img_txt_handle_t **handleP, const char *font_family,
|
2015-02-12 07:03:45 +00:00
|
|
|
const char *font_color, const char *bgcolor, uint16_t font_size, double angle, switch_memory_pool_t *pool)
|
2015-02-11 20:07:06 +00:00
|
|
|
{
|
|
|
|
int free_pool = 0;
|
|
|
|
switch_img_txt_handle_t *new_handle;
|
|
|
|
|
|
|
|
if (!pool) {
|
|
|
|
free_pool = 1;
|
|
|
|
switch_core_new_memory_pool(&pool);
|
|
|
|
}
|
|
|
|
|
|
|
|
new_handle = switch_core_alloc(pool, sizeof(*new_handle));
|
|
|
|
|
|
|
|
if (FT_Init_FreeType(&new_handle->library)) {
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_handle->pool = pool;
|
|
|
|
new_handle->free_pool = free_pool;
|
|
|
|
new_handle->font_family = switch_core_strdup(new_handle->pool, font_family);
|
|
|
|
new_handle->font_size = font_size;
|
|
|
|
new_handle->angle = angle;
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
switch_color_set_rgb(&new_handle->color, font_color);
|
|
|
|
switch_color_set_rgb(&new_handle->bgcolor, bgcolor);
|
|
|
|
|
|
|
|
init_gradient_table(new_handle);
|
2015-02-12 03:38:37 +00:00
|
|
|
|
2015-02-11 20:07:06 +00:00
|
|
|
*handleP = new_handle;
|
|
|
|
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SWITCH_DECLARE(void) switch_img_txt_handle_destroy(switch_img_txt_handle_t **handleP)
|
|
|
|
{
|
|
|
|
switch_img_txt_handle_t *old_handle = *handleP;
|
|
|
|
switch_memory_pool_t *pool;
|
|
|
|
|
|
|
|
*handleP = NULL;
|
2015-02-12 03:38:37 +00:00
|
|
|
|
2015-02-11 20:07:06 +00:00
|
|
|
if (old_handle->library) {
|
|
|
|
FT_Done_FreeType(old_handle->library);
|
|
|
|
old_handle->library = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pool = old_handle->pool;
|
|
|
|
|
|
|
|
if (old_handle->free_pool) {
|
|
|
|
switch_core_destroy_memory_pool(&pool);
|
|
|
|
pool = NULL;
|
|
|
|
old_handle = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
static void draw_bitmap(switch_img_txt_handle_t *handle, switch_image_t *img, FT_Bitmap* bitmap, FT_Int x, FT_Int y)
|
2015-02-11 20:07:06 +00:00
|
|
|
{
|
|
|
|
FT_Int i, j, p, q;
|
|
|
|
FT_Int x_max = x + bitmap->width;
|
|
|
|
FT_Int y_max = y + bitmap->rows;
|
2015-02-12 07:03:45 +00:00
|
|
|
switch_yuv_color_t yuv_color;
|
2015-02-11 20:07:06 +00:00
|
|
|
|
2015-02-12 03:38:37 +00:00
|
|
|
if (bitmap->width == 0) return;
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
switch_color_rgb2yuv(&handle->color, &yuv_color);
|
|
|
|
|
2015-02-11 20:07:06 +00:00
|
|
|
switch (bitmap->pixel_mode) {
|
|
|
|
case FT_PIXEL_MODE_GRAY: // it should always be GRAY since we use FT_LOAD_RENDER?
|
|
|
|
break;
|
|
|
|
case FT_PIXEL_MODE_NONE:
|
|
|
|
case FT_PIXEL_MODE_MONO:
|
2015-02-12 07:03:45 +00:00
|
|
|
{
|
|
|
|
|
2015-02-12 03:38:37 +00:00
|
|
|
for ( j = y, q = 0; j < y_max; j++, q++ ) {
|
|
|
|
for ( i = x, p = 0; i < x_max; i++, p++ ) {
|
|
|
|
uint8_t byte;
|
|
|
|
int linesize = ((bitmap->width - 1) / 8 + 1) * 8;
|
|
|
|
|
|
|
|
if ( i < 0 || j < 0 || i >= img->d_w || j >= img->d_h) continue;
|
|
|
|
|
|
|
|
byte = bitmap->buffer[(q * linesize + p) / 8];
|
|
|
|
if ((byte >> (7 - (p % 8))) & 0x1) {
|
2015-02-12 07:03:45 +00:00
|
|
|
switch_img_draw_pixel(img, i, j, &yuv_color);
|
2015-02-12 03:38:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
2015-02-12 07:03:45 +00:00
|
|
|
}
|
2015-02-11 20:07:06 +00:00
|
|
|
case FT_PIXEL_MODE_GRAY2:
|
|
|
|
case FT_PIXEL_MODE_GRAY4:
|
|
|
|
case FT_PIXEL_MODE_LCD:
|
|
|
|
case FT_PIXEL_MODE_LCD_V:
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "unsupported pixel mode %d\n", bitmap->pixel_mode);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( i = x, p = 0; i < x_max; i++, p++ ) {
|
|
|
|
for ( j = y, q = 0; j < y_max; j++, q++ ) {
|
2015-02-12 07:03:45 +00:00
|
|
|
int gradient = bitmap->buffer[q * bitmap->width + p];
|
2015-02-11 20:07:06 +00:00
|
|
|
if ( i < 0 || j < 0 || i >= img->d_w || j >= img->d_h) continue;
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
if (handle->use_bgcolor) {
|
|
|
|
switch_img_draw_pixel(img, i, j, &handle->gradient_table[gradient * MAX_GRADIENT / 256]);
|
|
|
|
} else {
|
|
|
|
if (gradient > 128) {
|
|
|
|
switch_img_draw_pixel(img, i, j, &yuv_color);
|
|
|
|
}
|
2015-02-11 20:07:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-12 03:38:37 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_img_txt_handle_render(switch_img_txt_handle_t *handle, switch_image_t *img,
|
|
|
|
int x, int y, const char *text,
|
2015-02-12 07:03:45 +00:00
|
|
|
const char *font_family, const char *font_color, const char *bgcolor, uint16_t font_size, double angle)
|
2015-02-11 20:07:06 +00:00
|
|
|
{
|
|
|
|
FT_GlyphSlot slot;
|
|
|
|
FT_Matrix matrix; /* transformation matrix */
|
|
|
|
FT_Vector pen; /* untransformed origin */
|
|
|
|
FT_Error error;
|
2015-02-12 07:03:45 +00:00
|
|
|
//int target_height;
|
2015-02-11 20:07:06 +00:00
|
|
|
int index = 0;
|
|
|
|
FT_ULong ch;
|
|
|
|
FT_Face face;
|
|
|
|
|
|
|
|
if (zstr(text)) return SWITCH_STATUS_FALSE;
|
|
|
|
|
|
|
|
if (font_family) {
|
|
|
|
handle->font_family = switch_core_strdup(handle->pool, font_family);
|
|
|
|
} else {
|
|
|
|
font_family = handle->font_family;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (font_size) {
|
|
|
|
handle->font_size = font_size;
|
|
|
|
} else {
|
|
|
|
font_size = handle->font_size;
|
|
|
|
}
|
2015-02-12 03:38:37 +00:00
|
|
|
|
2015-02-11 20:07:06 +00:00
|
|
|
if (font_color) {
|
2015-02-12 07:03:45 +00:00
|
|
|
switch_color_set_rgb(&handle->color, font_color);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bgcolor) {
|
|
|
|
switch_color_set_rgb(&handle->bgcolor, bgcolor);
|
|
|
|
handle->use_bgcolor = SWITCH_TRUE;
|
|
|
|
} else {
|
|
|
|
handle->use_bgcolor = SWITCH_FALSE;
|
2015-02-11 20:07:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
handle->angle = angle;
|
|
|
|
|
|
|
|
//angle = 0; (45.0 / 360 ) * 3.14159 * 2;
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
//target_height = img->d_h;
|
2015-02-11 20:07:06 +00:00
|
|
|
|
|
|
|
error = FT_New_Face(handle->library, font_family, 0, &face); /* create face object */
|
2015-02-12 03:38:37 +00:00
|
|
|
if (error) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to open font %s\n", font_family);
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
2015-02-11 20:07:06 +00:00
|
|
|
|
|
|
|
/* use 50pt at 100dpi */
|
|
|
|
error = FT_Set_Char_Size(face, 64 * font_size, 0, 96, 96); /* set character size */
|
|
|
|
if (error) {printf("WTF %d\n", __LINE__); return SWITCH_STATUS_FALSE;}
|
|
|
|
|
|
|
|
slot = face->glyph;
|
|
|
|
|
2015-02-12 07:03:45 +00:00
|
|
|
if (handle->use_bgcolor && slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO) {
|
|
|
|
init_gradient_table(handle);
|
|
|
|
}
|
|
|
|
|
2015-02-11 20:07:06 +00:00
|
|
|
/* set up matrix */
|
|
|
|
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
|
|
|
|
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
|
|
|
|
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
|
|
|
|
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
|
|
|
|
|
2015-02-12 03:38:37 +00:00
|
|
|
pen.x = x;
|
|
|
|
pen.y = y;
|
2015-02-11 20:07:06 +00:00
|
|
|
|
|
|
|
while(*(text + index)) {
|
|
|
|
ch = switch_u8_get_char((char *)text, &index);
|
|
|
|
|
|
|
|
if (ch == '\n') {
|
2015-02-12 03:38:37 +00:00
|
|
|
pen.x = x;
|
|
|
|
pen.y += (font_size + font_size / 4);
|
2015-02-11 20:07:06 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set transformation */
|
|
|
|
FT_Set_Transform(face, &matrix, &pen);
|
|
|
|
|
|
|
|
/* load glyph image into the slot (erase previous one) */
|
|
|
|
error = FT_Load_Char(face, ch, FT_LOAD_RENDER);
|
|
|
|
if (error) continue;
|
|
|
|
|
|
|
|
/* now, draw to our target surface (convert position) */
|
2015-02-12 07:03:45 +00:00
|
|
|
draw_bitmap(handle, img, &slot->bitmap, pen.x + slot->bitmap_left, pen.y - slot->bitmap_top + font_size);
|
2015-02-11 20:07:06 +00:00
|
|
|
|
|
|
|
/* increment pen position */
|
2015-02-12 03:38:37 +00:00
|
|
|
pen.x += slot->advance.x >> 6;
|
|
|
|
pen.y += slot->advance.y >> 6;
|
2015-02-11 20:07:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FT_Done_Face(face);
|
|
|
|
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-08-03 19:13:24 +00:00
|
|
|
/* For Emacs:
|
|
|
|
* Local Variables:
|
|
|
|
* mode:c
|
|
|
|
* indent-tabs-mode:t
|
|
|
|
* tab-width:4
|
|
|
|
* c-basic-offset:4
|
|
|
|
* End:
|
|
|
|
* For VIM:
|
|
|
|
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
|
|
|
*/
|