Fix non-ASCII comment
[vlc/asuraparaju-public.git] / modules / misc / win32text.c
blobe3464674ed26ea50961fd1afe1b8455918d1fc0e
1 /*****************************************************************************
2 * win32text.c : Text drawing routines using the TextOut win32 API
3 *****************************************************************************
4 * Copyright (C) 2002 - 2009 the VideoLAN team
5 * $Id$
7 * Authors: Gildas Bazin <gbazin@videolan.org>
8 * Pierre Ynard
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_vout.h>
36 #include <vlc_osd.h>
37 #include <vlc_block.h>
38 #include <vlc_filter.h>
40 #include <math.h>
42 /*****************************************************************************
43 * Local prototypes
44 *****************************************************************************/
45 static int Create ( vlc_object_t * );
46 static void Destroy( vlc_object_t * );
48 /* The RenderText call maps to pf_render_string, defined in vlc_filter.h */
49 static int RenderText( filter_t *, subpicture_region_t *,
50 subpicture_region_t * );
52 static int Render( filter_t *, subpicture_region_t *, uint8_t *, int, int);
53 static int SetFont( filter_t *, int );
55 /*****************************************************************************
56 * Module descriptor
57 *****************************************************************************/
58 #define FONT_TEXT N_("Font")
59 #define FONT_LONGTEXT N_("Filename for the font you want to use")
60 #define FONTSIZE_TEXT N_("Font size in pixels")
61 #define FONTSIZE_LONGTEXT N_("This is the default size of the fonts " \
62 "that will be rendered on the video. " \
63 "If set to something different than 0 this option will override the " \
64 "relative font size." )
65 #define OPACITY_TEXT N_("Opacity")
66 #define OPACITY_LONGTEXT N_("The opacity (inverse of transparency) of the " \
67 "text that will be rendered on the video. 0 = transparent, " \
68 "255 = totally opaque. " )
69 #define COLOR_TEXT N_("Text default color")
70 #define COLOR_LONGTEXT N_("The color of the text that will be rendered on "\
71 "the video. This must be an hexadecimal (like HTML colors). The first two "\
72 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
73 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
74 #define FONTSIZER_TEXT N_("Relative font size")
75 #define FONTSIZER_LONGTEXT N_("This is the relative default size of the " \
76 "fonts that will be rendered on the video. If absolute font size is set, "\
77 "relative size will be overriden." )
79 static int const pi_sizes[] = { 20, 18, 16, 12, 6 };
80 static char *const ppsz_sizes_text[] = {
81 N_("Smaller"), N_("Small"), N_("Normal"), N_("Large"), N_("Larger") };
82 static const int pi_color_values[] = {
83 0x00000000, 0x00808080, 0x00C0C0C0, 0x00FFFFFF, 0x00800000,
84 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00808000, 0x00008000, 0x00008080,
85 0x0000FF00, 0x00800080, 0x00000080, 0x000000FF, 0x0000FFFF };
87 static const char *const ppsz_color_descriptions[] = {
88 N_("Black"), N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"),
89 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"), N_("Teal"),
90 N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"), N_("Aqua") };
92 vlc_module_begin ()
93 set_shortname( N_("Text renderer"))
94 set_description( N_("Win32 font renderer") )
95 set_category( CAT_VIDEO )
96 set_subcategory( SUBCAT_VIDEO_SUBPIC )
98 add_integer( "win32text-fontsize", 0, NULL, FONTSIZE_TEXT,
99 FONTSIZE_LONGTEXT, true )
101 /* opacity valid on 0..255, with default 255 = fully opaque */
102 add_integer_with_range( "win32-opacity", 255, 0, 255, NULL,
103 OPACITY_TEXT, OPACITY_LONGTEXT, false )
105 /* hook to the color values list, with default 0x00ffffff = white */
106 add_integer( "win32text-color", 0x00FFFFFF, NULL, COLOR_TEXT,
107 COLOR_LONGTEXT, true )
108 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
110 add_integer( "win32text-rel-fontsize", 16, NULL, FONTSIZER_TEXT,
111 FONTSIZER_LONGTEXT, false )
112 change_integer_list( pi_sizes, ppsz_sizes_text, NULL );
114 set_capability( "text renderer", 50 )
115 add_shortcut( "text" )
116 set_callbacks( Create, Destroy )
117 vlc_module_end ()
119 /*****************************************************************************
120 * filter_sys_t: win32text local data
121 *****************************************************************************/
122 struct filter_sys_t
124 uint8_t i_font_opacity;
125 int i_font_color;
126 int i_font_size;
128 int i_default_font_size;
129 int i_display_height;
131 HDC hcdc;
132 HFONT hfont;
133 HFONT hfont_bak;
134 int i_logpy;
137 static const uint8_t pi_gamma[16] =
138 {0x00, 0x41, 0x52, 0x63, 0x84, 0x85, 0x96, 0xa7, 0xb8, 0xc9,
139 0xca, 0xdb, 0xdc, 0xed, 0xee, 0xff};
141 /*****************************************************************************
142 * Create: creates the module
143 *****************************************************************************/
144 static int Create( vlc_object_t *p_this )
146 filter_t *p_filter = (filter_t *)p_this;
147 filter_sys_t *p_sys;
148 char *psz_fontfile = NULL;
149 vlc_value_t val;
150 HDC hdc;
152 /* Allocate structure */
153 p_filter->p_sys = p_sys = malloc( sizeof( filter_sys_t ) );
154 if( !p_sys )
155 return VLC_ENOMEM;
156 p_sys->i_font_size = 0;
157 p_sys->i_display_height = 0;
159 var_Create( p_filter, "win32text-font",
160 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
161 var_Create( p_filter, "win32text-fontsize",
162 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
163 var_Create( p_filter, "win32text-rel-fontsize",
164 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
165 var_Create( p_filter, "win32text-opacity",
166 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
167 var_Get( p_filter, "win32text-opacity", &val );
168 p_sys->i_font_opacity = __MAX( __MIN( val.i_int, 255 ), 0 );
169 var_Create( p_filter, "win32text-color",
170 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
171 var_Get( p_filter, "win32text-color", &val );
172 p_sys->i_font_color = __MAX( __MIN( val.i_int, 0xFFFFFF ), 0 );
174 p_sys->hfont = p_sys->hfont_bak = 0;
175 hdc = GetDC( NULL );
176 p_sys->hcdc = CreateCompatibleDC( hdc );
177 p_sys->i_logpy = GetDeviceCaps( hdc, LOGPIXELSY );
178 ReleaseDC( NULL, hdc );
179 SetBkMode( p_sys->hcdc, TRANSPARENT );
181 var_Get( p_filter, "win32text-fontsize", &val );
182 p_sys->i_default_font_size = val.i_int;
183 if( SetFont( p_filter, 0 ) != VLC_SUCCESS ) goto error;
185 free( psz_fontfile );
186 p_filter->pf_render_text = RenderText;
187 p_filter->pf_render_html = NULL;
188 return VLC_SUCCESS;
190 error:
191 free( psz_fontfile );
192 free( p_sys );
193 return VLC_EGENERIC;
196 /*****************************************************************************
197 * Destroy: destroy the module
198 *****************************************************************************/
199 static void Destroy( vlc_object_t *p_this )
201 filter_t *p_filter = (filter_t *)p_this;
202 filter_sys_t *p_sys = p_filter->p_sys;
204 if( p_sys->hfont_bak ) SelectObject( p_sys->hcdc, p_sys->hfont_bak );
205 if( p_sys->hfont ) DeleteObject( p_sys->hfont );
206 DeleteDC( p_sys->hcdc );
207 free( p_sys );
210 /*****************************************************************************
211 * Render: place string in picture
212 *****************************************************************************
213 * This function merges the previously rendered win32text glyphs into a picture
214 *****************************************************************************/
215 static int Render( filter_t *p_filter, subpicture_region_t *p_region,
216 uint8_t *p_bitmap, int i_width, int i_height )
218 uint8_t *p_dst;
219 video_format_t fmt;
220 int i, i_pitch;
221 bool b_outline = true;
223 /* Create a new subpicture region */
224 memset( &fmt, 0, sizeof(video_format_t) );
225 fmt.i_chroma = VLC_CODEC_YUVP;
226 fmt.i_width = fmt.i_visible_width = i_width + (b_outline ? 4 : 0);
227 fmt.i_height = fmt.i_visible_height = i_height + (b_outline ? 4 : 0);
228 fmt.i_x_offset = fmt.i_y_offset = 0;
230 /* Build palette */
231 fmt.p_palette = calloc( 1, sizeof(*fmt.p_palette) );
232 if( !fmt.p_palette )
233 return VLC_EGENERIC;
234 fmt.p_palette->i_entries = 16;
235 for( i = 0; i < fmt.p_palette->i_entries; i++ )
237 fmt.p_palette->palette[i][0] = pi_gamma[i];
238 fmt.p_palette->palette[i][1] = 128;
239 fmt.p_palette->palette[i][2] = 128;
240 fmt.p_palette->palette[i][3] = pi_gamma[i];
243 p_region->p_picture = picture_NewFromFormat( &fmt );
244 if( !p_region->p_picture )
246 free( fmt.p_palette );
247 return VLC_EGENERIC;
249 p_region->fmt = fmt;
251 p_dst = p_region->p_picture->Y_PIXELS;
252 i_pitch = p_region->p_picture->Y_PITCH;
254 if( b_outline )
256 memset( p_dst, 0, i_pitch * fmt.i_height );
257 p_dst += p_region->p_picture->Y_PITCH * 2 + 2;
260 for( i = 0; i < i_height; i++ )
262 memcpy( p_dst, p_bitmap, i_width );
263 p_bitmap += (i_width+3) & ~3;
264 p_dst += i_pitch;
267 /* Outlining (find something better than nearest neighbour filtering ?) */
268 if( b_outline )
270 uint8_t *p_top = p_dst; /* Use 1st line as a cache */
271 uint8_t left, current;
272 int x, y;
274 p_dst = p_region->p_picture->Y_PIXELS;
276 for( y = 1; y < (int)fmt.i_height - 1; y++ )
278 memcpy( p_top, p_dst, fmt.i_width );
279 p_dst += i_pitch;
280 left = 0;
282 for( x = 1; x < (int)fmt.i_width - 1; x++ )
284 current = p_dst[x];
285 p_dst[x] = ( 4 * (int)p_dst[x] + left + p_top[x] + p_dst[x+1] +
286 p_dst[x + i_pitch]) / 8;
287 left = current;
290 memset( p_top, 0, fmt.i_width );
293 return VLC_SUCCESS;
296 static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
297 subpicture_region_t *p_region_in )
299 filter_sys_t *p_sys = p_filter->p_sys;
300 int i_font_color, i_font_alpha, i_font_size;
301 uint8_t *p_bitmap;
302 TCHAR *psz_string;
303 int i, i_width, i_height;
304 HBITMAP bitmap, bitmap_bak;
305 BITMAPINFO *p_bmi;
306 RECT rect = { 0, 0, 0, 0 };
308 /* Sanity check */
309 if( !p_region_in || !p_region_out ) return VLC_EGENERIC;
310 if( !p_region_in->psz_text || !*p_region_in->psz_text )
311 return VLC_EGENERIC;
313 psz_string = malloc( (strlen( p_region_in->psz_text )+1) * sizeof(TCHAR) );
314 if( !psz_string )
315 return VLC_ENOMEM;
316 #ifdef UNICODE
317 if( mbstowcs( psz_string, p_region_in->psz_text,
318 strlen( p_region_in->psz_text ) * sizeof(TCHAR) ) < 0 )
320 free( psz_string );
321 return VLC_EGENERIC;
323 #else
324 strcpy( psz_string, p_region_in->psz_text );
325 #endif
326 if( !*psz_string )
328 free( psz_string );
329 return VLC_EGENERIC;
332 if( p_region_in->p_style )
334 i_font_color = __MAX( __MIN( p_region_in->p_style->i_font_color, 0xFFFFFF ), 0 );
335 i_font_alpha = __MAX( __MIN( p_region_in->p_style->i_font_alpha, 255 ), 0 );
336 i_font_size = __MAX( __MIN( p_region_in->p_style->i_font_size, 255 ), 0 );
338 else
340 i_font_color = p_sys->i_font_color;
341 i_font_alpha = 255 - p_sys->i_font_opacity;
342 i_font_size = p_sys->i_default_font_size;
345 SetFont( p_filter, i_font_size );
347 SetTextColor( p_sys->hcdc, RGB( (i_font_color >> 16) & 0xff,
348 (i_font_color >> 8) & 0xff, i_font_color & 0xff) );
350 DrawText( p_sys->hcdc, psz_string, -1, &rect,
351 DT_CALCRECT | DT_CENTER | DT_NOPREFIX );
352 i_width = rect.right; i_height = rect.bottom;
354 p_bmi = malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*16);
355 memset( p_bmi, 0, sizeof(BITMAPINFOHEADER) );
356 p_bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
357 p_bmi->bmiHeader.biWidth = (i_width+3) & ~3;
358 p_bmi->bmiHeader.biHeight = - i_height;
359 p_bmi->bmiHeader.biPlanes = 1;
360 p_bmi->bmiHeader.biBitCount = 8;
361 p_bmi->bmiHeader.biCompression = BI_RGB;
362 p_bmi->bmiHeader.biClrUsed = 16;
364 for( i = 0; i < 16; i++ )
366 p_bmi->bmiColors[i].rgbBlue =
367 p_bmi->bmiColors[i].rgbGreen =
368 p_bmi->bmiColors[i].rgbRed = pi_gamma[i];
371 bitmap = CreateDIBSection( p_sys->hcdc, p_bmi, DIB_RGB_COLORS,
372 (void **)&p_bitmap, NULL, 0 );
373 if( !bitmap )
375 msg_Err( p_filter, "could not create bitmap" );
376 free( psz_string );
377 return VLC_EGENERIC;
380 bitmap_bak = SelectObject( p_sys->hcdc, bitmap );
381 FillRect( p_sys->hcdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH) );
383 if( !DrawText( p_sys->hcdc, psz_string, -1, &rect,
384 DT_CENTER | DT_NOPREFIX ) )
386 msg_Err( p_filter, "could not draw text" );
389 p_region_out->i_x = p_region_in->i_x;
390 p_region_out->i_y = p_region_in->i_y;
391 Render( p_filter, p_region_out, p_bitmap, i_width, i_height );
393 SelectObject( p_sys->hcdc, bitmap_bak );
394 DeleteObject( bitmap );
395 free( psz_string );
396 return VLC_SUCCESS;
399 static int SetFont( filter_t *p_filter, int i_size )
401 filter_sys_t *p_sys = p_filter->p_sys;
402 LOGFONT logfont;
404 if( i_size && i_size == p_sys->i_font_size ) return VLC_SUCCESS;
406 if( !i_size )
408 vlc_value_t val;
410 if( !p_sys->i_default_font_size &&
411 p_sys->i_display_height == (int)p_filter->fmt_out.video.i_height )
412 return VLC_SUCCESS;
414 if( p_sys->i_default_font_size )
416 i_size = p_sys->i_default_font_size;
418 else
420 var_Get( p_filter, "win32text-rel-fontsize", &val );
421 i_size = (int)p_filter->fmt_out.video.i_height / val.i_int;
422 p_filter->p_sys->i_display_height =
423 p_filter->fmt_out.video.i_height;
425 if( i_size <= 0 )
427 msg_Warn( p_filter, "invalid fontsize, using 12" );
428 i_size = 12;
431 msg_Dbg( p_filter, "using fontsize: %i", i_size );
434 p_sys->i_font_size = i_size;
436 if( p_sys->hfont_bak ) SelectObject( p_sys->hcdc, p_sys->hfont_bak );
437 if( p_sys->hfont ) DeleteObject( p_sys->hfont );
439 i_size = i_size * (int64_t)p_sys->i_logpy / 72;
441 logfont.lfHeight = i_size;
442 logfont.lfWidth = 0;
443 logfont.lfEscapement = 0;
444 logfont.lfOrientation = 0;
445 logfont.lfWeight = 0;
446 logfont.lfItalic = FALSE;
447 logfont.lfUnderline = FALSE;
448 logfont.lfStrikeOut = FALSE;
449 logfont.lfCharSet = ANSI_CHARSET;
450 logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
451 logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
452 logfont.lfQuality = ANTIALIASED_QUALITY;
453 logfont.lfPitchAndFamily = DEFAULT_PITCH;
454 memcpy( logfont.lfFaceName, _T("Arial"), sizeof(_T("Arial")) );
456 p_sys->hfont = CreateFontIndirect( &logfont );
458 p_sys->hfont_bak = SelectObject( p_sys->hcdc, p_sys->hfont );
460 return VLC_SUCCESS;