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 program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include "ass_bitmap.h"
31 struct ass_synth_priv_s
{
42 static const unsigned int maxcolor
= 255;
43 static const unsigned base
= 256;
44 static const double blur_radius
= 1.5;
46 static int generate_tables(ass_synth_priv_t
* priv
, double radius
)
48 double A
= log(1.0/base
)/(radius
*radius
*2);
50 double volume_diff
, volume_factor
= 0;
53 priv
->g_r
= ceil(radius
);
54 priv
->g_w
= 2*priv
->g_r
+1;
57 priv
->g
= malloc(priv
->g_w
* sizeof(unsigned));
58 priv
->gt2
= malloc(256 * priv
->g_w
* sizeof(unsigned));
59 if (priv
->g
==NULL
|| priv
->gt2
==NULL
) {
65 // gaussian curve with volume = 256
66 for (volume_diff
=10000000; volume_diff
>0.0000001; volume_diff
*=0.5){
67 volume_factor
+= volume_diff
;
69 for (i
= 0; i
<priv
->g_w
; ++i
) {
70 priv
->g
[i
] = (unsigned)(exp(A
* (i
-priv
->g_r
)*(i
-priv
->g_r
)) * volume_factor
+ .5);
73 if(volume
>256) volume_factor
-= volume_diff
;
76 for (i
= 0; i
<priv
->g_w
; ++i
) {
77 priv
->g
[i
] = (unsigned)(exp(A
* (i
-priv
->g_r
)*(i
-priv
->g_r
)) * volume_factor
+ .5);
82 for(mx
=0;mx
<priv
->g_w
;mx
++){
84 priv
->gt2
[mx
+i
*priv
->g_w
] = i
*priv
->g
[mx
];
92 static void resize_tmp(ass_synth_priv_t
* priv
, int w
, int h
)
94 if (priv
->tmp_w
>= w
&& priv
->tmp_h
>= h
)
100 while (priv
->tmp_w
< w
) priv
->tmp_w
*= 2;
101 while (priv
->tmp_h
< h
) priv
->tmp_h
*= 2;
104 priv
->tmp
= malloc((priv
->tmp_w
+ 1) * priv
->tmp_h
* sizeof(short));
107 ass_synth_priv_t
* ass_synth_init(void)
109 ass_synth_priv_t
* priv
= calloc(1, sizeof(ass_synth_priv_t
));
110 generate_tables(priv
, blur_radius
);
114 void ass_synth_done(ass_synth_priv_t
* priv
)
125 static bitmap_t
* alloc_bitmap(int w
, int h
)
128 bm
= calloc(1, sizeof(bitmap_t
));
129 bm
->buffer
= malloc(w
*h
);
132 bm
->left
= bm
->top
= 0;
136 void ass_free_bitmap(bitmap_t
* bm
)
139 if (bm
->buffer
) free(bm
->buffer
);
144 static bitmap_t
* copy_bitmap(const bitmap_t
* src
)
146 bitmap_t
* dst
= alloc_bitmap(src
->w
, src
->h
);
147 dst
->left
= src
->left
;
149 memcpy(dst
->buffer
, src
->buffer
, src
->w
* src
->h
);
153 static bitmap_t
* glyph_to_bitmap_internal(FT_Glyph glyph
, int bord
)
164 error
= FT_Glyph_To_Bitmap(&glyph
, FT_RENDER_MODE_NORMAL
, 0, 0);
166 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_FT_Glyph_To_BitmapError
, error
);
170 bg
= (FT_BitmapGlyph
)glyph
;
172 if (bit
->pixel_mode
!= FT_PIXEL_MODE_GRAY
) {
173 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_UnsupportedPixelMode
, (int)(bit
->pixel_mode
));
174 FT_Done_Glyph(glyph
);
180 bm
= alloc_bitmap(w
+ 2*bord
, h
+ 2*bord
);
181 memset(bm
->buffer
, 0, bm
->w
* bm
->h
);
182 bm
->left
= bg
->left
- bord
;
183 bm
->top
= - bg
->top
- bord
;
186 dst
= bm
->buffer
+ bord
+ bm
->w
* bord
;
187 for (i
= 0; i
< h
; ++i
) {
197 * \brief fix outline bitmap and generate shadow bitmap
198 * Two things are done here:
199 * 1. Glyph bitmap is subtracted from outline bitmap. This way looks much better in some cases.
200 * 2. Shadow bitmap is created as a sum of glyph and outline bitmaps.
202 static bitmap_t
* fix_outline_and_shadow(bitmap_t
* bm_g
, bitmap_t
* bm_o
)
205 const int l
= bm_o
->left
> bm_g
->left
? bm_o
->left
: bm_g
->left
;
206 const int t
= bm_o
->top
> bm_g
->top
? bm_o
->top
: bm_g
->top
;
207 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
;
208 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
;
210 bitmap_t
* bm_s
= copy_bitmap(bm_o
);
212 unsigned char* g
= bm_g
->buffer
+ (t
- bm_g
->top
) * bm_g
->w
+ (l
- bm_g
->left
);
213 unsigned char* o
= bm_o
->buffer
+ (t
- bm_o
->top
) * bm_o
->w
+ (l
- bm_o
->left
);
214 unsigned char* s
= bm_s
->buffer
+ (t
- bm_s
->top
) * bm_s
->w
+ (l
- bm_s
->left
);
216 for (y
= 0; y
< b
- t
; ++y
) {
217 for (x
= 0; x
< r
- l
; ++x
) {
218 unsigned char c_g
, c_o
;
221 o
[x
] = (c_o
> c_g
) ? c_o
: 0;
222 s
[x
] = (c_o
< 0xFF - c_g
) ? c_o
+ c_g
: 0xFF;
233 int glyph_to_bitmap(ass_synth_priv_t
* priv
, FT_Glyph glyph
, FT_Glyph outline_glyph
,
234 bitmap_t
** bm_g
, bitmap_t
** bm_o
, bitmap_t
** bm_s
, int be
)
236 const int bord
= be
? ceil(blur_radius
) : 0;
238 assert(bm_g
&& bm_o
&& bm_s
);
240 *bm_g
= *bm_o
= *bm_s
= 0;
243 *bm_g
= glyph_to_bitmap_internal(glyph
, bord
);
248 *bm_o
= glyph_to_bitmap_internal(outline_glyph
, bord
);
250 ass_free_bitmap(*bm_g
);
255 resize_tmp(priv
, (*bm_o
)->w
, (*bm_o
)->h
);
256 resize_tmp(priv
, (*bm_g
)->w
, (*bm_g
)->h
);
259 blur((*bm_g
)->buffer
, priv
->tmp
, (*bm_g
)->w
, (*bm_g
)->h
, (*bm_g
)->w
, (int*)priv
->gt2
, priv
->g_r
, priv
->g_w
);
261 blur((*bm_o
)->buffer
, priv
->tmp
, (*bm_o
)->w
, (*bm_o
)->h
, (*bm_o
)->w
, (int*)priv
->gt2
, priv
->g_r
, priv
->g_w
);
265 *bm_s
= fix_outline_and_shadow(*bm_g
, *bm_o
);
267 *bm_s
= copy_bitmap(*bm_g
);