Skip to content

Commit 232d5bd

Browse files
committed
实现文本内容
1 parent 4dbb824 commit 232d5bd

5 files changed

Lines changed: 317 additions & 131 deletions

File tree

Workbench/Wmf/SkiaWmfRenderer/src/SkiaWmfRenderer/Rendering/WmfRenderer.cs

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
using System.Diagnostics.CodeAnalysis;
2-
using Oxage.Wmf;
1+
using Oxage.Wmf;
32
using Oxage.Wmf.Records;
43
using SkiaSharp;
4+
using System;
5+
using System.Diagnostics.CodeAnalysis;
56

67
namespace SkiaWmfRenderer.Rendering;
78

@@ -392,6 +393,56 @@ private static bool RenderRecord(SKCanvas canvas, WmfRenderStatus renderStatus,
392393
renderStatus.IsItalic = createFontIndirectRecord.Italic;
393394
renderStatus.FontWeight = createFontIndirectRecord.Weight;
394395
}
396+
else if (wmfDocumentRecord is WmfExtTextoutRecord extTextoutRecord)
397+
{
398+
renderStatus.IsIncludeText = true;
399+
400+
// 是否包含了其他编码
401+
var isIncludeOtherEncoding = renderStatus.CurrentCharacterSet != CharacterSet.DEFAULT_CHARSET;
402+
renderStatus.IsIncludeOtherEncoding |=
403+
isIncludeOtherEncoding;
404+
405+
var isIncludeTextWithDx = renderStatus.LastDxOffset > 0;
406+
renderStatus.IsIncludeTextWithDx |=
407+
isIncludeTextWithDx;
408+
409+
var text = extTextoutRecord.GetText(renderStatus.CurrentEncoding);
410+
411+
var currentXOffset = renderStatus.CurrentX + extTextoutRecord.X + renderStatus.LastDxOffset;
412+
413+
renderStatus.UpdateSkiaTextStatus();
414+
415+
if (extTextoutRecord.Dx is null)
416+
{
417+
canvas.DrawText(text, currentXOffset, renderStatus.CurrentY + extTextoutRecord.Y, renderStatus.SKFont,
418+
renderStatus.Paint);
419+
}
420+
else
421+
{
422+
// 关于字间距的规则:
423+
// 1. 如果两个 META_EXTTEXTOUT 相邻,中间没有 MoveTo 之类
424+
// 则第二个 META_EXTTEXTOUT 将需要使用前一个 META_EXTTEXTOUT 的 dx 末项
425+
// 2. 可选的 dx 是存放在字符串末尾的可选项,从文档 2.3.3.5 上可见 dx 是顶格写的,这就意味着这个值是一定对齐整数倍的。由于 dx 是放在数据末尾,可通过减法算出 dx 长度,即数据总长度减去所有已知字段的长度加上字符串长度,剩余的就是 dx 长度。如果计算返回的 dx 长度是奇数,则首个 byte 是需要跳过的,如此就能确保在 16bit 下的 wmf 格式里面,读取的 dx 是从整数倍开始读取
426+
// 参考 https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/nf-wingdi-exttextoutw
427+
// 测试 17 项
428+
429+
if (extTextoutRecord.Dx.Length != text.Length)
430+
{
431+
return false;
432+
}
433+
434+
for (var textIndex = 0; textIndex < text.Length; textIndex++)
435+
{
436+
canvas.DrawText(text[textIndex].ToString(), currentXOffset,
437+
renderStatus.CurrentY + extTextoutRecord.Y, renderStatus.SKFont,
438+
renderStatus.Paint);
439+
440+
currentXOffset += extTextoutRecord.Dx[textIndex];
441+
}
442+
443+
renderStatus.LastDxOffset = extTextoutRecord.Dx[^1];
444+
}
445+
}
395446
else if (wmfDocumentRecord is WmfUnknownRecord unknownRecord)
396447
{
397448
switch (unknownRecord.RecordType)
@@ -406,14 +457,14 @@ private static bool RenderRecord(SKCanvas canvas, WmfRenderStatus renderStatus,
406457
// 2. 可选的 dx 是存放在字符串末尾的可选项,从文档 2.3.3.5 上可见 dx 是顶格写的,这就意味着这个值是一定对齐整数倍的。由于 dx 是放在数据末尾,可通过减法算出 dx 长度,即数据总长度减去所有已知字段的长度加上字符串长度,剩余的就是 dx 长度。如果计算返回的 dx 长度是奇数,则首个 byte 是需要跳过的,如此就能确保在 16bit 下的 wmf 格式里面,读取的 dx 是从整数倍开始读取
407458
// 参考 https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/nf-wingdi-exttextoutw
408459
// 测试 17 项
409-
var memoryStream = new MemoryStream(unknownRecord.Data);
460+
var memoryStream = new MemoryStream(unknownRecord.Data);
410461
var binaryReader = new BinaryReader(memoryStream);
411462
var ty = binaryReader.ReadUInt16();
412463
var tx = binaryReader.ReadUInt16();
413464
var stringLength = binaryReader.ReadUInt16();
414465
var fwOpts = (ExtTextOutOptions)binaryReader.ReadUInt16();
415466
// Rectangle (8 bytes): An optional 8-byte Rect Object (section 2.2.2.18).) When either ETO_CLIPPED, ETO_OPAQUE, or both are specified, the rectangle defines the dimensions, in logical coordinates, used for clipping, opaquing, or both. When neither ETO_CLIPPED nor ETO_OPAQUE is specified, the coordinates in Rectangle are ignored.
416-
var st = 8; /*2byte ofr ty tx stringLength fwOpts*/
467+
var st = 8; /*2byte of ty tx stringLength fwOpts*/
417468
if (fwOpts is ExtTextOutOptions.ETO_CLIPPED or ExtTextOutOptions.ETO_OPAQUE)
418469
{
419470
// 此时才有 Rectangle 的值
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Text;
2+
3+
namespace Oxage.Wmf.Extensions;
4+
5+
static class Converters
6+
{
7+
public static Encoding ToEncoding(this CharacterSet characterSet)
8+
{
9+
var codePageId = characterSet switch
10+
{
11+
CharacterSet.ANSI_CHARSET
12+
// DEFAULT_CHARSET: Specifies a character set based on the current system locale; for example, when the system locale is United States English, the default character set is ANSI_CHARSET.
13+
or CharacterSet.DEFAULT_CHARSET => 1252,
14+
CharacterSet.OEM_CHARSET => 437,
15+
CharacterSet.SHIFTJIS_CHARSET => 932,
16+
CharacterSet.HANGUL_CHARSET => 949,
17+
CharacterSet.JOHAB_CHARSET => 1361,
18+
CharacterSet.GB2312_CHARSET => 936,
19+
CharacterSet.CHINESEBIG5_CHARSET => 950,
20+
CharacterSet.HEBREW_CHARSET => 1255,
21+
CharacterSet.ARABIC_CHARSET => 1256,
22+
CharacterSet.GREEK_CHARSET => 1253,
23+
CharacterSet.TURKISH_CHARSET => 1254,
24+
CharacterSet.BALTIC_CHARSET => 1257,
25+
CharacterSet.EASTEUROPE_CHARSET => 1250,
26+
CharacterSet.RUSSIAN_CHARSET => 1251,
27+
CharacterSet.THAI_CHARSET => 874,
28+
CharacterSet.VIETNAMESE_CHARSET => 1258,
29+
CharacterSet.SYMBOL_CHARSET => 42, // Symbol font is not a code page, but 42 is often used for Symbol font
30+
_ => 1252,
31+
};
32+
33+
return Encoding.GetEncoding(codePageId);
34+
}
35+
}

0 commit comments

Comments
 (0)