Skip to content

Commit

Permalink
Merge pull request #5 from viordash/ClipboardImages
Browse files Browse the repository at this point in the history
Clipboard images
  • Loading branch information
viordash authored Jul 30, 2023
2 parents 6f6157b + 283dfb6 commit df921ca
Show file tree
Hide file tree
Showing 11 changed files with 1,209 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,8 @@ public void SetFileDropList_Test() {
Assert.That(outFormat, Is.EqualTo(ClipboardFile.Format.XKdeFileNames)
.Or.EqualTo(ClipboardFile.Format.XMateFileNames)
.Or.EqualTo(ClipboardFile.Format.XGnomeFileNames));
Assert.That(outObject, Is.InstanceOf<byte[]>());

var urls = System.Text.Encoding.UTF8.GetString((byte[])outObject!);
Assert.That(outObject, Is.InstanceOf<string>());
var urls = (string)outObject;
Assert.That(urls, Does.Contain("Clipbrd.Core").And.Contain("code%201%20amd64.deb"));
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.Linq;
using ShareClipbrd.Core.Clipboard;
using ShareClipbrd.Core.Helpers;

namespace ShareClipbrd.Core.Tests.Clipboard {
public class ImageConverterTests {

[Test]
public void FromDibToBmpFileData_Test() {
var streamDib = new MemoryStream(TestData.Dib_32x32);
var data = ImageConverter.FromDibToBmpFileData(streamDib);
Assert.That(data, Has.Length.GreaterThan(StructHelper.Size<BitmapFile.BITMAPFILEHEADER>()));
var bmpHeader = StructHelper.FromBytes<BitmapFile.BITMAPFILEHEADER>(data);
Assert.That(bmpHeader.bfType, Is.EqualTo(0x4D42));
Assert.That(data, Has.Length.EqualTo(bmpHeader.bfSize));
}

[Test]
public void FromDibToBmpFileData_45x45_32bit_Test() {
var streamDib = new MemoryStream(TestData.Dib_45x45_32bit);
var data = ImageConverter.FromDibToBmpFileData(streamDib);
Assert.That(data, Has.Length.GreaterThan(StructHelper.Size<BitmapFile.BITMAPFILEHEADER>()));
var bmpHeader = StructHelper.FromBytes<BitmapFile.BITMAPFILEHEADER>(data);
Assert.That(bmpHeader.bfType, Is.EqualTo(0x4D42));
Assert.That(data, Has.Length.EqualTo(bmpHeader.bfSize));
}

[Test]
public void FromDibToBmpFileData_For_Incorrect_Data_Length_Throws_ArgumentException() {
var streamDib = new MemoryStream(TestData.Dib_32x32.Skip(1).ToArray());
var ex = Assert.Throws<ArgumentException>(() => ImageConverter.FromDibToBmpFileData(streamDib));
Assert.That(ex.Message, Is.EqualTo("Deserialize BITMAPINFO. data invalid"));
}

[Test]
public void FromDibToBmpFileData_For_Incorrect_Header_Throws_ArgumentException() {
var data = TestData.Dib_32x32.ToArray();
data[0]--;
var streamDib = new MemoryStream(data);
var ex = Assert.Throws<ArgumentException>(() => ImageConverter.FromDibToBmpFileData(streamDib));
Assert.That(ex.Message, Is.EqualTo("Deserialize BITMAPINFO. data invalid"));
}

[Test]
public void FromBmpFileToDibData_Test() {
var streamDib = new MemoryStream(TestData.Dib_32x32);
var bytesBmp = ImageConverter.FromDibToBmpFileData(streamDib);
var streamBmp = new MemoryStream(bytesBmp);
var bytesDibConverted = ImageConverter.FromBmpFileToDibData(streamBmp);
Assert.That(bytesDibConverted, Has.Length.EqualTo(3112));
Assert.That(bytesDibConverted, Is.EquivalentTo(TestData.Dib_32x32.Take(bytesDibConverted.Length)));
}
}
}
774 changes: 774 additions & 0 deletions ShareClipbrd/ShareClipbrd.Core.Tests/Clipboard/TestData.cs

Large diffs are not rendered by default.

129 changes: 129 additions & 0 deletions ShareClipbrd/ShareClipbrd.Core/Clipboard/BITMAPINFO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using System.Runtime.InteropServices;
using ShareClipbrd.Core.Helpers;

namespace ShareClipbrd.Core.Clipboard {
public enum BitmapCompressionMode : uint {
BI_RGB = 0,
BI_RLE8 = 1,
BI_RLE4 = 2,
BI_BITFIELDS = 3,
BI_JPEG = 4,
BI_PNG = 5
}

[StructLayout(LayoutKind.Sequential)]
public struct CIEXYZ {
public long ciexyzX;
public long ciexyzY;
public long ciexyzZ;
}

[StructLayout(LayoutKind.Sequential)]
public struct CIEXYZTRIPLE {
public CIEXYZ ciexyzRed;
public CIEXYZ ciexyzGreen;
public CIEXYZ ciexyzBlue;
}

[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFOHEADER {
public uint biSize;
public int biWidth;
public int biHeight;
public ushort biPlanes;
public ushort biBitCount;
public BitmapCompressionMode biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public uint biClrUsed;
public uint biClrImportant;

public BITMAPINFOHEADER() {
biSize = StructHelper.Size(this);
}
}

[StructLayout(LayoutKind.Sequential)]
public struct BITMAPV5HEADER {
public uint bV5Size;
public int bV5Width;
public int bV5Height;
public ushort bV5Planes;
public ushort bV5BitCount;
public BitmapCompressionMode bV5Compression;
public uint bV5SizeImage;
public int bV5XPelsPerMeter;
public int bV5YPelsPerMeter;
public uint bV5ClrUsed;
public uint bV5ClrImportant;

public uint bV5RedMask;
public uint bV5GreenMask;
public uint bV5BlueMask;
public uint bV5AlphaMask;
public uint bV5CSType;
public CIEXYZTRIPLE bV5Endpoints;
public uint bV5GammaRed;
public uint bV5GammaGreen;
public uint bV5GammaBlue;
public uint bV5Intent;
public uint bV5ProfileData;
public uint bV5ProfileSize;
public uint bV5Reserved;

public BITMAPV5HEADER() {
bV5Size = StructHelper.Size(this);
}
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RGBQUAD {
public byte rgbBlue;
public byte rgbGreen;
public byte rgbRed;
public byte rgbReserved;
}

[StructLayoutAttribute(LayoutKind.Sequential)]
public struct BITMAPINFO {
public BITMAPINFOHEADER bmiHeader;

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = UnmanagedType.Struct)]
public RGBQUAD[] bmiColors;

public static bool TryParse(byte[] bytes, out BITMAPINFO bitmapinfo) {
if(bytes.Length < StructHelper.Size<BITMAPINFOHEADER>()) {
bitmapinfo = new BITMAPINFO();
return false;
}

bitmapinfo = StructHelper.FromBytes<BITMAPINFO>(bytes);
if(bitmapinfo.bmiHeader.biSize != StructHelper.Size<BITMAPINFOHEADER>()) {
return false;
}
return true;
}
}

[StructLayoutAttribute(LayoutKind.Sequential)]
public struct BITMAPV5INFO {
public BITMAPV5HEADER bmiHeader;

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = UnmanagedType.Struct)]
public RGBQUAD[] bmiColors;

public static bool TryParse(byte[] bytes, out BITMAPV5INFO bitmapinfo) {
if(bytes.Length < StructHelper.Size<BITMAPV5HEADER>()) {
bitmapinfo = new BITMAPV5INFO();
return false;
}

bitmapinfo = StructHelper.FromBytes<BITMAPV5INFO>(bytes);
if(bitmapinfo.bmiHeader.bV5Size != StructHelper.Size<BITMAPV5HEADER>()) {
return false;
}
return true;
}
}
}
50 changes: 50 additions & 0 deletions ShareClipbrd/ShareClipbrd.Core/Clipboard/BitmapFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Runtime.InteropServices;
using ShareClipbrd.Core.Helpers;

namespace ShareClipbrd.Core.Clipboard {
public class BitmapFile {
[StructLayout(LayoutKind.Sequential, Pack = 2)]
public struct BITMAPFILEHEADER {
public ushort bfType;
public uint bfSize;
public ushort bfReserved1;
public ushort bfReserved2;
public uint bfOffBits;

public BITMAPFILEHEADER() {
bfSize = StructHelper.Size(this);
}
}

public static byte[] Create(byte[] bytes, BITMAPINFO bitmapinfo) {
var bitmapFileHeader = new BITMAPFILEHEADER();

using var memorystream = new MemoryStream();
var sizeImage = bitmapinfo.bmiHeader.biSizeImage > 0
? bitmapinfo.bmiHeader.biSizeImage
: (uint)(bitmapinfo.bmiHeader.biBitCount / 8) * (uint)bitmapinfo.bmiHeader.biWidth * (uint)bitmapinfo.bmiHeader.biHeight;
var sizeDib = bitmapinfo.bmiHeader.biSize + bitmapinfo.bmiHeader.biClrUsed * StructHelper.Size<RGBQUAD>()
+ sizeImage;

bitmapFileHeader.bfType = 0x4D42;
bitmapFileHeader.bfSize = StructHelper.Size<BITMAPFILEHEADER>() + sizeDib;
bitmapFileHeader.bfReserved1 = 0;
bitmapFileHeader.bfReserved2 = 0;
bitmapFileHeader.bfOffBits = StructHelper.Size<BITMAPFILEHEADER>() + bitmapinfo.bmiHeader.biSize
+ bitmapinfo.bmiHeader.biClrUsed * StructHelper.Size<RGBQUAD>();

memorystream.Write(StructHelper.ToBytes(bitmapFileHeader));

memorystream.Write(bytes, 0, (int)sizeDib);
return memorystream.ToArray();
}

public static byte[] ExtractDib(byte[] bytesBmp) {
return bytesBmp.Skip((int)StructHelper.Size<BITMAPFILEHEADER>()).ToArray();
}

public static byte[] Create(byte[] bytes, BITMAPV5INFO bitmapinfo) {
throw new NotImplementedException();
}
}
}
Loading

0 comments on commit df921ca

Please sign in to comment.