📄 freetype.c
字号:
for( y = 0, i_bitmap_offset = 0; y < p_glyph->bitmap.rows; y++ ) { for( x = 0; x < p_glyph->bitmap.width; x++, i_bitmap_offset++ ) { if( p_glyph->bitmap.buffer[i_bitmap_offset] ) p_dst[i_offset+x] = ((int)p_glyph->bitmap.buffer[i_bitmap_offset] + 8)/16; } i_offset += i_pitch; } } } /* Outlining (find something better than nearest neighbour filtering ?) */ if( 1 ) { uint8_t *p_dst = p_region->picture.Y_PIXELS; uint8_t *p_top = p_dst; /* Use 1st line as a cache */ uint8_t left, current; for( y = 1; y < (int)fmt.i_height - 1; y++ ) { memcpy( p_top, p_dst, fmt.i_width ); p_dst += p_region->picture.Y_PITCH; left = 0; for( x = 1; x < (int)fmt.i_width - 1; x++ ) { current = p_dst[x]; p_dst[x] = ( 4 * (int)p_dst[x] + left + p_top[x] + p_dst[x+1] + p_dst[x + p_region->picture.Y_PITCH]) / 8; left = current; } } memset( p_top, 0, fmt.i_width ); } return VLC_SUCCESS;}/** * This function renders a text subpicture region into another one. * It also calculates the size needed for this string, and renders the * needed glyphs into memory. It is used as pf_add_string callback in * the vout method by this module */static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, subpicture_region_t *p_region_in ){ filter_sys_t *p_sys = p_filter->p_sys; line_desc_t *p_lines = 0, *p_line = 0, *p_next = 0, *p_prev = 0; int i, i_pen_y, i_pen_x, i_error, i_glyph_index, i_previous; uint32_t *psz_unicode, *psz_unicode_orig = 0, i_char, *psz_line_start; int i_string_length; char *psz_string; vlc_iconv_t iconv_handle = (vlc_iconv_t)(-1); int i_font_color, i_font_alpha, i_font_size, i_red, i_green, i_blue; FT_BBox line; FT_BBox glyph_size; FT_Vector result; FT_Glyph tmp_glyph; /* Sanity check */ if( !p_region_in || !p_region_out ) return VLC_EGENERIC; psz_string = p_region_in->psz_text; if( !psz_string || !*psz_string ) return VLC_EGENERIC; i_font_color = __MAX( __MIN( p_region_in->i_text_color, 0xFFFFFF ), 0 ); if( i_font_color == 0xFFFFFF ) i_font_color = p_sys->i_font_color; i_font_alpha = __MAX( __MIN( p_region_in->i_text_alpha, 255 ), 0 ); if( !i_font_alpha ) i_font_alpha = 255 - p_sys->i_font_opacity; i_font_size = __MAX( __MIN( p_region_in->i_text_size, 255 ), 0 ); SetFontSize( p_filter, i_font_size ); i_red = ( i_font_color & 0x00FF0000 ) >> 16; i_green = ( i_font_color & 0x0000FF00 ) >> 8; i_blue = i_font_color & 0x000000FF; result.x = result.y = 0; line.xMin = line.xMax = line.yMin = line.yMax = 0; psz_unicode = psz_unicode_orig = malloc( ( strlen(psz_string) + 1 ) * sizeof(uint32_t) ); if( psz_unicode == NULL ) { msg_Err( p_filter, "out of memory" ); goto error; }#if defined(WORDS_BIGENDIAN) iconv_handle = vlc_iconv_open( "UCS-4BE", "UTF-8" );#else iconv_handle = vlc_iconv_open( "UCS-4LE", "UTF-8" );#endif if( iconv_handle == (vlc_iconv_t)-1 ) { msg_Warn( p_filter, "unable to do conversion" ); goto error; } { char *p_in_buffer, *p_out_buffer; size_t i_in_bytes, i_out_bytes, i_out_bytes_left, i_ret; i_in_bytes = strlen( psz_string ); i_out_bytes = i_in_bytes * sizeof( uint32_t ); i_out_bytes_left = i_out_bytes; p_in_buffer = psz_string; p_out_buffer = (char *)psz_unicode; i_ret = vlc_iconv( iconv_handle, &p_in_buffer, &i_in_bytes, &p_out_buffer, &i_out_bytes_left ); vlc_iconv_close( iconv_handle ); if( i_in_bytes ) { msg_Warn( p_filter, "failed to convert string to unicode (%s), " "bytes left %d", strerror(errno), i_in_bytes ); goto error; } *(uint32_t*)p_out_buffer = 0; i_string_length = (i_out_bytes - i_out_bytes_left) / sizeof(uint32_t); }#if defined(HAVE_FRIBIDI) { uint32_t *p_fribidi_string; FriBidiCharType base_dir = FRIBIDI_TYPE_ON; p_fribidi_string = malloc( (i_string_length + 1) * sizeof(uint32_t) ); fribidi_log2vis( (FriBidiChar*)psz_unicode, i_string_length, &base_dir, (FriBidiChar*)p_fribidi_string, 0, 0, 0 ); free( psz_unicode_orig ); psz_unicode = psz_unicode_orig = p_fribidi_string; p_fribidi_string[ i_string_length ] = 0; }#endif /* Calculate relative glyph positions and a bounding box for the * entire string */ if( !(p_line = NewLine( psz_string )) ) { msg_Err( p_filter, "out of memory" ); goto error; } p_lines = p_line; i_pen_x = i_pen_y = 0; i_previous = i = 0; psz_line_start = psz_unicode;#define face p_sys->p_face#define glyph face->glyph while( *psz_unicode ) { i_char = *psz_unicode++; if( i_char == '\r' ) /* ignore CR chars wherever they may be */ { continue; } if( i_char == '\n' ) { psz_line_start = psz_unicode; if( !(p_next = NewLine( psz_string )) ) { msg_Err( p_filter, "out of memory" ); goto error; } p_line->p_next = p_next; p_line->i_width = line.xMax; p_line->i_height = face->size->metrics.height >> 6; p_line->pp_glyphs[ i ] = NULL; p_line->i_alpha = i_font_alpha; p_line->i_red = i_red; p_line->i_green = i_green; p_line->i_blue = i_blue; p_prev = p_line; p_line = p_next; result.x = __MAX( result.x, line.xMax ); result.y += face->size->metrics.height >> 6; i_pen_x = 0; i_previous = i = 0; line.xMin = line.xMax = line.yMin = line.yMax = 0; i_pen_y += face->size->metrics.height >> 6;#if 0 msg_Dbg( p_filter, "Creating new line, i is %d", i );#endif continue; } i_glyph_index = FT_Get_Char_Index( face, i_char ); if( p_sys->i_use_kerning && i_glyph_index && i_previous ) { FT_Vector delta; FT_Get_Kerning( face, i_previous, i_glyph_index, ft_kerning_default, &delta ); i_pen_x += delta.x >> 6; } p_line->p_glyph_pos[ i ].x = i_pen_x; p_line->p_glyph_pos[ i ].y = i_pen_y; i_error = FT_Load_Glyph( face, i_glyph_index, FT_LOAD_DEFAULT ); if( i_error ) { msg_Err( p_filter, "FT_Load_Glyph returned %d", i_error ); goto error; } i_error = FT_Get_Glyph( glyph, &tmp_glyph ); if( i_error ) { msg_Err( p_filter, "FT_Get_Glyph returned %d", i_error ); goto error; } FT_Glyph_Get_CBox( tmp_glyph, ft_glyph_bbox_pixels, &glyph_size ); i_error = FT_Glyph_To_Bitmap( &tmp_glyph, ft_render_mode_normal, 0, 1); if( i_error ) continue; p_line->pp_glyphs[ i ] = (FT_BitmapGlyph)tmp_glyph; /* Do rest */ line.xMax = p_line->p_glyph_pos[i].x + glyph_size.xMax - glyph_size.xMin + ((FT_BitmapGlyph)tmp_glyph)->left; if( line.xMax > (int)p_filter->fmt_out.video.i_visible_width - 20 ) { p_line->pp_glyphs[ i ] = NULL; FreeLine( p_line ); p_line = NewLine( psz_string ); if( p_prev ) p_prev->p_next = p_line; else p_lines = p_line; while( psz_unicode > psz_line_start && *psz_unicode != ' ' ) { psz_unicode--; } if( psz_unicode == psz_line_start ) { msg_Warn( p_filter, "unbreakable string" ); goto error; } else { *psz_unicode = '\n'; } psz_unicode = psz_line_start; i_pen_x = 0; i_previous = i = 0; line.xMin = line.xMax = line.yMin = line.yMax = 0; continue; } line.yMax = __MAX( line.yMax, glyph_size.yMax ); line.yMin = __MIN( line.yMin, glyph_size.yMin ); i_previous = i_glyph_index; i_pen_x += glyph->advance.x >> 6; i++; } p_line->i_width = line.xMax; p_line->i_height = face->size->metrics.height >> 6; p_line->pp_glyphs[ i ] = NULL; p_line->i_alpha = i_font_alpha; p_line->i_red = i_red; p_line->i_green = i_green; p_line->i_blue = i_blue; result.x = __MAX( result.x, line.xMax ); result.y += line.yMax - line.yMin;#undef face#undef glyph p_region_out->i_x = p_region_in->i_x; p_region_out->i_y = p_region_in->i_y; Render( p_filter, p_region_out, p_lines, result.x, result.y ); if( psz_unicode_orig ) free( psz_unicode_orig ); FreeLines( p_lines ); return VLC_SUCCESS; error: if( psz_unicode_orig ) free( psz_unicode_orig ); FreeLines( p_lines ); return VLC_EGENERIC;}static void FreeLine( line_desc_t *p_line ){ unsigned int i; for( i = 0; p_line->pp_glyphs[ i ] != NULL; i++ ) { FT_Done_Glyph( (FT_Glyph)p_line->pp_glyphs[ i ] ); } free( p_line->pp_glyphs ); free( p_line->p_glyph_pos ); free( p_line );}static void FreeLines( line_desc_t *p_lines ){ line_desc_t *p_line, *p_next; if( !p_lines ) return; for( p_line = p_lines; p_line != NULL; p_line = p_next ) { p_next = p_line->p_next; FreeLine( p_line ); }}static line_desc_t *NewLine( byte_t *psz_string ){ int i_count; line_desc_t *p_line = malloc( sizeof(line_desc_t) ); if( !p_line ) return NULL; p_line->i_height = 0; p_line->i_width = 0; p_line->p_next = NULL; /* We don't use CountUtf8Characters() here because we are not acutally * sure the string is utf8. Better be safe than sorry. */ i_count = strlen( psz_string ); p_line->pp_glyphs = malloc( sizeof(FT_BitmapGlyph) * ( i_count + 1 ) ); if( p_line->pp_glyphs == NULL ) { free( p_line ); return NULL; } p_line->pp_glyphs[0] = NULL; p_line->p_glyph_pos = malloc( sizeof( FT_Vector ) * i_count + 1 ); if( p_line->p_glyph_pos == NULL ) { free( p_line->pp_glyphs ); free( p_line ); return NULL; } return p_line;}static int SetFontSize( filter_t *p_filter, int i_size ){ filter_sys_t *p_sys = p_filter->p_sys; if( i_size && i_size == p_sys->i_font_size ) return VLC_SUCCESS; if( !i_size ) { vlc_value_t val; if( !p_sys->i_default_font_size && p_sys->i_display_height == (int)p_filter->fmt_out.video.i_height ) return VLC_SUCCESS; if( p_sys->i_default_font_size ) { i_size = p_sys->i_default_font_size; } else { var_Get( p_filter, "freetype-rel-fontsize", &val ); i_size = (int)p_filter->fmt_out.video.i_height / val.i_int; p_filter->p_sys->i_display_height = p_filter->fmt_out.video.i_height; } if( i_size <= 0 ) { msg_Warn( p_filter, "Invalid fontsize, using 12" ); i_size = 12; } msg_Dbg( p_filter, "Using fontsize: %i", i_size ); } p_sys->i_font_size = i_size; if( FT_Set_Pixel_Sizes( p_sys->p_face, 0, i_size ) ) { msg_Err( p_filter, "couldn't set font size to %d", i_size ); return VLC_EGENERIC; } return VLC_SUCCESS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -