1 // -*- c-basic-offset: 8; indent-tabs-mode: t -*-
2 // vim:ts=8:sw=8:noet:ai:
4 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
6 * This file is part of libass.
8 * libass is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * libass is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with libass; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include "ass_bitmap.h"
33 struct ass_synth_priv_s
{
46 static const unsigned int maxcolor
= 255;
47 static const unsigned base
= 256;
49 static int generate_tables(ass_synth_priv_t
* priv
, double radius
)
51 double A
= log(1.0/base
)/(radius
*radius
*2);
53 double volume_diff
, volume_factor
= 0;
56 if (priv
->radius
== radius
)
59 priv
->radius
= radius
;
61 priv
->g_r
= ceil(radius
);
62 priv
->g_w
= 2*priv
->g_r
+1;
65 priv
->g
= malloc(priv
->g_w
* sizeof(unsigned));
66 priv
->gt2
= malloc(256 * priv
->g_w
* sizeof(unsigned));
67 if (priv
->g
==NULL
|| priv
->gt2
==NULL
) {
73 // gaussian curve with volume = 256
74 for (volume_diff
=10000000; volume_diff
>0.0000001; volume_diff
*=0.5){
75 volume_factor
+= volume_diff
;
77 for (i
= 0; i
<priv
->g_w
; ++i
) {
78 priv
->g
[i
] = (unsigned)(exp(A
* (i
-priv
->g_r
)*(i
-priv
->g_r
)) * volume_factor
+ .5);
81 if(volume
>256) volume_factor
-= volume_diff
;
84 for (i
= 0; i
<priv
->g_w
; ++i
) {
85 priv
->g
[i
] = (unsigned)(exp(A
* (i
-priv
->g_r
)*(i
-priv
->g_r
)) * volume_factor
+ .5);
90 for(mx
=0;mx
<priv
->g_w
;mx
++){
92 priv
->gt2
[mx
+i
*priv
->g_w
] = i
*priv
->g
[mx
];
100 static void resize_tmp(ass_synth_priv_t
* priv
, int w
, int h
)
102 if (priv
->tmp_w
>= w
&& priv
->tmp_h
>= h
)
104 if (priv
->tmp_w
== 0)
106 if (priv
->tmp_h
== 0)
108 while (priv
->tmp_w
< w
) priv
->tmp_w
*= 2;
109 while (priv
->tmp_h
< h
) priv
->tmp_h
*= 2;
112 priv
->tmp
= malloc((priv
->tmp_w
+ 1) * priv
->tmp_h
* sizeof(short));
115 ass_synth_priv_t
* ass_synth_init(double radius
)
117 ass_synth_priv_t
* priv
= calloc(1, sizeof(ass_synth_priv_t
));
118 generate_tables(priv
, radius
);
122 void ass_synth_done(ass_synth_priv_t
* priv
)
133 static bitmap_t
* alloc_bitmap(int w
, int h
)
136 bm
= calloc(1, sizeof(bitmap_t
));
137 bm
->buffer
= malloc(w
*h
);
140 bm
->left
= bm
->top
= 0;
144 void ass_free_bitmap(bitmap_t
* bm
)
147 if (bm
->buffer
) free(bm
->buffer
);
152 static bitmap_t
* copy_bitmap(const bitmap_t
* src
)
154 bitmap_t
* dst
= alloc_bitmap(src
->w
, src
->h
);
155 dst
->left
= src
->left
;
157 memcpy(dst
->buffer
, src
->buffer
, src
->w
* src
->h
);
161 static int check_glyph_area(FT_Glyph glyph
)
165 FT_Glyph_Get_CBox(glyph
, FT_GLYPH_BBOX_TRUNCATE
, &bbox
);
166 dx
= bbox
.xMax
- bbox
.xMin
;
167 dy
= bbox
.yMax
- bbox
.yMin
;
168 if (dx
* dy
> 8000000) {
169 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_GlyphBBoxTooLarge
, (int)dx
, (int)dy
);
175 static bitmap_t
* glyph_to_bitmap_internal(FT_Glyph glyph
, int bord
)
186 if (check_glyph_area(glyph
))
188 error
= FT_Glyph_To_Bitmap(&glyph
, FT_RENDER_MODE_NORMAL
, 0, 0);
190 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_FT_Glyph_To_BitmapError
, error
);
194 bg
= (FT_BitmapGlyph
)glyph
;
196 if (bit
->pixel_mode
!= FT_PIXEL_MODE_GRAY
) {
197 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_UnsupportedPixelMode
, (int)(bit
->pixel_mode
));
198 FT_Done_Glyph(glyph
);
204 bm
= alloc_bitmap(w
+ 2*bord
, h
+ 2*bord
);
205 memset(bm
->buffer
, 0, bm
->w
* bm
->h
);
206 bm
->left
= bg
->left
- bord
;
207 bm
->top
= - bg
->top
- bord
;
210 dst
= bm
->buffer
+ bord
+ bm
->w
* bord
;
211 for (i
= 0; i
< h
; ++i
) {
221 * \brief fix outline bitmap and generate shadow bitmap
222 * Two things are done here:
223 * 1. Glyph bitmap is subtracted from outline bitmap. This way looks much better in some cases.
224 * 2. Shadow bitmap is created as a sum of glyph and outline bitmaps.
226 static bitmap_t
* fix_outline_and_shadow(bitmap_t
* bm_g
, bitmap_t
* bm_o
)
229 const int l
= bm_o
->left
> bm_g
->left
? bm_o
->left
: bm_g
->left
;
230 const int t
= bm_o
->top
> bm_g
->top
? bm_o
->top
: bm_g
->top
;
231 const int r
= bm_o
->left
+ bm_o
->w
< bm_g
->left
+ bm_g
->w
? bm_o
->left
+ bm_o
->w
: bm_g
->left
+ bm_g
->w
;
232 const int b
= bm_o
->top
+ bm_o
->h
< bm_g
->top
+ bm_g
->h
? bm_o
->top
+ bm_o
->h
: bm_g
->top
+ bm_g
->h
;
234 bitmap_t
* bm_s
= copy_bitmap(bm_o
);
236 unsigned char* g
= bm_g
->buffer
+ (t
- bm_g
->top
) * bm_g
->w
+ (l
- bm_g
->left
);
237 unsigned char* o
= bm_o
->buffer
+ (t
- bm_o
->top
) * bm_o
->w
+ (l
- bm_o
->left
);
238 unsigned char* s
= bm_s
->buffer
+ (t
- bm_s
->top
) * bm_s
->w
+ (l
- bm_s
->left
);
240 for (y
= 0; y
< b
- t
; ++y
) {
241 for (x
= 0; x
< r
- l
; ++x
) {
242 unsigned char c_g
, c_o
;
245 o
[x
] = (c_o
> c_g
) ? c_o
: 0;
246 s
[x
] = (c_o
< 0xFF - c_g
) ? c_o
+ c_g
: 0xFF;
257 int glyph_to_bitmap(ass_synth_priv_t
* priv
, ass_synth_priv_t
* priv_blur
,
258 FT_Glyph glyph
, FT_Glyph outline_glyph
, bitmap_t
** bm_g
,
259 bitmap_t
** bm_o
, bitmap_t
** bm_s
, int be
, double blur_radius
)
261 int bord
= be
? (be
+1) : 0;
262 bord
= (blur_radius
> 0.0) ? blur_radius
: bord
;
264 assert(bm_g
&& bm_o
&& bm_s
);
266 *bm_g
= *bm_o
= *bm_s
= 0;
269 *bm_g
= glyph_to_bitmap_internal(glyph
, bord
);
274 *bm_o
= glyph_to_bitmap_internal(outline_glyph
, bord
);
276 ass_free_bitmap(*bm_g
);
281 resize_tmp(priv
, (*bm_o
)->w
, (*bm_o
)->h
);
282 resize_tmp(priv_blur
, (*bm_o
)->w
, (*bm_o
)->h
);
284 resize_tmp(priv
, (*bm_g
)->w
, (*bm_g
)->h
);
285 resize_tmp(priv_blur
, (*bm_g
)->w
, (*bm_g
)->h
);
290 blur((*bm_o
)->buffer
, priv
->tmp
, (*bm_o
)->w
, (*bm_o
)->h
, (*bm_o
)->w
, (int*)priv
->gt2
, priv
->g_r
, priv
->g_w
);
292 blur((*bm_g
)->buffer
, priv
->tmp
, (*bm_g
)->w
, (*bm_g
)->h
, (*bm_g
)->w
, (int*)priv
->gt2
, priv
->g_r
, priv
->g_w
);
295 if (blur_radius
> 0.0) {
296 generate_tables(priv_blur
, blur_radius
);
298 blur((*bm_o
)->buffer
, priv_blur
->tmp
, (*bm_o
)->w
, (*bm_o
)->h
, (*bm_o
)->w
, (int*)priv_blur
->gt2
, priv_blur
->g_r
, priv_blur
->g_w
);
300 blur((*bm_g
)->buffer
, priv_blur
->tmp
, (*bm_g
)->w
, (*bm_g
)->h
, (*bm_g
)->w
, (int*)priv_blur
->gt2
, priv_blur
->g_r
, priv_blur
->g_w
);
304 *bm_s
= fix_outline_and_shadow(*bm_g
, *bm_o
);
306 *bm_s
= copy_bitmap(*bm_g
);