diff options
-rw-r--r-- | libass/ass_bitmap.c | 57 | ||||
-rw-r--r-- | libass/ass_bitmap.h | 2 | ||||
-rw-r--r-- | libass/ass_cache_template.c | 1 | ||||
-rw-r--r-- | libass/ass_render.c | 18 |
4 files changed, 72 insertions, 6 deletions
diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index 46ead6ea..d7573ef7 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -273,6 +273,56 @@ static bitmap_t *fix_outline_and_shadow(bitmap_t *bm_g, bitmap_t *bm_o) } /** + * \brief Shift a bitmap by the fraction of a pixel in x and y direction + * expressed in 26.6 fixed point + */ +static void shift_bitmap(unsigned char *buf, int w, int h, int shift_x, + int shift_y) +{ + int x, y, b; + + // Shift in x direction + if (shift_x > 0) { + for (y = 0; y < h; y++) { + for (x = w - 1; x > 0; x--) { + b = (buf[x + y * w - 1] * shift_x) / 64; + buf[x + y * w - 1] -= b; + buf[x + y * w] += b; + } + } + } else if (shift_x < 0) { + shift_x = -shift_x; + for (y = 0; y < h; y++) { + for (x = 0; x < w - 1; x++) { + b = (buf[x + y * w + 1] * shift_x) / 64; + buf[x + y * w + 1] -= b; + buf[x + y * w] += b; + } + } + } + + // Shift in y direction + if (shift_y > 0) { + for (x = 0; x < w; x++) { + for (y = h - 1; y > 0; y--) { + b = (buf[x + (y - 1) * w] * shift_y) / 64; + buf[x + (y - 1) * w] -= b; + buf[x + y * w] += b; + } + } + } else if (shift_y < 0) { + shift_y = -shift_y; + for (x = 0; x < w; x++) { + for (y = 0; y < h - 1; y++) { + b = (buf[x + (y + 1) * w] * shift_y) / 64; + buf[x + (y + 1) * w] -= b; + buf[x + y * w] += b; + } + } + } +} + +/** * \brief Blur with [[1,2,1]. [2,4,2], [1,2,1]] kernel * This blur is the same as the one employed by vsfilter. */ @@ -303,11 +353,13 @@ static void be_blur(unsigned char *buf, int w, int h) int glyph_to_bitmap(ass_synth_priv_t *priv_blur, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t **bm_g, bitmap_t **bm_o, bitmap_t **bm_s, - int be, double blur_radius) + int be, double blur_radius, FT_Vector shadow_offset) { int bord = be ? (be / 4 + 1) : 0; blur_radius *= 2; bord = (blur_radius > 0.0) ? blur_radius + 1 : bord; + if (bord == 0 && (shadow_offset.x || shadow_offset.y)) + bord = 1; assert(bm_g && bm_o && bm_s); @@ -356,6 +408,9 @@ int glyph_to_bitmap(ass_synth_priv_t *priv_blur, else *bm_s = copy_bitmap(*bm_g); + shift_bitmap((*bm_s)->buffer, (*bm_s)->w,(*bm_s)->h, + shadow_offset.x, shadow_offset.y); + assert(bm_s); return 0; } diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h index 73a36698..f6b13805 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -47,7 +47,7 @@ typedef struct bitmap_s { int glyph_to_bitmap(ass_synth_priv_t *priv_blur, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t **bm_g, bitmap_t **bm_o, bitmap_t **bm_s, int be, - double blur_radius); + double blur_radius, FT_Vector shadow_offset); void ass_free_bitmap(bitmap_t *bm); diff --git a/libass/ass_cache_template.c b/libass/ass_cache_template.c index 6c536fbb..dd9adbd4 100644 --- a/libass/ass_cache_template.c +++ b/libass/ass_cache_template.c @@ -77,6 +77,7 @@ START(bitmap, bipmap_hash_key_s) GENERIC(int, shift_x) GENERIC(int, shift_y) FTVECTOR(advance) // subpixel shift vector + FTVECTOR(shadow_offset) // shadow subpixel shift END(bitmap_hash_key_t) // describes an outline glyph diff --git a/libass/ass_render.c b/libass/ass_render.c index 2abb9d7f..c779f3b1 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -41,7 +41,6 @@ #define MAX_LINES_INITIAL 64 #define BLUR_MAX_RADIUS 100.0 #define MAX_BE 100 -#define ROUND(x) ((int) ((x) + .5)) #define SUBPIXEL_MASK 63 // d6 bitmask for subpixel accuracy adjustment static int last_render_id = 0; @@ -574,10 +573,10 @@ static ass_image_t *render_text(ass_renderer_t *render_priv, int dst_x, pen_x = dst_x + (info->pos.x >> 6) + - ROUND(info->shadow_x * render_priv->border_scale); + (int) (info->shadow_x * render_priv->border_scale); pen_y = dst_y + (info->pos.y >> 6) + - ROUND(info->shadow_y * render_priv->border_scale); + (int) (info->shadow_y * render_priv->border_scale); bm = info->bm_s; here_tail = tail; @@ -1874,7 +1873,8 @@ get_bitmap_glyph(ass_renderer_t *render_priv, glyph_info_t *info) info->glyph, info->outline_glyph, &info->bm, &info->bm_o, &info->bm_s, info->be, - info->blur * render_priv->border_scale); + info->blur * render_priv->border_scale, + info->hash_key.shadow_offset); if (error) info->symbol = 0; @@ -2439,6 +2439,16 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event, render_priv->state.be; text_info->glyphs[text_info->length].hash_key.blur = render_priv->state.blur; + text_info->glyphs[text_info->length].hash_key.shadow_offset.x = + double_to_d6( + render_priv->state.shadow_x * render_priv->border_scale - + (int) (render_priv->state.shadow_x * + render_priv->border_scale)); + text_info->glyphs[text_info->length].hash_key.shadow_offset.y = + double_to_d6( + render_priv->state.shadow_y * render_priv->border_scale - + (int) (render_priv->state.shadow_y * + render_priv->border_scale)); text_info->length++; |