mirror of
https://github.com/greenshot/greenshot
synced 2025-08-14 10:47:02 -07:00
Added support of another clipboard format "CF_DIBV5" (aka Format17) to Greenshot, this will improve the result for "Open image from clipboard" and the drag&drop actions. Without Format17 these actions still work, but sometimes the transparency is lost as the other formats on the clipboard don't have this information. Greenshot can also write the new format, when enabled in the expert settings. Currently I haven't seen a reason to enable it yet, but due to the complexity of the clipboard and the amount of possible applications maybe an application does work better...
This commit is contained in:
parent
6ddb16e0b1
commit
1ff27810db
5 changed files with 302 additions and 162 deletions
|
@ -12,6 +12,7 @@ Features:
|
|||
* Added the possibility to select the region to capture by using the keyboard, use the cursor keys to move the cursor (ctrl-key speeds up the movement) and the enter key to mark the start and ending.
|
||||
* FEATURE-757: Greenshot will now store the last used region in the greenshot.ini, which makes it also available after a restart.
|
||||
* FEATURE-758: Due to the fact that more and more high DPI displays are used, we added a setting to change the icon size.
|
||||
* Added support for another clipboard format "Format17" (aka CF_DIBV5) which should improve the result of the "open image from clipboard" and drag&drop actions.
|
||||
|
||||
Changes:
|
||||
* JIRA: With JIRA 6.x using the SOAP (Webservice) API the access has gotten really slow, we improved the performance slightly by loading some information parallel. (In Greenshot 2.x we will move to another API.)
|
||||
|
|
|
@ -49,7 +49,8 @@ namespace GreenshotPlugin.Core {
|
|||
private static readonly string FORMAT_JFIF = "JFIF";
|
||||
private static readonly string FORMAT_JFIF_OFFICEART = "JFIF+Office Art";
|
||||
private static readonly string FORMAT_GIF = "GIF";
|
||||
private static readonly string FORMAT_BITMAP_PLACEHOLDER = "_BITMAP_";
|
||||
private static readonly string FORMAT_BITMAP = "System.Drawing.Bitmap";
|
||||
//private static readonly string FORMAT_HTML = "HTML Format";
|
||||
|
||||
private static IntPtr nextClipboardViewer = IntPtr.Zero;
|
||||
// Template for the HTML Text on the clipboard
|
||||
|
@ -230,6 +231,7 @@ EndSelection:<<<<<<<4
|
|||
|| dataObject.GetDataPresent(DataFormats.Tiff)
|
||||
|| dataObject.GetDataPresent(DataFormats.EnhancedMetafile)
|
||||
|| dataObject.GetDataPresent(FORMAT_PNG)
|
||||
|| dataObject.GetDataPresent(FORMAT_17)
|
||||
|| dataObject.GetDataPresent(FORMAT_JPG)
|
||||
|| dataObject.GetDataPresent(FORMAT_GIF)) {
|
||||
return true;
|
||||
|
@ -324,30 +326,14 @@ EndSelection:<<<<<<<4
|
|||
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) {
|
||||
// Outlook ??
|
||||
LOG.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front...");
|
||||
retrieveFormats = new string[] { DataFormats.Dib, FORMAT_BITMAP_PLACEHOLDER, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JFIF, DataFormats.Tiff, FORMAT_GIF };
|
||||
retrieveFormats = new string[] { DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JFIF, DataFormats.Tiff, FORMAT_GIF };
|
||||
} else {
|
||||
retrieveFormats = new string[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JFIF, DataFormats.Tiff, "System.Drawing.Bitmap", DataFormats.Dib, FORMAT_BITMAP_PLACEHOLDER, FORMAT_FILECONTENTS, FORMAT_GIF };
|
||||
retrieveFormats = new string[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_GIF };
|
||||
}
|
||||
foreach (string currentFormat in retrieveFormats) {
|
||||
if (FORMAT_BITMAP_PLACEHOLDER.Equals(currentFormat)) {
|
||||
LOG.Info("Using default .NET Clipboard.GetImage()");
|
||||
try {
|
||||
returnImage = Clipboard.GetImage();
|
||||
if (returnImage == null) {
|
||||
LOG.Info("Clipboard.GetImage() didn't return an image.");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.Error("Problem retrieving Image via Clipboard.GetImage(): ", ex);
|
||||
}
|
||||
} else if (formats.Contains(currentFormat)) {
|
||||
if (formats.Contains(currentFormat)) {
|
||||
LOG.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
|
||||
if (currentFormat == DataFormats.Dib) {
|
||||
returnImage = GetDIBImage(dataObject);
|
||||
} else if (currentFormat == FORMAT_17) {
|
||||
returnImage = CF_DIBV5ToBitmap(dataObject);
|
||||
} else {
|
||||
returnImage = GetImageFormat(currentFormat, dataObject);
|
||||
}
|
||||
returnImage = GetImageForFormat(currentFormat, dataObject);
|
||||
} else {
|
||||
LOG.DebugFormat("Couldn't find format {0}.", currentFormat);
|
||||
}
|
||||
|
@ -359,102 +345,85 @@ EndSelection:<<<<<<<4
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert Format17 (DIBV5) to a bitmap
|
||||
/// Based on: http://stackoverflow.com/a/14335591
|
||||
/// </summary>
|
||||
/// <param name="stream">MemoryStream</param>
|
||||
/// <returns>Bitmap</returns>
|
||||
private static Bitmap CF_DIBV5ToBitmap(IDataObject dataObject) {
|
||||
MemoryStream dibStream = GetFromDataObject(dataObject, DataFormats.Dib) as MemoryStream;
|
||||
if (isValidStream(dibStream)) {
|
||||
IntPtr gcHandle = IntPtr.Zero;
|
||||
try {
|
||||
byte[] data = dibStream.ToArray();
|
||||
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
gcHandle = GCHandle.ToIntPtr(handle);
|
||||
var bmi = (BitmapV5Header)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(BitmapV5Header));
|
||||
return new Bitmap(bmi.bV5Width, bmi.bV5Height, -(int)(bmi.bV5SizeImage / bmi.bV5Height),
|
||||
PixelFormat.Format32bppArgb,
|
||||
new IntPtr(handle.AddrOfPinnedObject().ToInt32() + bmi.bV5Size + (bmi.bV5Height - 1) * (int)(bmi.bV5SizeImage / bmi.bV5Height)));
|
||||
} catch (Exception ex) {
|
||||
LOG.Error("Problem retrieving Format17 from clipboard.", ex);
|
||||
} finally {
|
||||
if (gcHandle == IntPtr.Zero) {
|
||||
GCHandle.FromIntPtr(gcHandle).Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to try to get an image in the specified format from the dataObject
|
||||
/// the DIB readed should solve the issue reported here: https://sourceforge.net/projects/greenshot/forums/forum/676083/topic/6354353/index/page/1
|
||||
/// It also supports Format17/DibV5, by using the following information: http://stackoverflow.com/a/14335591
|
||||
/// </summary>
|
||||
/// <returns>Image</returns>
|
||||
private static Image GetDIBImage(IDataObject dataObject) {
|
||||
try {
|
||||
// If the EnableSpecialDIBClipboardReader flag in the config is set, use the code from:
|
||||
// http://www.thomaslevesque.com/2009/02/05/wpf-paste-an-image-from-the-clipboard/
|
||||
// to read the DeviceIndependentBitmap from the clipboard, this might fix bug 3576125
|
||||
/// <param name="format">string with the format</param>
|
||||
/// <param name="dataObject">IDataObject</param>
|
||||
/// <returns>Image or null</returns>
|
||||
private static Image GetImageForFormat(string format, IDataObject dataObject) {
|
||||
object clipboardObject = GetFromDataObject(dataObject, format);
|
||||
MemoryStream imageStream = clipboardObject as MemoryStream;
|
||||
if (!isValidStream(imageStream)) {
|
||||
// TODO: add "HTML Format" support here...
|
||||
return clipboardObject as Image;
|
||||
} else {
|
||||
if (config.EnableSpecialDIBClipboardReader) {
|
||||
MemoryStream dibStream = GetFromDataObject(dataObject, DataFormats.Dib) as MemoryStream;
|
||||
if (isValidStream(dibStream)) {
|
||||
LOG.Info("Found valid DIB stream, trying to process it.");
|
||||
byte[] dibBuffer = new byte[dibStream.Length];
|
||||
dibStream.Read(dibBuffer, 0, dibBuffer.Length);
|
||||
BitmapInfoHeader infoHeader = BinaryStructHelper.FromByteArray<BitmapInfoHeader>(dibBuffer);
|
||||
LOG.InfoFormat("Using special DIB format reader for biCompression {0}", infoHeader.biCompression);
|
||||
int fileHeaderSize = Marshal.SizeOf(typeof(BitmapFileHeader));
|
||||
uint infoHeaderSize = infoHeader.biSize;
|
||||
int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
|
||||
if (format == FORMAT_17 || format == DataFormats.Dib) {
|
||||
LOG.Info("Found DIB stream, trying to process it.");
|
||||
try {
|
||||
byte[] dibBuffer = new byte[imageStream.Length];
|
||||
imageStream.Read(dibBuffer, 0, dibBuffer.Length);
|
||||
BITMAPINFOHEADER infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADER>(dibBuffer);
|
||||
if (!infoHeader.IsDibV5) {
|
||||
LOG.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
|
||||
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
|
||||
uint infoHeaderSize = infoHeader.biSize;
|
||||
int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
|
||||
|
||||
BitmapFileHeader fileHeader = new BitmapFileHeader();
|
||||
fileHeader.bfType = BitmapFileHeader.BM;
|
||||
fileHeader.bfSize = fileSize;
|
||||
fileHeader.bfReserved1 = 0;
|
||||
fileHeader.bfReserved2 = 0;
|
||||
fileHeader.bfOffBits = (int)(fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4);
|
||||
BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER();
|
||||
fileHeader.bfType = BITMAPFILEHEADER.BM;
|
||||
fileHeader.bfSize = fileSize;
|
||||
fileHeader.bfReserved1 = 0;
|
||||
fileHeader.bfReserved2 = 0;
|
||||
fileHeader.bfOffBits = (int)(fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4);
|
||||
|
||||
byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray<BitmapFileHeader>(fileHeader);
|
||||
byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray<BITMAPFILEHEADER>(fileHeader);
|
||||
|
||||
using (MemoryStream bitmapStream = new MemoryStream()) {
|
||||
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
|
||||
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
|
||||
bitmapStream.Seek(0, SeekOrigin.Begin);
|
||||
using (Image tmpImage = Image.FromStream(bitmapStream)) {
|
||||
if (tmpImage != null) {
|
||||
return ImageHelper.Clone(tmpImage);
|
||||
using (MemoryStream bitmapStream = new MemoryStream()) {
|
||||
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
|
||||
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
|
||||
bitmapStream.Seek(0, SeekOrigin.Begin);
|
||||
using (Image tmpImage = Image.FromStream(bitmapStream)) {
|
||||
if (tmpImage != null) {
|
||||
return ImageHelper.Clone(tmpImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG.Info("Using special DIBV5 / Format17 format reader");
|
||||
// CF_DIBV5
|
||||
IntPtr gcHandle = IntPtr.Zero;
|
||||
try {
|
||||
GCHandle handle = GCHandle.Alloc(dibBuffer, GCHandleType.Pinned);
|
||||
gcHandle = GCHandle.ToIntPtr(handle);
|
||||
return new Bitmap(infoHeader.biWidth, infoHeader.biHeight, -(int)(infoHeader.biSizeImage / infoHeader.biHeight),
|
||||
infoHeader.biBitCount == 32?PixelFormat.Format32bppArgb: PixelFormat.Format24bppRgb,
|
||||
new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels + (infoHeader.biHeight - 1) * (int)(infoHeader.biSizeImage / infoHeader.biHeight)));
|
||||
} catch (Exception ex) {
|
||||
LOG.Error("Problem retrieving Format17 from clipboard.", ex);
|
||||
} finally {
|
||||
if (gcHandle == IntPtr.Zero) {
|
||||
GCHandle.FromIntPtr(gcHandle).Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception dibEx) {
|
||||
LOG.Error("Problem retrieving DIB from clipboard.", dibEx);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG.Info("Skipping special DIB format reader as it's disabled in the configuration.");
|
||||
}
|
||||
} catch (Exception dibEx) {
|
||||
LOG.Error("Problem retrieving DIB from clipboard.", dibEx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to try to get an image in the specified format from the dataObject
|
||||
/// </summary>
|
||||
/// <param name="format">string with the format</param>
|
||||
/// <param name="dataObject">IDataObject</param>
|
||||
/// <returns>Image or null</returns>
|
||||
private static Image GetImageFormat(string format, IDataObject dataObject) {
|
||||
MemoryStream imageStream = GetFromDataObject(dataObject, format) as MemoryStream;
|
||||
if (isValidStream(imageStream)) {
|
||||
try {
|
||||
imageStream.Seek(0, SeekOrigin.Begin);
|
||||
using (Image tmpImage = Image.FromStream(imageStream, true, true)) {
|
||||
if (tmpImage != null) {
|
||||
LOG.InfoFormat("Got image with clipboard format {0} from the clipboard.", format);
|
||||
return ImageHelper.Clone(tmpImage);
|
||||
return ImageHelper.Clone(tmpImage);
|
||||
}
|
||||
}
|
||||
} catch (Exception streamImageEx) {
|
||||
|
@ -539,6 +508,7 @@ EndSelection:<<<<<<<4
|
|||
//ido.SetData(DataFormats.Bitmap, true, image);
|
||||
|
||||
MemoryStream dibStream = null;
|
||||
MemoryStream dibV5Stream = null;
|
||||
MemoryStream pngStream = null;
|
||||
Image imageToSave = null;
|
||||
bool disposeImage = false;
|
||||
|
@ -579,6 +549,43 @@ EndSelection:<<<<<<<4
|
|||
} catch (Exception dibEx) {
|
||||
LOG.Error("Error creating DIB for the Clipboard.", dibEx);
|
||||
}
|
||||
|
||||
// CF_DibV5
|
||||
try {
|
||||
if (config.ClipboardFormats.Contains(ClipboardFormat.DIBV5)) {
|
||||
// Create the stream for the clipboard
|
||||
dibV5Stream = new MemoryStream();
|
||||
|
||||
// Create the BITMAPINFOHEADER
|
||||
BITMAPINFOHEADER header = new BITMAPINFOHEADER(imageToSave.Width, imageToSave.Height, 32);
|
||||
// Make sure we have BI_BITFIELDS, this seems to be normal for Format17?
|
||||
header.biCompression = BI_COMPRESSION.BI_BITFIELDS;
|
||||
// Create a byte[] to write
|
||||
byte[] headerBytes = BinaryStructHelper.ToByteArray<BITMAPINFOHEADER>(header);
|
||||
// Write the BITMAPINFOHEADER to the stream
|
||||
dibV5Stream.Write(headerBytes, 0, headerBytes.Length);
|
||||
|
||||
// As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added
|
||||
BitfieldColorMask colorMask = new BitfieldColorMask();
|
||||
// Make sure the values are set
|
||||
colorMask.InitValues();
|
||||
// Create the byte[] from the struct
|
||||
byte[] colorMaskBytes = BinaryStructHelper.ToByteArray<BitfieldColorMask>(colorMask);
|
||||
Array.Reverse(colorMaskBytes);
|
||||
// Write to the stream
|
||||
dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length);
|
||||
|
||||
// Create the raw bytes for the pixels only
|
||||
byte[] bitmapBytes = BitmapToByteArray((Bitmap)imageToSave);
|
||||
// Write to the stream
|
||||
dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length);
|
||||
|
||||
// Set the DIBv5 to the clipboard DataObject
|
||||
dataObject.SetData(FORMAT_17, true, dibV5Stream);
|
||||
}
|
||||
} catch (Exception dibEx) {
|
||||
LOG.Error("Error creating DIB for the Clipboard.", dibEx);
|
||||
}
|
||||
|
||||
// Set the HTML
|
||||
if (config.ClipboardFormats.Contains(ClipboardFormat.HTML)) {
|
||||
|
@ -623,6 +630,10 @@ EndSelection:<<<<<<<4
|
|||
dibStream.Dispose();
|
||||
dibStream = null;
|
||||
}
|
||||
if (dibV5Stream != null) {
|
||||
dibV5Stream.Dispose();
|
||||
dibV5Stream = null;
|
||||
}
|
||||
// cleanup if needed
|
||||
if (disposeImage && imageToSave != null) {
|
||||
imageToSave.Dispose();
|
||||
|
@ -630,6 +641,34 @@ EndSelection:<<<<<<<4
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method so get the bitmap bytes
|
||||
/// See: http://stackoverflow.com/a/6570155
|
||||
/// </summary>
|
||||
/// <param name="bitmap">Bitmap</param>
|
||||
/// <returns>byte[]</returns>
|
||||
private static byte[] BitmapToByteArray(Bitmap bitmap) {
|
||||
// Lock the bitmap's bits.
|
||||
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
|
||||
BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||
|
||||
int absStride = Math.Abs(bmpData.Stride);
|
||||
int bytes = absStride * bitmap.Height;
|
||||
long ptr = bmpData.Scan0.ToInt32();
|
||||
// Declare an array to hold the bytes of the bitmap.
|
||||
byte[] rgbValues = new byte[bytes];
|
||||
|
||||
for (int i = 0; i < bitmap.Height; i++) {
|
||||
IntPtr pointer = new IntPtr(ptr + (bmpData.Stride * i));
|
||||
Marshal.Copy(pointer, rgbValues, absStride * (bitmap.Height - i - 1), absStride);
|
||||
}
|
||||
|
||||
// Unlock the bits.
|
||||
bitmap.UnlockBits(bmpData);
|
||||
|
||||
return rgbValues;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set Object with type Type to the clipboard
|
||||
/// </summary>
|
||||
|
|
|
@ -29,7 +29,7 @@ using System.Reflection;
|
|||
|
||||
namespace GreenshotPlugin.Core {
|
||||
public enum ClipboardFormat {
|
||||
PNG, DIB, HTML, HTMLDATAURL, BITMAP
|
||||
PNG, DIB, HTML, HTMLDATAURL, BITMAP, DIBV5
|
||||
}
|
||||
public enum OutputFormat {
|
||||
bmp, gif, jpg, png, tiff, greenshot
|
||||
|
|
|
@ -651,15 +651,15 @@ namespace GreenshotPlugin.Core {
|
|||
// throw exception
|
||||
throw exceptionToThrow;
|
||||
}
|
||||
// Create BitmapInfoHeader for CreateDIBSection
|
||||
BitmapInfoHeader bmi = new BitmapInfoHeader(captureBounds.Width, captureBounds.Height, 24);
|
||||
// Create BITMAPINFOHEADER for CreateDIBSection
|
||||
BITMAPINFOHEADER bmi = new BITMAPINFOHEADER(captureBounds.Width, captureBounds.Height, 24);
|
||||
|
||||
// Make sure the last error is set to 0
|
||||
Win32.SetLastError(0);
|
||||
|
||||
// create a bitmap we can copy it to, using GetDeviceCaps to get the width/height
|
||||
IntPtr bits0; // not used for our purposes. It returns a pointer to the raw bits that make up the bitmap.
|
||||
using (SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDCHandle, ref bmi, BitmapInfoHeader.DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0)) {
|
||||
using (SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDCHandle, ref bmi, BITMAPINFOHEADER.DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0)) {
|
||||
if (safeDibSectionHandle.IsInvalid) {
|
||||
// Get Exception before the error is lost
|
||||
Exception exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
|
||||
|
|
|
@ -212,7 +212,7 @@ namespace GreenshotPlugin.UnmanagedHelpers {
|
|||
[DllImport("gdi32", SetLastError=true)]
|
||||
public static extern IntPtr SelectObject(SafeHandle hDC, SafeHandle hObject);
|
||||
[DllImport("gdi32", SetLastError=true)]
|
||||
public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BitmapInfoHeader bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset);
|
||||
public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADER bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset);
|
||||
[DllImport("gdi32", SetLastError=true)]
|
||||
public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
|
||||
[DllImport("gdi32", SetLastError=true)]
|
||||
|
@ -257,7 +257,7 @@ namespace GreenshotPlugin.UnmanagedHelpers {
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
public struct BitmapFileHeader {
|
||||
public struct BITMAPFILEHEADER {
|
||||
public static readonly short BM = 0x4d42; // BM
|
||||
public short bfType;
|
||||
public int bfSize;
|
||||
|
@ -266,66 +266,166 @@ namespace GreenshotPlugin.UnmanagedHelpers {
|
|||
public int bfOffBits;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct BitmapInfoHeader {
|
||||
public uint biSize;
|
||||
public int biWidth;
|
||||
public int biHeight;
|
||||
public short biPlanes;
|
||||
public short biBitCount;
|
||||
public uint biCompression;
|
||||
public uint biSizeImage;
|
||||
public int biXPelsPerMeter;
|
||||
public int biYPelsPerMeter;
|
||||
public uint biClrUsed;
|
||||
public int biClrImportant;
|
||||
|
||||
private const int BI_RGB = 0; //Das Bitmap ist nicht komprimiert
|
||||
private const int BI_RLE8 = 1; //Das Bitmap ist komprimiert (Für 8-Bit Bitmaps)
|
||||
private const int BI_RLE4 = 2; //Das Bitmap ist komprimiert (Für 4-Bit Bitmaps)
|
||||
private const int BI_BITFIELDS = 3; //Das Bitmap ist nicht komprimiert. Die Farbtabelle enthält
|
||||
public const int DIB_RGB_COLORS = 0;
|
||||
|
||||
public BitmapInfoHeader(int width, int height, short bpp) {
|
||||
biSize = (uint)Marshal.SizeOf(typeof(BitmapInfoHeader)); // BITMAPINFOHEADER is 40 bytes
|
||||
biPlanes = 1; // Should allways be 1
|
||||
biCompression = BI_RGB;
|
||||
biWidth=width;
|
||||
biHeight=height;
|
||||
biBitCount=bpp;
|
||||
biSizeImage = 0;
|
||||
biXPelsPerMeter = 0;
|
||||
biYPelsPerMeter = 0;
|
||||
biClrUsed = 0;
|
||||
biClrImportant = 0;
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct BitfieldColorMask {
|
||||
public uint blue;
|
||||
public uint green;
|
||||
public uint red;
|
||||
public void InitValues() {
|
||||
red = (uint)255 << 8;
|
||||
green = (uint)255 << 16;
|
||||
blue = (uint)255 << 24;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct BitmapV5Header {
|
||||
public uint bV5Size;
|
||||
public int bV5Width;
|
||||
public int bV5Height;
|
||||
public UInt16 bV5Planes;
|
||||
public UInt16 bV5BitCount;
|
||||
public uint bV5Compression;
|
||||
public uint bV5SizeImage;
|
||||
public int bV5XPelsPerMeter;
|
||||
public int bV5YPelsPerMeter;
|
||||
public UInt16 bV5ClrUsed;
|
||||
public UInt16 bV5ClrImportant;
|
||||
public UInt16 bV5RedMask;
|
||||
public UInt16 bV5GreenMask;
|
||||
public UInt16 bV5BlueMask;
|
||||
public UInt16 bV5AlphaMask;
|
||||
public UInt16 bV5CSType;
|
||||
public IntPtr bV5Endpoints;
|
||||
public UInt16 bV5GammaRed;
|
||||
public UInt16 bV5GammaGreen;
|
||||
public UInt16 bV5GammaBlue;
|
||||
public UInt16 bV5Intent;
|
||||
public UInt16 bV5ProfileData;
|
||||
public UInt16 bV5ProfileSize;
|
||||
public UInt16 bV5Reserved;
|
||||
}
|
||||
public struct CIEXYZ {
|
||||
public uint ciexyzX; //FXPT2DOT30
|
||||
public uint ciexyzY; //FXPT2DOT30
|
||||
public uint ciexyzZ; //FXPT2DOT30
|
||||
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 enum BI_COMPRESSION : uint {
|
||||
BI_RGB = 0, // Uncompressed
|
||||
BI_RLE8 = 1, // RLE 8BPP
|
||||
BI_RLE4 = 2, // RLE 4BPP
|
||||
BI_BITFIELDS = 3, // Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. This is valid when used with 16- and 32-bpp bitmaps.
|
||||
BI_JPEG = 4, // Indicates that the image is a JPEG image.
|
||||
BI_PNG = 5 // Indicates that the image is a PNG image.
|
||||
}
|
||||
|
||||
[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;
|
||||
[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; // Rendering intent for bitmap
|
||||
[FieldOffset(112)]
|
||||
public uint bV5ProfileData;
|
||||
[FieldOffset(116)]
|
||||
public uint bV5ProfileSize;
|
||||
[FieldOffset(120)]
|
||||
public uint bV5Reserved;
|
||||
|
||||
public const int DIB_RGB_COLORS = 0;
|
||||
|
||||
public BITMAPINFOHEADER(int width, int height, ushort bpp) {
|
||||
biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER < DIBV5 is 40 bytes
|
||||
biPlanes = 1; // Should allways be 1
|
||||
biCompression = BI_COMPRESSION.BI_RGB;
|
||||
biWidth = width;
|
||||
biHeight = height;
|
||||
biBitCount = bpp;
|
||||
biSizeImage = (uint)(width*height*(bpp>>3));
|
||||
biXPelsPerMeter = 0;
|
||||
biYPelsPerMeter = 0;
|
||||
biClrUsed = 0;
|
||||
biClrImportant = 0;
|
||||
|
||||
// V5
|
||||
bV5RedMask = (uint)255 << 16;
|
||||
bV5GreenMask = (uint)255 << 8;
|
||||
bV5BlueMask = (uint)255;
|
||||
bV5AlphaMask = (uint)255 << 24;
|
||||
bV5CSType = 1934772034; // sRGB
|
||||
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 bool IsDibV5 {
|
||||
get {
|
||||
uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER));
|
||||
return biSize >= sizeOfBMI;
|
||||
}
|
||||
}
|
||||
public uint OffsetToPixels {
|
||||
get {
|
||||
if (biCompression == BI_COMPRESSION.BI_BITFIELDS) {
|
||||
// Add 3x4 bytes for the bitfield color mask
|
||||
return biSize + 3 * 4;
|
||||
}
|
||||
return biSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayoutAttribute(LayoutKind.Sequential)]
|
||||
public struct BITMAPINFO {
|
||||
/// <summary>
|
||||
/// A BITMAPINFOHEADER structure that contains information about the dimensions of color format.
|
||||
/// </summary>
|
||||
public BITMAPINFOHEADER bmiHeader;
|
||||
|
||||
/// <summary>
|
||||
/// An array of RGBQUAD. The elements of the array that make up the color table.
|
||||
/// </summary>
|
||||
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = UnmanagedType.Struct)]
|
||||
public RGBQUAD[] bmiColors;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RGBQUAD {
|
||||
public byte rgbBlue;
|
||||
public byte rgbGreen;
|
||||
public byte rgbRed;
|
||||
public byte rgbReserved;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue