Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start parsing EmfPlusPen, EmfPlusBrush, and EmfPlusDrawlines #4

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions src/AutoGenerated/AutoGeneratedConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ public static class Integers
/// <summary>
/// Current month 1..12
/// </summary>
public const int CurrentMonth = 10;
public const int CurrentMonth = 12;

/// <summary>
/// Current day of the month 1..31
/// </summary>
public const int CurrentDayOfMonth = 30;
public const int CurrentDayOfMonth = 23;

/// <summary>
/// Current hour from 0..23
/// </summary>
public const int CurrentHour = 16;
public const int CurrentHour = 20;

/// <summary>
/// Current hour from 0..59
/// </summary>
public const int CurrentMinute = 7;
public const int CurrentMinute = 22;
}

public static class Strings
Expand All @@ -48,42 +48,42 @@ public static class Strings
/// <summary>
/// Current month 1..12
/// </summary>
public const string CurrentMonth = "10";
public const string CurrentMonth = "12";

/// <summary>
/// Current month 01..12
/// </summary>
public const string CurrentTwoDigitMonth = "10";
public const string CurrentTwoDigitMonth = "12";

/// <summary>
/// Current day of the month 1..31
/// </summary>
public const string CurrentDayOfMonth = "30";
public const string CurrentDayOfMonth = "23";

/// <summary>
/// Current two digit day of the month 01..31
/// </summary>
public const string CurrentTwoDigitDayOfMonth = "30";
public const string CurrentTwoDigitDayOfMonth = "23";

/// <summary>
/// Current hour from 0..23
/// </summary>
public const string CurrentHour = "16";
public const string CurrentHour = "20";

/// <summary>
/// Current two digit hour from 00..23
/// </summary>
public const string CurrentTwoDigitHour = "16";
public const string CurrentTwoDigitHour = "20";

/// <summary>
/// Current hour from 0..59
/// </summary>
public const string CurrentMinute = "7";
public const string CurrentMinute = "22";

/// <summary>
/// Current two digit hour from 00..59
/// </summary>
public const string CurrentTwoDigitMinute = "07";
public const string CurrentTwoDigitMinute = "22";
}
}
}
45 changes: 42 additions & 3 deletions src/Tests/WInterop.Tests/GdiPlus/Metafiles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,10 @@ public unsafe void ParseGdiCommentRecords()
using (MetafilePlus record = new(stream, deviceContext, EmfType.EmfPlusDual))
{
using Graphics graphics = new(record);
using Pen pen = new(Color.Purple);
graphics.DrawLine(pen, new(1, 1), new(3, 5));
using Pen pen = new(Color.Purple, 10, GpUnit.UnitInch);
pen.SetStartCap(GpLineCapType.LineCapArrowAnchor);
pen.SetEndCap(GpLineCapType.LineCapRoundAnchor);
graphics.DrawLine(pen, new(20, 175), new(300, 175));
}

fixed (byte* b = stream.GetBuffer())
Expand All @@ -329,13 +331,50 @@ public unsafe void ParseGdiCommentRecords()
emr = emr->GetNextRecord();
emr->iType.Should().Be(MetafileRecordType.GdiComment);

emr->dParam[0].Should().Be(76);
emr->dParam[0].Should().Be(84);

record = MetafilePlusRecord.GetFromMetafileComment((EMRGDICOMMENT*)emr);
record->Type.Should().Be(RecordType.EmfPlusObject);

MetafilePlusObject* @object = (MetafilePlusObject*)record;
@object->ObjectType.Should().Be(MetafilePlusObjectType.Pen);

// TODO: Complete MetafilePlusPen
MetafilePlusPen* pen = (MetafilePlusPen*)@object->ObjectData;
pen->Version->MetafileSignature.ToString("X").Should().Be("DBC01");
pen->Version->GraphicsVersion.Should().Be(GraphicsVersionEnum.GraphicsVersion1_1);
pen->Type.Should().Be(0);
pen->PenData->PenUnit.Should().Be(UnitType.UnitTypeInch);
pen->PenData->PenWidth.Should().Be(10);
(pen->PenData->PenDataFlags & PenDataFlags.PenDataStartCap).Should().NotBe(0);
(pen->PenData->PenDataFlags & PenDataFlags.PenDataEndCap).Should().NotBe(0);
pen->PenData->OptionalData->StartCap.Should().Be(LineCapType.LineCapTypeArrowAnchor);
pen->PenData->OptionalData->EndCap.Should().Be(LineCapType.LineCapTypeRoundAnchor);
pen->BrushObject->Version->MetafileSignature.ToString("X").Should().Be("DBC01");
pen->BrushObject->Version->GraphicsVersion.Should().Be(GraphicsVersionEnum.GraphicsVersion1_1);
pen->BrushObject->Type.Should().Be(BrushType.BrushTypeSolidColor);
pen->BrushObject->BrushData->SolidColor.Alpha.Should().Be(Color.Purple.A);
pen->BrushObject->BrushData->SolidColor.Red.Should().Be(Color.Purple.R);
pen->BrushObject->BrushData->SolidColor.Green.Should().Be(Color.Purple.G);
pen->BrushObject->BrushData->SolidColor.Blue.Should().Be(Color.Purple.B);

// Get the next EMF+ record
record = MetafilePlusRecord.GetNextMetafilePlusRecord(record);
record->Type.Should().Be(RecordType.EmfPlusDrawLines);

// TODO: Complete MetafileDrawLines
MetafilePlusDrawLines* @drawLines = (MetafilePlusDrawLines*)record;
@drawLines->CompressedData.Should().Be(true);
@drawLines->ExtraLine.Should().Be(false);
@drawLines->RelativeLocation.Should().Be(false);
@drawLines->ObjectId.Should().Be(0);
@drawLines->Count.Should().Be(2); // Number of points
MetafilePlusPoint point1 = @drawLines->GetPoint(0);
MetafilePlusPoint point2 = @drawLines->GetPoint(1);
point1.X.Should().Be(20);
point1.Y.Should().Be(175);
point2.X.Should().Be(300);
point2.Y.Should().Be(175);
}
}
}
Expand Down
82 changes: 82 additions & 0 deletions src/WInterop.GdiPlus/EmfPlus/MetafilePlusBrush.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Runtime.InteropServices;

namespace WInterop.GdiPlus.EmfPlus
{
[StructLayout(LayoutKind.Sequential)]
public readonly ref struct MetafilePlusBrush
{
private readonly byte _data;

public unsafe readonly MetafilePlusGraphicsVersion* Version
{
get
{
fixed (byte* b = &_data)
{
return (MetafilePlusGraphicsVersion*)b;
}
}
}

public unsafe readonly BrushType Type
{
get
{
fixed (byte* b = &_data)
{
return *(BrushType*)(b + 4);
}
}
}

public unsafe readonly MetafilePlusSolidBrushData* BrushData
{
get
{
fixed (byte* b = &_data)
{
return (MetafilePlusSolidBrushData*)(b + 8);
}
}
}

// TODO: Implement BrushData
}

[StructLayout(LayoutKind.Sequential)]
public readonly ref struct MetafilePlusSolidBrushData
{
private readonly byte _data;

public unsafe readonly MetafilePlusARGB SolidColor
{
get
{
fixed (byte* b = &_data)
{
return *(MetafilePlusARGB*)(b);
}
}
}
}

public enum BrushType : uint
{
BrushTypeSolidColor = 0x00000000,
BrushTypeHatchFill = 0x00000001,
BrushTypeTextureFill = 0x00000002,
BrushTypePathGradient = 0x00000003,
BrushTypeLinearGradient = 0x00000004
}

[StructLayout(LayoutKind.Sequential)]
public readonly ref struct MetafilePlusARGB
{
public readonly byte Blue;
public readonly byte Green;
public readonly byte Red;
public readonly byte Alpha;
}
}
119 changes: 119 additions & 0 deletions src/WInterop.GdiPlus/EmfPlus/MetafilePlusDrawLines.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
using System;
using System.Runtime.InteropServices;

namespace WInterop.GdiPlus.EmfPlus
{
[StructLayout(LayoutKind.Sequential)]
public readonly ref struct MetafilePlusDrawLines
{
public const ushort CompressedDataFlag = 0b0100_0000_0000_0000;
public const ushort ExtraLineFlag = 0b0010_0000_0000_0000;
public const ushort RelativeLocationFlag = 0b0001_0000_0000_0000;
public const ushort ObjectIdMask = 0b0000_0000_1111_1111;

public readonly MetafilePlusRecord Record;

private readonly byte _data;

public unsafe uint Count
{
get
{
fixed (byte* b = &_data)
{
return *(uint*)b;
}
}
}

public uint Size
{
get
{
if (RelativeLocation)
{
return (Count * 0x00000002) + 0x00000010;
}
else if (CompressedData)
{
return (Count * 0x00000004) + 0x00000010;
}
else
{
return (Count * 0x00000008) + 0x00000010;
}
}
}


public uint DataSize
{
get
{
if (RelativeLocation)
{
return (Count * 0x00000002) + 0x00000004;
}
else if (CompressedData)
{
return (Count * 0x00000004) + 0x00000004;
}
else
{
return (Count * 0x00000008) + 0x00000004;
}
}
}

public unsafe byte[] PointData
{
get
{
byte[] pointData = new byte[DataSize - 4];
fixed (byte* ptr = &_data)
{
for (int i = 0; 4 + i < DataSize; i++)
{
pointData[i] = ptr[4 + i];
}
}

return pointData;
}
}

public bool CompressedData => (Record.Flags & CompressedDataFlag) != 0;
public bool ExtraLine => (Record.Flags & ExtraLineFlag) != 0;
public bool RelativeLocation => (Record.Flags & RelativeLocationFlag) != 0;
public int ObjectId => Record.Flags & ObjectIdMask;

public MetafilePlusPoint GetPoint(int index)
{
int offset = index * 4;
MetafilePlusPoint point = new ();
point.X = BitConverter.ToUInt16(PointData, offset);
point.Y = BitConverter.ToUInt16(PointData, offset + 2);
return point;
}
}

[StructLayout(LayoutKind.Sequential)]
public struct MetafilePlusPointR
{

}

[StructLayout(LayoutKind.Sequential)]
public struct MetafilePlusPoint
{
public ushort X;
public ushort Y;
}

[StructLayout(LayoutKind.Sequential)]
public struct MetafilePlusPointF
{
public uint X;
public uint Y;
}
}
35 changes: 35 additions & 0 deletions src/WInterop.GdiPlus/EmfPlus/MetafilePlusGraphicsVersion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Runtime.InteropServices;

namespace WInterop.GdiPlus.EmfPlus
{
[StructLayout(LayoutKind.Sequential)]
public readonly ref struct MetafilePlusGraphicsVersion
{
public const uint MetafileSignatureMask = 0b1111_1111_1111_1111_1111_0000_0000_0000;
public const uint GraphicsVersionMask = 0b0000_0000_0000_0000_0000_1111_1111_1111;

private readonly byte _data;

public unsafe readonly uint MetafileSignature
{
get
{
fixed (byte* b = &_data)
{
return (*(uint*)(b) & MetafileSignatureMask) >> 12;
}
}
}

public readonly GraphicsVersionEnum GraphicsVersion => (GraphicsVersionEnum)(_data & GraphicsVersionMask);
}

public enum GraphicsVersionEnum : uint
{
GraphicsVersion1 = 0x0001,
GraphicsVersion1_1 = 0x0002
}
}
Loading