Canvas 希腊语 google 字体无法正确呈现
Canvas Greek google fonts not rendering correctly
我认为这是一个错误,但如果你们知道任何解决方法,请告诉我。
首先,字体加载101%。
我同步加载Google种字体
我定期检查以确保字体已加载。
我使用 canvas 成功地将字符串转换为图像(使用以下函数)(当
我用英文字符)
渲染几个英文字符后,我尝试渲染一个希腊字符
word 但 canvas 退回到浏览器默认字体。
Firefox 没有任何问题,它运行良好。问题是
Chrome.
Bellow 是根据给定字符串在左上角创建色带标签背景图像的函数(PS:此函数 return imageData 稍后将与其他 imageData 合并):
ImageProcessor.prototype.createLabelImageData = function ( str, size, font, color, backgroundColor, shadowColor, shadowOffsetX, shadowOffsetY, shadowBlur, width, height ) {
this.canvas.width = width || this.settings.width;
this.canvas.height = height || this.settings.height;
this.ctx.clearRect( 0, 0, this.canvas.width, this.canvas.height );
this.ctx.font = "Bold " + ( size || 64 ) + "px " + ( font || "Arial" );
this.ctx.textAlign = "center";
this.ctx.textBaseline = "middle";
var labelHeight = ( size || 64 ) + ( ( size || 64 ) / 4 );
var labelTop = this.canvas.height / 2 - labelHeight / 2;
var labelWidth = this.canvas.width;
var strLen = this.ctx.measureText( str + " " ).width;
var side = Math.sqrt( ( strLen * strLen ) / 2 );
var distance = Math.sqrt( ( side * side ) - ( ( strLen / 2 ) * ( strLen / 2 ) ) );
this.ctx.save();
this.ctx.rotate( -Math.PI / 4 );
this.ctx.translate( -this.canvas.width / 2, -this.canvas.height / 2 + distance );
this.ctx.fillStyle = ( backgroundColor || '#f00' );
this.ctx.beginPath();
this.ctx.moveTo( 0, labelTop );
this.ctx.lineTo( labelWidth, labelTop );
this.ctx.lineTo( labelWidth, labelTop + labelHeight );
this.ctx.lineTo( 0, labelTop + labelHeight );
this.ctx.closePath();
this.ctx.fill();
if ( shadowColor ) {
this.ctx.shadowColor = shadowColor;
this.ctx.shadowOffsetX = ( shadowOffsetX || 0 );
this.ctx.shadowOffsetY = ( shadowOffsetY || 0 );
this.ctx.shadowBlur = ( shadowBlur || size || 64 );
}
this.ctx.fillStyle = ( color || "#fff" );
this.ctx.fillText( str, this.canvas.width / 2, this.canvas.height / 2 );
this.ctx.restore();
var imageData = this.ctx.getImageData( 0, 0, this.canvas.width, this.canvas.height );
this.canvas.width = this.settings.width;
this.canvas.height = this.settings.height;
return imageData;
};
经过一些测试、反复试验和许多小时的阅读...
我发现在canvas中要使用字体时,是否已经下载并不重要。在其他任何事情和任何检查之前对我有用的是创建 n*2 div 元素(n 加载的字体数)并将它们定位在视口之外。 n*2 因为在一些我添加了 font-weight:bold
.
底线是您希望在 canvas 中使用的确切字体必须是:
- 预加载
- 使用所有语言的 innerHTML 文本创建一个虚拟 dom 元素
变体(在我的例子中是拉丁语和希腊语)。
请注意,您必须为字体的粗体变体创建额外的元素。
这是我目前用来预加载字体并确保它们在 canvas 中可用的代码。
Vise.prototype.initializeFonts = function ( settings, globalCallback ) {
var that = this; // reference to parent class
/********************************************
********************************************
**
**
** Default settings
**
**
********************************************
********************************************/
var defaults = {
interval: 100,
timeout: 10000,
families: [
'Open+Sans+Condensed:300,300italic,700:latin,greek',
'Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800:latin,greek',
'Roboto+Condensed:300italic,400italic,700italic,400,700,300:latin,greek',
'Roboto:400,100,100italic,300,300italic,400italic,500,500italic,700,700italic,900,900italic:latin,greek'
]
};
// initialization
this.fonts = new Fonts( $.extend( true, defaults, settings ) );
this.fonts.onload = globalCallback;
this.fonts.load();
};
/********************************************
********************************************
**
**
** Fonts class
**
**
********************************************
********************************************/
function Fonts( settings ) {
this.settings = settings;
this.success = [];
this.fail = [];
this.interval = null;
this.elapsedTime = this.settings.interval;
this.fontDetective = new Detector();
}
Fonts.prototype.load = function () {
WebFont.load( {
google: {
families: this.settings.families
}
} );
for ( var i in this.settings.families ) {
var el, elBold;
var familyStr = this.settings.families[ i ];
var family = familyStr.split( ':' )[ 0 ].replace( /[+]/gi, ' ' );
el = document.createElement( "div" );
el.innerHTML = "Font loader Φόρτωμα γραμματοσειράς";
el.style.fontFamily = family;
el.style.color = "#f00";
el.style.position = "fixed";
el.style.zIndex = 9999;
el.style.left = "9999px";
document.body.appendChild( el );
elBold = document.createElement( "div" );
elBold.innerHTML = "Font loader Φόρτωμα γραμματοσειράς";
elBold.style.fontFamily = family;
elBold.style.fontWeight = "bold";
elBold.style.color = "#f00";
elBold.style.position = "fixed";
elBold.style.zIndex = 9999;
elBold.style.left = "9999px";
document.body.appendChild( elBold );
}
this.interval = setInterval( this.areLoaded.bind( this ), this.settings.interval );
};
Fonts.prototype.areLoaded = function () {
for ( var i in this.settings.families ) {
var familyStr = this.settings.families[ i ];
var family = familyStr.split( ':' )[ 0 ].replace( /[+]/gi, ' ' );
var successIdx, failIdx;
if ( this.fontDetective.detect( family ) ) {
successIdx = this.success.indexOf( family );
failIdx = this.fail.indexOf( family );
if ( successIdx === -1 ) {
this.success.push( family );
console.log( "[" + family + "] was successfully loaded." );
}
if ( failIdx > -1 ) {
this.fail.splice( failIdx, 1 );
}
} else {
successIdx = this.success.indexOf( family );
failIdx = this.fail.indexOf( family );
if ( successIdx > -1 ) {
this.success.splice( successIdx, 1 );
}
if ( failIdx === -1 ) {
this.fail.push( family );
}
}
}
if ( this.elapsedTime >= this.settings.timeout ) {
clearInterval( this.interval );
var err = new Error( "Unable to load fonts: " + this.fail.toString() );
this.onload( err, null );
return;
}
if ( this.success.length === this.settings.families.length ) {
clearInterval( this.interval );
this.onload( null, null );
return;
}
this.elapsedTime += this.settings.interval;
};
这对我有用,以防其他人在 chrome 上遇到同样的问题。
PS:看看我在代码中使用的 fontdetect.js。
我认为这是一个错误,但如果你们知道任何解决方法,请告诉我。
首先,字体加载101%。
我同步加载Google种字体
我定期检查以确保字体已加载。
我使用 canvas 成功地将字符串转换为图像(使用以下函数)(当 我用英文字符)
渲染几个英文字符后,我尝试渲染一个希腊字符 word 但 canvas 退回到浏览器默认字体。
Firefox 没有任何问题,它运行良好。问题是 Chrome.
Bellow 是根据给定字符串在左上角创建色带标签背景图像的函数(PS:此函数 return imageData 稍后将与其他 imageData 合并):
ImageProcessor.prototype.createLabelImageData = function ( str, size, font, color, backgroundColor, shadowColor, shadowOffsetX, shadowOffsetY, shadowBlur, width, height ) {
this.canvas.width = width || this.settings.width;
this.canvas.height = height || this.settings.height;
this.ctx.clearRect( 0, 0, this.canvas.width, this.canvas.height );
this.ctx.font = "Bold " + ( size || 64 ) + "px " + ( font || "Arial" );
this.ctx.textAlign = "center";
this.ctx.textBaseline = "middle";
var labelHeight = ( size || 64 ) + ( ( size || 64 ) / 4 );
var labelTop = this.canvas.height / 2 - labelHeight / 2;
var labelWidth = this.canvas.width;
var strLen = this.ctx.measureText( str + " " ).width;
var side = Math.sqrt( ( strLen * strLen ) / 2 );
var distance = Math.sqrt( ( side * side ) - ( ( strLen / 2 ) * ( strLen / 2 ) ) );
this.ctx.save();
this.ctx.rotate( -Math.PI / 4 );
this.ctx.translate( -this.canvas.width / 2, -this.canvas.height / 2 + distance );
this.ctx.fillStyle = ( backgroundColor || '#f00' );
this.ctx.beginPath();
this.ctx.moveTo( 0, labelTop );
this.ctx.lineTo( labelWidth, labelTop );
this.ctx.lineTo( labelWidth, labelTop + labelHeight );
this.ctx.lineTo( 0, labelTop + labelHeight );
this.ctx.closePath();
this.ctx.fill();
if ( shadowColor ) {
this.ctx.shadowColor = shadowColor;
this.ctx.shadowOffsetX = ( shadowOffsetX || 0 );
this.ctx.shadowOffsetY = ( shadowOffsetY || 0 );
this.ctx.shadowBlur = ( shadowBlur || size || 64 );
}
this.ctx.fillStyle = ( color || "#fff" );
this.ctx.fillText( str, this.canvas.width / 2, this.canvas.height / 2 );
this.ctx.restore();
var imageData = this.ctx.getImageData( 0, 0, this.canvas.width, this.canvas.height );
this.canvas.width = this.settings.width;
this.canvas.height = this.settings.height;
return imageData;
};
经过一些测试、反复试验和许多小时的阅读...
我发现在canvas中要使用字体时,是否已经下载并不重要。在其他任何事情和任何检查之前对我有用的是创建 n*2 div 元素(n 加载的字体数)并将它们定位在视口之外。 n*2 因为在一些我添加了 font-weight:bold
.
底线是您希望在 canvas 中使用的确切字体必须是:
- 预加载
- 使用所有语言的 innerHTML 文本创建一个虚拟 dom 元素 变体(在我的例子中是拉丁语和希腊语)。
请注意,您必须为字体的粗体变体创建额外的元素。
这是我目前用来预加载字体并确保它们在 canvas 中可用的代码。
Vise.prototype.initializeFonts = function ( settings, globalCallback ) {
var that = this; // reference to parent class
/********************************************
********************************************
**
**
** Default settings
**
**
********************************************
********************************************/
var defaults = {
interval: 100,
timeout: 10000,
families: [
'Open+Sans+Condensed:300,300italic,700:latin,greek',
'Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800:latin,greek',
'Roboto+Condensed:300italic,400italic,700italic,400,700,300:latin,greek',
'Roboto:400,100,100italic,300,300italic,400italic,500,500italic,700,700italic,900,900italic:latin,greek'
]
};
// initialization
this.fonts = new Fonts( $.extend( true, defaults, settings ) );
this.fonts.onload = globalCallback;
this.fonts.load();
};
/********************************************
********************************************
**
**
** Fonts class
**
**
********************************************
********************************************/
function Fonts( settings ) {
this.settings = settings;
this.success = [];
this.fail = [];
this.interval = null;
this.elapsedTime = this.settings.interval;
this.fontDetective = new Detector();
}
Fonts.prototype.load = function () {
WebFont.load( {
google: {
families: this.settings.families
}
} );
for ( var i in this.settings.families ) {
var el, elBold;
var familyStr = this.settings.families[ i ];
var family = familyStr.split( ':' )[ 0 ].replace( /[+]/gi, ' ' );
el = document.createElement( "div" );
el.innerHTML = "Font loader Φόρτωμα γραμματοσειράς";
el.style.fontFamily = family;
el.style.color = "#f00";
el.style.position = "fixed";
el.style.zIndex = 9999;
el.style.left = "9999px";
document.body.appendChild( el );
elBold = document.createElement( "div" );
elBold.innerHTML = "Font loader Φόρτωμα γραμματοσειράς";
elBold.style.fontFamily = family;
elBold.style.fontWeight = "bold";
elBold.style.color = "#f00";
elBold.style.position = "fixed";
elBold.style.zIndex = 9999;
elBold.style.left = "9999px";
document.body.appendChild( elBold );
}
this.interval = setInterval( this.areLoaded.bind( this ), this.settings.interval );
};
Fonts.prototype.areLoaded = function () {
for ( var i in this.settings.families ) {
var familyStr = this.settings.families[ i ];
var family = familyStr.split( ':' )[ 0 ].replace( /[+]/gi, ' ' );
var successIdx, failIdx;
if ( this.fontDetective.detect( family ) ) {
successIdx = this.success.indexOf( family );
failIdx = this.fail.indexOf( family );
if ( successIdx === -1 ) {
this.success.push( family );
console.log( "[" + family + "] was successfully loaded." );
}
if ( failIdx > -1 ) {
this.fail.splice( failIdx, 1 );
}
} else {
successIdx = this.success.indexOf( family );
failIdx = this.fail.indexOf( family );
if ( successIdx > -1 ) {
this.success.splice( successIdx, 1 );
}
if ( failIdx === -1 ) {
this.fail.push( family );
}
}
}
if ( this.elapsedTime >= this.settings.timeout ) {
clearInterval( this.interval );
var err = new Error( "Unable to load fonts: " + this.fail.toString() );
this.onload( err, null );
return;
}
if ( this.success.length === this.settings.families.length ) {
clearInterval( this.interval );
this.onload( null, null );
return;
}
this.elapsedTime += this.settings.interval;
};
这对我有用,以防其他人在 chrome 上遇到同样的问题。
PS:看看我在代码中使用的 fontdetect.js。