fixed #1261: Properly convert DIB to image

This commit is contained in:
Jaex 2016-01-18 23:52:47 +02:00
parent 341784cc93
commit db93b5a6dc
4 changed files with 198 additions and 40 deletions

View file

@ -37,6 +37,8 @@ namespace ShareX.HelpersLib
public static class ClipboardHelpers
{
private const int RetryTimes = 20, RetryDelay = 100;
private const string FORMAT_PNG = "PNG";
private const string FORMAT_17 = "Format17";
private static readonly object ClipboardLock = new object();
@ -267,46 +269,44 @@ private static Image GetImageAlternative()
{
string[] dataFormats = dataObject.GetFormats(false);
if (dataFormats.Contains("PNG"))
if (dataFormats.Contains(FORMAT_PNG))
{
using (MemoryStream ms = (MemoryStream)dataObject.GetData("PNG"))
using (MemoryStream ms = dataObject.GetData(FORMAT_PNG) as MemoryStream)
{
return (Image)Image.FromStream(ms).Clone();
if (ms != null)
{
using (Image img = Image.FromStream(ms))
{
return (Image)img.Clone();
}
}
if (dataFormats.Contains(DataFormats.Dib))
{
byte[] dib;
using (MemoryStream ms = (MemoryStream)dataObject.GetData(DataFormats.Dib))
{
dib = ms.ToArray();
}
short bpp = BitConverter.ToInt16(dib, 14);
if (bpp == 32)
}
else
{
foreach (string format in new[] { DataFormats.Dib, FORMAT_17 })
{
if (dataFormats.Contains(format))
{
using (MemoryStream ms = dataObject.GetData(format) as MemoryStream)
{
if (ms != null)
{
GCHandle gch = GCHandle.Alloc(dib, GCHandleType.Pinned);
try
{
int width = BitConverter.ToInt32(dib, 4);
int height = BitConverter.ToInt32(dib, 8);
int stride = width * 4;
IntPtr ptr = new IntPtr((long)gch.AddrOfPinnedObject() + 40);
Image img = GetDIBImage(ms);
using (Bitmap bmp = new Bitmap(width, height, stride, PixelFormat.Format32bppArgb, ptr))
if (img != null)
{
Image img = (Image)bmp.Clone();
img.RotateFlip(RotateFlipType.Rotate180FlipX);
return img;
}
}
finally
catch (Exception e)
{
gch.Free();
DebugHelper.WriteException(e);
}
}
}
}
}
}
@ -319,5 +319,36 @@ private static Image GetImageAlternative()
return null;
}
private static Image GetDIBImage(MemoryStream ms)
{
byte[] dib = ms.ToArray();
BITMAPINFOHEADER infoHeader = Helpers.ByteArrayToStructure<BITMAPINFOHEADER>(dib);
IntPtr gcHandle = IntPtr.Zero;
try
{
GCHandle handle = GCHandle.Alloc(dib, GCHandleType.Pinned);
gcHandle = GCHandle.ToIntPtr(handle);
if (infoHeader.biSizeImage == 0)
{
infoHeader.biSizeImage = (uint)(infoHeader.biWidth * infoHeader.biHeight * (infoHeader.biBitCount >> 3));
}
return new Bitmap(infoHeader.biWidth, infoHeader.biHeight, -(int)(infoHeader.biSizeImage / infoHeader.biHeight),
infoHeader.biBitCount == 32 ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb,
new IntPtr((long)handle.AddrOfPinnedObject() + infoHeader.OffsetToPixels + (infoHeader.biHeight - 1) * (int)(infoHeader.biSizeImage / infoHeader.biHeight)));
}
finally
{
if (gcHandle != IntPtr.Zero)
{
GCHandle.FromIntPtr(gcHandle).Free();
}
}
}
}
}

View file

@ -38,6 +38,7 @@ You should have received a copy of the GNU General Public License
using System.Net.NetworkInformation;
using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Principal;
@ -999,5 +1000,19 @@ public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
CopyAll(diSourceSubDir, nextTargetSubDir);
}
}
public static T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
}
finally
{
handle.Free();
}
}
}
}

View file

@ -2833,4 +2833,14 @@ public enum ScrollInfoMask : uint
SIF_TRACKPOS = 0x10,
SIF_ALL = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS
}
public enum BI_COMPRESSION : int
{
BI_RGB = 0,
BI_RLE8 = 1,
BI_RLE4 = 2,
BI_BITFIELDS = 3,
BI_JPEG = 4,
BI_PNG = 5
}
}

View file

@ -513,35 +513,137 @@ public struct AVICOMPRESSOPTIONS
public int interleaveEvery;
}
[StructLayout(LayoutKind.Sequential)]
[StructLayout(LayoutKind.Sequential, Pack = 2)]
public struct BITMAPFILEHEADER
{
public static readonly short BM = 0x4d42;
public short bfType;
public int bfSize;
public short bfReserved1;
public short bfReserved2;
public int bfOffBits;
}
[StructLayout(LayoutKind.Explicit)]
public struct BITMAPINFOHEADER
{
[FieldOffset(0)]
public uint biSize;
[FieldOffset(4)]
public int biWidth;
[FieldOffset(8)]
public int biHeight;
[FieldOffset(12)]
public ushort biPlanes;
[FieldOffset(14)]
public ushort biBitCount;
public BitmapCompressionMode biCompression;
[FieldOffset(16)]
public BI_COMPRESSION biCompression;
[FieldOffset(20)]
public uint biSizeImage;
[FieldOffset(24)]
public int biXPelsPerMeter;
[FieldOffset(28)]
public int biYPelsPerMeter;
[FieldOffset(32)]
public uint biClrUsed;
[FieldOffset(36)]
public uint biClrImportant;
[FieldOffset(40)]
public uint bV5RedMask;
[FieldOffset(44)]
public uint bV5GreenMask;
[FieldOffset(48)]
public uint bV5BlueMask;
[FieldOffset(52)]
public uint bV5AlphaMask;
[FieldOffset(56)]
public uint bV5CSType;
[FieldOffset(60)]
public CIEXYZTRIPLE bV5Endpoints;
[FieldOffset(96)]
public uint bV5GammaRed;
[FieldOffset(100)]
public uint bV5GammaGreen;
[FieldOffset(104)]
public uint bV5GammaBlue;
[FieldOffset(108)]
public uint bV5Intent;
[FieldOffset(112)]
public uint bV5ProfileData;
[FieldOffset(116)]
public uint bV5ProfileSize;
[FieldOffset(120)]
public uint bV5Reserved;
public BITMAPINFOHEADER(int width, int height, ushort bitCount)
public const int DIB_RGB_COLORS = 0;
public BITMAPINFOHEADER(int width, int height, ushort bpp)
{
biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER));
biPlanes = 1;
biCompression = BI_COMPRESSION.BI_RGB;
biWidth = width;
biHeight = height;
biPlanes = 1;
biBitCount = bitCount;
biCompression = BitmapCompressionMode.BI_RGB;
biSizeImage = 0;
biBitCount = bpp;
biSizeImage = (uint)(width * height * (bpp >> 3));
biXPelsPerMeter = 0;
biYPelsPerMeter = 0;
biClrUsed = 0;
biClrImportant = 0;
bV5RedMask = (uint)255 << 16;
bV5GreenMask = (uint)255 << 8;
bV5BlueMask = (uint)255;
bV5AlphaMask = (uint)255 << 24;
bV5CSType = 1934772034;
bV5Endpoints = new CIEXYZTRIPLE();
bV5Endpoints.ciexyzBlue = new CIEXYZ(0);
bV5Endpoints.ciexyzGreen = new CIEXYZ(0);
bV5Endpoints.ciexyzRed = new CIEXYZ(0);
bV5GammaRed = 0;
bV5GammaGreen = 0;
bV5GammaBlue = 0;
bV5Intent = 4;
bV5ProfileData = 0;
bV5ProfileSize = 0;
bV5Reserved = 0;
}
public uint OffsetToPixels
{
get
{
if (biCompression == BI_COMPRESSION.BI_BITFIELDS)
{
return biSize + 3 * 4;
}
return biSize;
}
}
}
[StructLayout(LayoutKind.Sequential)]
public struct CIEXYZ
{
public uint ciexyzX;
public uint ciexyzY;
public uint ciexyzZ;
public CIEXYZ(uint FXPT2DOT30)
{
ciexyzX = FXPT2DOT30;
ciexyzY = FXPT2DOT30;
ciexyzZ = FXPT2DOT30;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct CIEXYZTRIPLE
{
public CIEXYZ ciexyzRed;
public CIEXYZ ciexyzGreen;
public CIEXYZ ciexyzBlue;
}
public struct INPUT