Skip to content

Commit b5147fe

Browse files
committed
加上判断能否渲染的条件
1 parent 840c065 commit b5147fe

2 files changed

Lines changed: 102 additions & 83 deletions

File tree

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ public void UpdateSkiaFillStatus()
8080
Paint.Color = CurrentFillColor;
8181
}
8282

83+
public bool IsIncludeText { get; set; } = false;
84+
public bool IsIncludeOtherEncoding { get; set; } = false;
85+
public bool IsIncludeTextWithDx { get; set; } = false;
86+
8387
public void Dispose()
8488
{
8589
Paint.Dispose();

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

Lines changed: 98 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
using System.Diagnostics.CodeAnalysis;
2-
32
using Oxage.Wmf;
43
using Oxage.Wmf.Records;
5-
64
using SkiaSharp;
75

86
namespace SkiaWmfRenderer.Rendering;
@@ -74,11 +72,11 @@ public bool TryRender([NotNullWhen(true)] out SKBitmap? skBitmap)
7472
{
7573
var format = WmfDocument.Format;
7674
var offsetX = format.Right > format.Left
77-
? -format.Left
78-
: -format.Right;
75+
? -format.Left
76+
: -format.Right;
7977
var offsetY = format.Bottom > format.Top
80-
? -format.Top
81-
: -format.Bottom;
78+
? -format.Top
79+
: -format.Bottom;
8280

8381
var width = Math.Abs(format.Right - format.Left);
8482
var height = Math.Abs(format.Bottom - format.Top);
@@ -92,9 +90,9 @@ public bool TryRender([NotNullWhen(true)] out SKBitmap? skBitmap)
9290
if (renderWidth > MaxWidth)
9391
{
9492
// 约束宽度为最大宽度
95-
var sx = MaxWidth / (float) renderWidth;
93+
var sx = MaxWidth / (float)renderWidth;
9694
renderWidth = MaxWidth;
97-
renderHeight = (int) Math.Round(renderHeight * sx);
95+
renderHeight = (int)Math.Round(renderHeight * sx);
9896
}
9997
else
10098
{
@@ -103,19 +101,19 @@ public bool TryRender([NotNullWhen(true)] out SKBitmap? skBitmap)
103101
}
104102
else
105103
{
106-
var sx = requestWidth / (float) renderWidth;
104+
var sx = requestWidth / (float)renderWidth;
107105
renderWidth = requestWidth;
108-
renderHeight = (int) Math.Round(renderHeight * sx);
106+
renderHeight = (int)Math.Round(renderHeight * sx);
109107
}
110108

111109
var requestHeight = RequestHeight;
112110
if (requestHeight == 0)
113111
{
114112
if (renderHeight > MaxHeight)
115113
{
116-
var sy = MaxHeight / (float) renderHeight;
114+
var sy = MaxHeight / (float)renderHeight;
117115
renderHeight = MaxHeight;
118-
renderWidth = (int) Math.Round(renderWidth * sy);
116+
renderWidth = (int)Math.Round(renderWidth * sy);
119117
}
120118
else
121119
{
@@ -130,19 +128,19 @@ public bool TryRender([NotNullWhen(true)] out SKBitmap? skBitmap)
130128
}
131129
else
132130
{
133-
var sy = requestHeight / (float) renderHeight;
131+
var sy = requestHeight / (float)renderHeight;
134132
renderHeight = requestHeight;
135-
renderWidth = (int) Math.Round(renderWidth * sy);
133+
renderWidth = (int)Math.Round(renderWidth * sy);
136134
}
137135
}
138136

139-
var scaleX = (float) renderWidth / width;
140-
var scaleY = (float) renderHeight / height;
137+
var scaleX = (float)renderWidth / width;
138+
var scaleY = (float)renderHeight / height;
141139

142140
var skBitmap = new SKBitmap(renderWidth, renderHeight, SKColorType.Bgra8888, SKAlphaType.Premul);
143141

144142
SKCanvas canvas = new SKCanvas(skBitmap);
145-
143+
146144
canvas.Scale(scaleX, scaleY);
147145
//canvas.Translate(offsetX, offsetY);
148146
canvas.Save();
@@ -184,7 +182,7 @@ private static bool RenderRecord(SKCanvas canvas, WmfRenderStatus renderStatus,
184182

185183
if (setWindow.X > 0 && setWindow.Y > 0)
186184
{
187-
var scaleX = renderStatus.Width / (float) setWindow.X;
185+
var scaleX = renderStatus.Width / (float)setWindow.X;
188186
var scaleY = renderStatus.Height / (float)setWindow.Y;
189187

190188
canvas.Scale(scaleX, scaleY);
@@ -391,86 +389,103 @@ private static bool RenderRecord(SKCanvas canvas, WmfRenderStatus renderStatus,
391389
switch (unknownRecord.RecordType)
392390
{
393391
case RecordType.META_EXTTEXTOUT:
392+
{
393+
renderStatus.IsIncludeText = true;
394+
395+
// 关于字间距的规则:
396+
// 1. 如果两个 META_EXTTEXTOUT 相邻,中间没有 MoveTo 之类
397+
// 则第二个 META_EXTTEXTOUT 将需要使用前一个 META_EXTTEXTOUT 的 dx 末项
398+
// 2. 可选的 dx 是存放在字符串末尾的可选项,从文档 2.3.3.5 上可见 dx 是顶格写的,这就意味着这个值是一定对齐整数倍的。由于 dx 是放在数据末尾,可通过减法算出 dx 长度,即数据总长度减去所有已知字段的长度加上字符串长度,剩余的就是 dx 长度。如果计算返回的 dx 长度是奇数,则首个 byte 是需要跳过的,如此就能确保在 16bit 下的 wmf 格式里面,读取的 dx 是从整数倍开始读取
399+
// 参考 https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/nf-wingdi-exttextoutw
400+
// 测试 17 项
401+
var memoryStream = new MemoryStream(unknownRecord.Data);
402+
var binaryReader = new BinaryReader(memoryStream);
403+
var ty = binaryReader.ReadUInt16();
404+
var tx = binaryReader.ReadUInt16();
405+
var stringLength = binaryReader.ReadUInt16();
406+
var fwOpts = (ExtTextOutOptions)binaryReader.ReadUInt16();
407+
// 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.
408+
var st = 8; /*2byte ofr ty tx stringLength fwOpts*/
409+
if (fwOpts is ExtTextOutOptions.ETO_CLIPPED or ExtTextOutOptions.ETO_OPAQUE)
394410
{
395-
// 关于字间距的规则:
396-
// 1. 如果两个 META_EXTTEXTOUT 相邻,中间没有 MoveTo 之类
397-
// 则第二个 META_EXTTEXTOUT 将需要使用前一个 META_EXTTEXTOUT 的 dx 末项
398-
// 2. 可选的 dx 是存放在字符串末尾的可选项,从文档 2.3.3.5 上可见 dx 是顶格写的,这就意味着这个值是一定对齐整数倍的。由于 dx 是放在数据末尾,可通过减法算出 dx 长度,即数据总长度减去所有已知字段的长度加上字符串长度,剩余的就是 dx 长度。如果计算返回的 dx 长度是奇数,则首个 byte 是需要跳过的,如此就能确保在 16bit 下的 wmf 格式里面,读取的 dx 是从整数倍开始读取
399-
// 参考 https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/nf-wingdi-exttextoutw
400-
// 测试 17 项
401-
var memoryStream = new MemoryStream(unknownRecord.Data);
402-
var binaryReader = new BinaryReader(memoryStream);
403-
var ty = binaryReader.ReadUInt16();
404-
var tx = binaryReader.ReadUInt16();
405-
var stringLength = binaryReader.ReadUInt16();
406-
var fwOpts = (ExtTextOutOptions) binaryReader.ReadUInt16();
407-
// 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.
408-
var st = 8; /*2byte ofr ty tx stringLength fwOpts*/
409-
if (fwOpts is ExtTextOutOptions.ETO_CLIPPED or ExtTextOutOptions.ETO_OPAQUE)
410-
{
411-
// 此时才有 Rectangle 的值
412-
binaryReader.ReadBytes(8);
413-
st += 8;
414-
}
411+
// 此时才有 Rectangle 的值
412+
binaryReader.ReadBytes(8);
413+
st += 8;
414+
}
415+
416+
st += stringLength;
415417

416-
st += stringLength;
418+
// String (variable): A variable-length string that specifies the text to be drawn. The string does not need to be null-terminated, because StringLength specifies the length of the string. If the length is odd, an extra byte is placed after it so that the following member (optional Dx) is aligned on a 16-bit boundary. The string will be decoded based on the font object currently selected into the playback device context. If a font matching the font object’s specification is not found, the decoding is undefined. If a matching font is found that matches the charset specified in the font object, the string should be decoded with the codepages in the following table.
419+
var stringBuffer = binaryReader.ReadBytes(stringLength);
420+
var text = renderStatus.CurrentEncoding.GetString(stringBuffer);
417421

418-
// String (variable): A variable-length string that specifies the text to be drawn. The string does not need to be null-terminated, because StringLength specifies the length of the string. If the length is odd, an extra byte is placed after it so that the following member (optional Dx) is aligned on a 16-bit boundary. The string will be decoded based on the font object currently selected into the playback device context. If a font matching the font object’s specification is not found, the decoding is undefined. If a matching font is found that matches the charset specified in the font object, the string should be decoded with the codepages in the following table.
419-
var stringBuffer = binaryReader.ReadBytes(stringLength);
420-
var text = renderStatus.CurrentEncoding.GetString(stringBuffer);
422+
// 是否包含了其他编码
423+
var isIncludeOtherEncoding = renderStatus.CurrentCharacterSet != CharacterSet.DEFAULT_CHARSET;
424+
renderStatus.IsIncludeOtherEncoding |=
425+
isIncludeOtherEncoding;
421426

422-
// Dx (variable): An optional array of 16-bit signed integers that indicate the distance between origins of adjacent character cells. For example, Dx[i] logical units separate the origins of character cell i and character cell i + 1. If this field is present, there MUST be the same number of values as there are characters in the string.
423-
//Debug.Assert(st == unknownRecord.RecordSize);
424-
var dxLength = unknownRecord.Data.Length - st;
427+
// Dx (variable): An optional array of 16-bit signed integers that indicate the distance between origins of adjacent character cells. For example, Dx[i] logical units separate the origins of character cell i and character cell i + 1. If this field is present, there MUST be the same number of values as there are characters in the string.
428+
//Debug.Assert(st == unknownRecord.RecordSize);
429+
var dxLength = unknownRecord.Data.Length - st;
425430

426-
renderStatus.UpdateSkiaTextStatus();
431+
renderStatus.UpdateSkiaTextStatus();
427432

428-
var currentXOffset = renderStatus.CurrentX + tx + renderStatus.LastDxOffset;
433+
var currentXOffset = renderStatus.CurrentX + tx + renderStatus.LastDxOffset;
429434

430-
if (dxLength == 0)
435+
var isIncludeTextWithDx = renderStatus.LastDxOffset > 0;
436+
renderStatus.IsIncludeTextWithDx |=
437+
isIncludeTextWithDx;
438+
439+
if (dxLength == 0)
440+
{
441+
canvas.DrawText(text, currentXOffset, renderStatus.CurrentY + ty, renderStatus.SKFont,
442+
renderStatus.Paint);
443+
}
444+
else
445+
{
446+
// 如果这里计算出来不是偶数,则首个需要跳过。这是经过测试验证的。~~但没有相关说明内容。且跳过的 byte 是有内容的~~ String (variable): If the length is odd, an extra byte is placed after it so that the following member (optional Dx) is aligned on a 16-bit boundary.
447+
// 如果字符串的长度是奇数,则在字符串后面放置一个额外的字节,以便下一个成员(可选的 Dx)对齐到 16 位边界。
448+
if (dxLength > ((dxLength / sizeof(UInt16)) * sizeof(UInt16)))
431449
{
432-
canvas.DrawText(text, currentXOffset, renderStatus.CurrentY + ty, renderStatus.SKFont,
433-
renderStatus.Paint);
450+
// 读取掉这个额外的字节,以便 Dx 对齐到 16 位边界
451+
var r = binaryReader.ReadByte();
452+
_ = r;
453+
}
454+
455+
UInt16[] dxArray = new UInt16[dxLength / sizeof(UInt16)];
456+
for (var t = 0; t < dxArray.Length; t++)
457+
{
458+
dxArray[t] = binaryReader.ReadUInt16();
434459
}
435-
else
460+
461+
if (dxArray.Length != text.Length)
436462
{
437-
// 如果这里计算出来不是偶数,则首个需要跳过。这是经过测试验证的。~~但没有相关说明内容。且跳过的 byte 是有内容的~~ String (variable): If the length is odd, an extra byte is placed after it so that the following member (optional Dx) is aligned on a 16-bit boundary.
438-
// 如果字符串的长度是奇数,则在字符串后面放置一个额外的字节,以便下一个成员(可选的 Dx)对齐到 16 位边界。
439-
if (dxLength > ((dxLength / sizeof(UInt16)) * sizeof(UInt16)))
440-
{
441-
// 读取掉这个额外的字节,以便 Dx 对齐到 16 位边界
442-
var r = binaryReader.ReadByte();
443-
_ = r;
444-
}
445-
446-
UInt16[] dxArray = new UInt16[dxLength / sizeof(UInt16)];
447-
for (var t = 0; t < dxArray.Length; t++)
448-
{
449-
dxArray[t] = binaryReader.ReadUInt16();
450-
}
451-
452-
if (dxArray.Length != text.Length)
453-
{
454-
return false;
455-
}
456-
457-
for (var textIndex = 0; textIndex < text.Length; textIndex++)
458-
{
459-
canvas.DrawText(text[textIndex].ToString(), currentXOffset,
460-
renderStatus.CurrentY + ty, renderStatus.SKFont,
461-
renderStatus.Paint);
462-
463-
currentXOffset += dxArray[textIndex];
464-
}
465-
466-
renderStatus.LastDxOffset = dxArray[^1];
463+
return false;
467464
}
468465

469-
break;
466+
for (var textIndex = 0; textIndex < text.Length; textIndex++)
467+
{
468+
canvas.DrawText(text[textIndex].ToString(), currentXOffset,
469+
renderStatus.CurrentY + ty, renderStatus.SKFont,
470+
renderStatus.Paint);
471+
472+
currentXOffset += dxArray[textIndex];
473+
}
474+
475+
renderStatus.LastDxOffset = dxArray[^1];
470476
}
477+
478+
break;
479+
}
471480
}
472481
}
473482

474-
return true;
483+
// 如果包含有文本,且此时有其他编码或带 DX 就表示可以转换,效果不会比 libwmf 更差
484+
if (renderStatus.IsIncludeText && (renderStatus.IsIncludeOtherEncoding ||renderStatus.IsIncludeTextWithDx))
485+
{
486+
return true;
487+
}
488+
489+
return false;
475490
}
476491
}

0 commit comments

Comments
 (0)