static FT_Outline* getFTOutline(JNIEnv* env, jobject font2D, FTScalerContext *context, FTScalerInfo* scalerInfo, jint glyphCode, jfloat xpos, jfloat ypos) { int renderFlags; int glyph_index; FT_Error error; FT_GlyphSlot ftglyph; if (glyphCode >= INVISIBLE_GLYPHS || isNullScalerContext(context) || scalerInfo == NULL) { return NULL; } error = setupFTContext(env, font2D, scalerInfo, context); if (error) { return NULL; } renderFlags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; glyph_index = FT_Get_Char_Index(scalerInfo->face, glyphCode); error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags); if (error) { return NULL; } ftglyph = scalerInfo->face->glyph; /* apply styles */ if (context->doBold) { /* if bold style */ FT_GlyphSlot_Embolden(ftglyph); } if (context->doItalize) { /* if oblique */ FT_GlyphSlot_Oblique(ftglyph); } FT_Outline_Translate(&ftglyph->outline, FloatToF26Dot6(xpos), -FloatToF26Dot6(ypos)); return &ftglyph->outline; }
static void freetype2_drawtext(PFont pfont, image_p pimage, int x, int y, const void *text, int cc, int flags) { PFontFreetype pf = (PFontFreetype) pfont; uint16_t* value; FT_Glyph glyph; int pen_x = x; int pen_y = y + pf->size; int i; FT_BitmapGlyph bitmap_glyph; FT_Bitmap* bitmap; value = _nge_ft_conv_encoding(pfont, text, &cc); if (cc <= 0) return; if(pimage->swizzle ==1){ unswizzle_swap(pimage); pimage->dontswizzle = 1; } pimage->modified =1; for (i =0;i<cc;i++) { FT_Load_Glyph( pf->face, FT_Get_Char_Index( pf->face, value[i] ), FT_LOAD_DEFAULT ); if(pf->flags & FLAGS_FREETYPE_BOLD) FT_GlyphSlot_Embolden(pf->face->glyph); if(pf->flags & FLAGS_FREETYPE_ITALICS) FT_GlyphSlot_Oblique(pf->face->glyph); FT_Get_Glyph( pf->face->glyph, &glyph ); FT_Render_Glyph( pf->face->glyph, ft_render_mode_normal ); FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 ); bitmap_glyph = (FT_BitmapGlyph)glyph; bitmap=&bitmap_glyph->bitmap; draw_one_word(pf,bitmap,pimage,pen_x + pf->face->glyph->bitmap_left,pen_y - pf->face->glyph->bitmap_top ); pen_x +=(pf->face->glyph->advance.x+pf->fix_width*72) >> 6 ; FT_Done_Glyph( glyph ); } }
/** * \brief Get a glyph * \param ch character code **/ FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch, ass_hinting_t hinting) { int error; int index = 0; int i; FT_Glyph glyph; FT_Face face = 0; int flags = 0; if (ch < 0x20) return 0; if (font->n_faces == 0) return 0; for (i = 0; i < font->n_faces; ++i) { face = font->faces[i]; index = FT_Get_Char_Index(face, ch); if (index) break; } #ifdef HAVE_FONTCONFIG if (index == 0) { int face_idx; mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_GlyphNotFoundReselectingFont, ch, font->desc.family, font->desc.bold, font->desc.italic); face_idx = add_face(fontconfig_priv, font, ch); if (face_idx >= 0) { face = font->faces[face_idx]; index = FT_Get_Char_Index(face, ch); if (index == 0) { mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_GlyphNotFound, ch, font->desc.family, font->desc.bold, font->desc.italic); } } } #endif switch (hinting) { case ASS_HINTING_NONE: flags = FT_LOAD_NO_HINTING; break; case ASS_HINTING_LIGHT: flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT; break; case ASS_HINTING_NORMAL: flags = FT_LOAD_FORCE_AUTOHINT; break; case ASS_HINTING_NATIVE: flags = 0; break; } error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP | flags); if (error) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph); return 0; } #if (FREETYPE_MAJOR > 2) || \ ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2)) || \ ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 10)) // FreeType >= 2.1.10 required if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) && (font->desc.italic > 55)) { FT_GlyphSlot_Oblique(face->glyph); } #endif error = FT_Get_Glyph(face->glyph, &glyph); if (error) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph); return 0; } return glyph; }
/* * Load the glyphs of a paragraph. When shaping with HarfBuzz the glyph indices * have already been determined at this point, as well as the advance values. */ static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph, bool b_use_glyph_indices, bool b_overwrite_advance ) { if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0 ) { msg_Err( p_filter, "LoadGlyphs() invalid parameters. " "Paragraph size: %d. Runs count %d", p_paragraph->i_size, p_paragraph->i_runs_count ); return VLC_EGENERIC; } filter_sys_t *p_sys = p_filter->p_sys; for( int i = 0; i < p_paragraph->i_runs_count; ++i ) { run_desc_t *p_run = p_paragraph->p_runs + i; text_style_t *p_style = p_run->p_style; FT_Face p_face = 0; if( !p_run->p_face ) { p_face = LoadFace( p_filter, p_style ); if( !p_face ) { p_face = p_sys->p_face; p_style = &p_sys->style; p_run->p_style = p_style; } p_run->p_face = p_face; } else p_face = p_run->p_face; if( p_sys->p_stroker ) { double f_outline_thickness = var_InheritInteger( p_filter, "freetype-outline-thickness" ) / 100.0; f_outline_thickness = VLC_CLIP( f_outline_thickness, 0.0, 0.5 ); int i_radius = ( p_style->i_font_size << 6 ) * f_outline_thickness; FT_Stroker_Set( p_sys->p_stroker, i_radius, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 ); } for( int j = p_run->i_start_offset; j < p_run->i_end_offset; ++j ) { int i_glyph_index; if( b_use_glyph_indices ) i_glyph_index = p_paragraph->pi_glyph_indices[ j ]; else i_glyph_index = FT_Get_Char_Index( p_face, p_paragraph->p_code_points[ j ] ); glyph_bitmaps_t *p_bitmaps = p_paragraph->p_glyph_bitmaps + j; if( FT_Load_Glyph( p_face, i_glyph_index, FT_LOAD_NO_BITMAP | FT_LOAD_DEFAULT ) && FT_Load_Glyph( p_face, i_glyph_index, FT_LOAD_DEFAULT ) ) { p_bitmaps->p_glyph = 0; p_bitmaps->p_outline = 0; p_bitmaps->p_shadow = 0; p_bitmaps->i_x_advance = 0; p_bitmaps->i_y_advance = 0; continue; } if( ( p_style->i_style_flags & STYLE_BOLD ) && !( p_face->style_flags & FT_STYLE_FLAG_BOLD ) ) FT_GlyphSlot_Embolden( p_face->glyph ); if( ( p_style->i_style_flags & STYLE_ITALIC ) && !( p_face->style_flags & FT_STYLE_FLAG_ITALIC ) ) FT_GlyphSlot_Oblique( p_face->glyph ); if( FT_Get_Glyph( p_face->glyph, &p_bitmaps->p_glyph ) ) { p_bitmaps->p_glyph = 0; p_bitmaps->p_outline = 0; p_bitmaps->p_shadow = 0; p_bitmaps->i_x_advance = 0; p_bitmaps->i_y_advance = 0; continue; } if( p_filter->p_sys->p_stroker ) { p_bitmaps->p_outline = p_bitmaps->p_glyph; if( FT_Glyph_StrokeBorder( &p_bitmaps->p_outline, p_filter->p_sys->p_stroker, 0, 0 ) ) p_bitmaps->p_outline = 0; } if( p_filter->p_sys->style.i_shadow_alpha > 0 ) p_bitmaps->p_shadow = p_bitmaps->p_outline ? p_bitmaps->p_outline : p_bitmaps->p_glyph; if( b_overwrite_advance ) { p_bitmaps->i_x_advance = p_face->glyph->advance.x; p_bitmaps->i_y_advance = p_face->glyph->advance.y; } } } return VLC_SUCCESS; }
/* * Class: sun_font_FreetypeFontScaler * Method: getGlyphImageNative * Signature: (Lsun/font/Font2D;JI)J */ JNIEXPORT jlong JNICALL Java_sun_font_FreetypeFontScaler_getGlyphImageNative( JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext, jlong pScaler, jint glyphCode) { int error, imageSize; UInt16 width, height; GlyphInfo *glyphInfo; int glyph_index; int renderFlags = FT_LOAD_RENDER, target; FT_GlyphSlot ftglyph; FTScalerContext* context = (FTScalerContext*) jlong_to_ptr(pScalerContext); FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler); if (isNullScalerContext(context) || scalerInfo == NULL) { return ptr_to_jlong(getNullGlyphImage()); } error = setupFTContext(env, font2D, scalerInfo, context); if (error) { invalidateJavaScaler(env, scaler, scalerInfo); return ptr_to_jlong(getNullGlyphImage()); } /* if algorithmic styling is required then we do not request bitmap */ if (context->doBold || context->doItalize) { renderFlags = FT_LOAD_DEFAULT; } /* NB: in case of non identity transform we might also prefer to disable transform before hinting, and apply it explicitly after hinting is performed. Or we can disable hinting. */ /* select appropriate hinting mode */ if (context->aaType == TEXT_AA_OFF) { target = FT_LOAD_TARGET_MONO; } else if (context->aaType == TEXT_AA_ON) { target = FT_LOAD_TARGET_NORMAL; } else if (context->aaType == TEXT_AA_LCD_HRGB || context->aaType == TEXT_AA_LCD_HBGR) { target = FT_LOAD_TARGET_LCD; } else { target = FT_LOAD_TARGET_LCD_V; } renderFlags |= target; glyph_index = FT_Get_Char_Index(scalerInfo->face, glyphCode); error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags); if (error) { //do not destroy scaler yet. //this can be problem of particular context (e.g. with bad transform) return ptr_to_jlong(getNullGlyphImage()); } ftglyph = scalerInfo->face->glyph; /* apply styles */ if (context->doBold) { /* if bold style */ FT_GlyphSlot_Embolden(ftglyph); } if (context->doItalize) { /* if oblique */ FT_GlyphSlot_Oblique(ftglyph); } /* generate bitmap if it is not done yet e.g. if algorithmic styling is performed and style was added to outline */ if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) { FT_Render_Glyph(ftglyph, FT_LOAD_TARGET_MODE(target)); } width = (UInt16) ftglyph->bitmap.width; height = (UInt16) ftglyph->bitmap.rows; imageSize = width*height; glyphInfo = (GlyphInfo*) malloc(sizeof(GlyphInfo) + imageSize); if (glyphInfo == NULL) { glyphInfo = getNullGlyphImage(); return ptr_to_jlong(glyphInfo); } glyphInfo->cellInfo = NULL; glyphInfo->managed = UNMANAGED_GLYPH; glyphInfo->rowBytes = width; glyphInfo->width = width; glyphInfo->height = height; glyphInfo->topLeftX = (float) ftglyph->bitmap_left; glyphInfo->topLeftY = (float) -ftglyph->bitmap_top; if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) { glyphInfo->width = width/3; } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) { glyphInfo->height = glyphInfo->height/3; } if (context->fmType == TEXT_FM_ON) { double advh = FTFixedToFloat(ftglyph->linearHoriAdvance); glyphInfo->advanceX = (float) (advh * FTFixedToFloat(context->transform.xx)); glyphInfo->advanceY = (float) (advh * FTFixedToFloat(context->transform.xy)); } else { if (!ftglyph->advance.y) { glyphInfo->advanceX = (float) ROUND(FT26Dot6ToFloat(ftglyph->advance.x)); glyphInfo->advanceY = 0; } else if (!ftglyph->advance.x) { glyphInfo->advanceX = 0; glyphInfo->advanceY = (float) ROUND(FT26Dot6ToFloat(-ftglyph->advance.y)); } else { glyphInfo->advanceX = FT26Dot6ToFloat(ftglyph->advance.x); glyphInfo->advanceY = FT26Dot6ToFloat(-ftglyph->advance.y); } } if (imageSize == 0) { glyphInfo->image = NULL; } else { glyphInfo->image = (unsigned char*) glyphInfo + sizeof(GlyphInfo); //convert result to output format //output format is either 3 bytes per pixel (for subpixel modes) // or 1 byte per pixel for AA and B&W if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { /* convert from 8 pixels per byte to 1 byte per pixel */ CopyBW2Grey8(ftglyph->bitmap.buffer, ftglyph->bitmap.pitch, (void *) glyphInfo->image, width, width, height); } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) { /* byte per pixel to byte per pixel => just copy */ memcpy(glyphInfo->image, ftglyph->bitmap.buffer, imageSize); } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY4) { /* 4 bits per pixel to byte per pixel */ CopyGrey4ToGrey8(ftglyph->bitmap.buffer, ftglyph->bitmap.pitch, (void *) glyphInfo->image, width, width, height); } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) { /* 3 bytes per pixel to 3 bytes per pixel */ CopyFTSubpixelToSubpixel(ftglyph->bitmap.buffer, ftglyph->bitmap.pitch, (void *) glyphInfo->image, width, width, height); } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) { /* 3 bytes per pixel to 3 bytes per pixel */ CopyFTSubpixelVToSubpixel(ftglyph->bitmap.buffer, ftglyph->bitmap.pitch, (void *) glyphInfo->image, width*3, width, height); glyphInfo->rowBytes *=3; } else { free(glyphInfo); glyphInfo = getNullGlyphImage(); } } return ptr_to_jlong(glyphInfo); }
static int _draw_string(FT_Face face, const uint8_t *string, int length, TEXTST_BITMAP *bmp, int x, int y, BD_TEXTST_REGION_STYLE *style, int *baseline_pos) { uint8_t color = style->font_color; unsigned char_code; int ii, jj, kk; unsigned flags; if (length <= 0) { return -1; } if (!bmp) { flags = FT_LOAD_DEFAULT; } else { flags = FT_LOAD_RENDER; } for (ii = 0; ii < length; ii++) { /*if (p->char_code == BLURAY_TEXT_CHAR_CODE_UTF8) {*/ int char_size = _utf8_char_size(string + ii); char_code = _utf8_char_get(string + ii, char_size); ii += char_size - 1; /*}*/ if (FT_Load_Char(face, char_code, flags /*| FT_LOAD_MONOCHROME*/) == 0) { if (style->font_style.bold && !(face->style_flags & FT_STYLE_FLAG_BOLD)) { FT_GlyphSlot_Embolden( face->glyph ); } if (style->font_style.italic && !(face->style_flags & FT_STYLE_FLAG_ITALIC)) { FT_GlyphSlot_Oblique( face->glyph ); } if (bmp) { for (jj = 0; jj < face->glyph->bitmap.rows; jj++) { for (kk = 0; kk < face->glyph->bitmap.width; kk++) { uint8_t pixel = face->glyph->bitmap.buffer[jj * face->glyph->bitmap.pitch + kk]; if (pixel & 0x80) { int xpos = x + face->glyph->bitmap_left + kk; int ypos = y - face->glyph->bitmap_top + jj; if (xpos >= 0 && xpos < bmp->width && ypos >= 0 && ypos < bmp->height) { bmp->mem[xpos + ypos * bmp->stride] = color; } } } } } /* track max baseline when calculating line size */ if (baseline_pos) { *baseline_pos = BD_MAX(*baseline_pos, (face->size->metrics.ascender >> 6) + 1); } x += face->glyph->metrics.horiAdvance >> 6; } } return x; }