mirror of
https://github.com/greenshot/greenshot
synced 2025-08-19 21:13:23 -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.
|
* 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-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.
|
* 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:
|
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.)
|
* 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 = "JFIF";
|
||||||
private static readonly string FORMAT_JFIF_OFFICEART = "JFIF+Office Art";
|
private static readonly string FORMAT_JFIF_OFFICEART = "JFIF+Office Art";
|
||||||
private static readonly string FORMAT_GIF = "GIF";
|
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;
|
private static IntPtr nextClipboardViewer = IntPtr.Zero;
|
||||||
// Template for the HTML Text on the clipboard
|
// Template for the HTML Text on the clipboard
|
||||||
|
@ -230,6 +231,7 @@ EndSelection:<<<<<<<4
|
||||||
|| dataObject.GetDataPresent(DataFormats.Tiff)
|
|| dataObject.GetDataPresent(DataFormats.Tiff)
|
||||||
|| dataObject.GetDataPresent(DataFormats.EnhancedMetafile)
|
|| dataObject.GetDataPresent(DataFormats.EnhancedMetafile)
|
||||||
|| dataObject.GetDataPresent(FORMAT_PNG)
|
|| dataObject.GetDataPresent(FORMAT_PNG)
|
||||||
|
|| dataObject.GetDataPresent(FORMAT_17)
|
||||||
|| dataObject.GetDataPresent(FORMAT_JPG)
|
|| dataObject.GetDataPresent(FORMAT_JPG)
|
||||||
|| dataObject.GetDataPresent(FORMAT_GIF)) {
|
|| dataObject.GetDataPresent(FORMAT_GIF)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -324,30 +326,14 @@ EndSelection:<<<<<<<4
|
||||||
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) {
|
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) {
|
||||||
// Outlook ??
|
// 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...");
|
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 {
|
} 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) {
|
foreach (string currentFormat in retrieveFormats) {
|
||||||
if (FORMAT_BITMAP_PLACEHOLDER.Equals(currentFormat)) {
|
if (formats.Contains(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)) {
|
|
||||||
LOG.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
|
LOG.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
|
||||||
if (currentFormat == DataFormats.Dib) {
|
returnImage = GetImageForFormat(currentFormat, dataObject);
|
||||||
returnImage = GetDIBImage(dataObject);
|
|
||||||
} else if (currentFormat == FORMAT_17) {
|
|
||||||
returnImage = CF_DIBV5ToBitmap(dataObject);
|
|
||||||
} else {
|
|
||||||
returnImage = GetImageFormat(currentFormat, dataObject);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
LOG.DebugFormat("Couldn't find format {0}.", currentFormat);
|
LOG.DebugFormat("Couldn't find format {0}.", currentFormat);
|
||||||
}
|
}
|
||||||
|
@ -361,94 +347,77 @@ EndSelection:<<<<<<<4
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert Format17 (DIBV5) to a bitmap
|
/// Helper method to try to get an image in the specified format from the dataObject
|
||||||
/// 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>
|
|
||||||
/// the DIB readed should solve the issue reported here: https://sourceforge.net/projects/greenshot/forums/forum/676083/topic/6354353/index/page/1
|
/// 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>
|
/// </summary>
|
||||||
/// <returns>Image</returns>
|
/// <param name="format">string with the format</param>
|
||||||
private static Image GetDIBImage(IDataObject dataObject) {
|
/// <param name="dataObject">IDataObject</param>
|
||||||
try {
|
/// <returns>Image or null</returns>
|
||||||
// If the EnableSpecialDIBClipboardReader flag in the config is set, use the code from:
|
private static Image GetImageForFormat(string format, IDataObject dataObject) {
|
||||||
// http://www.thomaslevesque.com/2009/02/05/wpf-paste-an-image-from-the-clipboard/
|
object clipboardObject = GetFromDataObject(dataObject, format);
|
||||||
// to read the DeviceIndependentBitmap from the clipboard, this might fix bug 3576125
|
MemoryStream imageStream = clipboardObject as MemoryStream;
|
||||||
|
if (!isValidStream(imageStream)) {
|
||||||
|
// TODO: add "HTML Format" support here...
|
||||||
|
return clipboardObject as Image;
|
||||||
|
} else {
|
||||||
if (config.EnableSpecialDIBClipboardReader) {
|
if (config.EnableSpecialDIBClipboardReader) {
|
||||||
MemoryStream dibStream = GetFromDataObject(dataObject, DataFormats.Dib) as MemoryStream;
|
if (format == FORMAT_17 || format == DataFormats.Dib) {
|
||||||
if (isValidStream(dibStream)) {
|
LOG.Info("Found DIB stream, trying to process it.");
|
||||||
LOG.Info("Found valid DIB stream, trying to process it.");
|
try {
|
||||||
byte[] dibBuffer = new byte[dibStream.Length];
|
byte[] dibBuffer = new byte[imageStream.Length];
|
||||||
dibStream.Read(dibBuffer, 0, dibBuffer.Length);
|
imageStream.Read(dibBuffer, 0, dibBuffer.Length);
|
||||||
BitmapInfoHeader infoHeader = BinaryStructHelper.FromByteArray<BitmapInfoHeader>(dibBuffer);
|
BITMAPINFOHEADER infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADER>(dibBuffer);
|
||||||
LOG.InfoFormat("Using special DIB format reader for biCompression {0}", infoHeader.biCompression);
|
if (!infoHeader.IsDibV5) {
|
||||||
int fileHeaderSize = Marshal.SizeOf(typeof(BitmapFileHeader));
|
LOG.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
|
||||||
uint infoHeaderSize = infoHeader.biSize;
|
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
|
||||||
int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
|
uint infoHeaderSize = infoHeader.biSize;
|
||||||
|
int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
|
||||||
|
|
||||||
BitmapFileHeader fileHeader = new BitmapFileHeader();
|
BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER();
|
||||||
fileHeader.bfType = BitmapFileHeader.BM;
|
fileHeader.bfType = BITMAPFILEHEADER.BM;
|
||||||
fileHeader.bfSize = fileSize;
|
fileHeader.bfSize = fileSize;
|
||||||
fileHeader.bfReserved1 = 0;
|
fileHeader.bfReserved1 = 0;
|
||||||
fileHeader.bfReserved2 = 0;
|
fileHeader.bfReserved2 = 0;
|
||||||
fileHeader.bfOffBits = (int)(fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4);
|
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()) {
|
using (MemoryStream bitmapStream = new MemoryStream()) {
|
||||||
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
|
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
|
||||||
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
|
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
|
||||||
bitmapStream.Seek(0, SeekOrigin.Begin);
|
bitmapStream.Seek(0, SeekOrigin.Begin);
|
||||||
using (Image tmpImage = Image.FromStream(bitmapStream)) {
|
using (Image tmpImage = Image.FromStream(bitmapStream)) {
|
||||||
if (tmpImage != null) {
|
if (tmpImage != null) {
|
||||||
return ImageHelper.Clone(tmpImage);
|
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 {
|
} else {
|
||||||
LOG.Info("Skipping special DIB format reader as it's disabled in the configuration.");
|
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 {
|
try {
|
||||||
imageStream.Seek(0, SeekOrigin.Begin);
|
imageStream.Seek(0, SeekOrigin.Begin);
|
||||||
using (Image tmpImage = Image.FromStream(imageStream, true, true)) {
|
using (Image tmpImage = Image.FromStream(imageStream, true, true)) {
|
||||||
|
@ -539,6 +508,7 @@ EndSelection:<<<<<<<4
|
||||||
//ido.SetData(DataFormats.Bitmap, true, image);
|
//ido.SetData(DataFormats.Bitmap, true, image);
|
||||||
|
|
||||||
MemoryStream dibStream = null;
|
MemoryStream dibStream = null;
|
||||||
|
MemoryStream dibV5Stream = null;
|
||||||
MemoryStream pngStream = null;
|
MemoryStream pngStream = null;
|
||||||
Image imageToSave = null;
|
Image imageToSave = null;
|
||||||
bool disposeImage = false;
|
bool disposeImage = false;
|
||||||
|
@ -580,6 +550,43 @@ EndSelection:<<<<<<<4
|
||||||
LOG.Error("Error creating DIB for the Clipboard.", 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
|
// Set the HTML
|
||||||
if (config.ClipboardFormats.Contains(ClipboardFormat.HTML)) {
|
if (config.ClipboardFormats.Contains(ClipboardFormat.HTML)) {
|
||||||
string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null);
|
string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null);
|
||||||
|
@ -623,6 +630,10 @@ EndSelection:<<<<<<<4
|
||||||
dibStream.Dispose();
|
dibStream.Dispose();
|
||||||
dibStream = null;
|
dibStream = null;
|
||||||
}
|
}
|
||||||
|
if (dibV5Stream != null) {
|
||||||
|
dibV5Stream.Dispose();
|
||||||
|
dibV5Stream = null;
|
||||||
|
}
|
||||||
// cleanup if needed
|
// cleanup if needed
|
||||||
if (disposeImage && imageToSave != null) {
|
if (disposeImage && imageToSave != null) {
|
||||||
imageToSave.Dispose();
|
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>
|
/// <summary>
|
||||||
/// Set Object with type Type to the clipboard
|
/// Set Object with type Type to the clipboard
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -29,7 +29,7 @@ using System.Reflection;
|
||||||
|
|
||||||
namespace GreenshotPlugin.Core {
|
namespace GreenshotPlugin.Core {
|
||||||
public enum ClipboardFormat {
|
public enum ClipboardFormat {
|
||||||
PNG, DIB, HTML, HTMLDATAURL, BITMAP
|
PNG, DIB, HTML, HTMLDATAURL, BITMAP, DIBV5
|
||||||
}
|
}
|
||||||
public enum OutputFormat {
|
public enum OutputFormat {
|
||||||
bmp, gif, jpg, png, tiff, greenshot
|
bmp, gif, jpg, png, tiff, greenshot
|
||||||
|
|
|
@ -651,15 +651,15 @@ namespace GreenshotPlugin.Core {
|
||||||
// throw exception
|
// throw exception
|
||||||
throw exceptionToThrow;
|
throw exceptionToThrow;
|
||||||
}
|
}
|
||||||
// Create BitmapInfoHeader for CreateDIBSection
|
// Create BITMAPINFOHEADER for CreateDIBSection
|
||||||
BitmapInfoHeader bmi = new BitmapInfoHeader(captureBounds.Width, captureBounds.Height, 24);
|
BITMAPINFOHEADER bmi = new BITMAPINFOHEADER(captureBounds.Width, captureBounds.Height, 24);
|
||||||
|
|
||||||
// Make sure the last error is set to 0
|
// Make sure the last error is set to 0
|
||||||
Win32.SetLastError(0);
|
Win32.SetLastError(0);
|
||||||
|
|
||||||
// create a bitmap we can copy it to, using GetDeviceCaps to get the width/height
|
// 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.
|
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) {
|
if (safeDibSectionHandle.IsInvalid) {
|
||||||
// Get Exception before the error is lost
|
// Get Exception before the error is lost
|
||||||
Exception exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
|
Exception exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
|
||||||
|
|
|
@ -212,7 +212,7 @@ namespace GreenshotPlugin.UnmanagedHelpers {
|
||||||
[DllImport("gdi32", SetLastError=true)]
|
[DllImport("gdi32", SetLastError=true)]
|
||||||
public static extern IntPtr SelectObject(SafeHandle hDC, SafeHandle hObject);
|
public static extern IntPtr SelectObject(SafeHandle hDC, SafeHandle hObject);
|
||||||
[DllImport("gdi32", SetLastError=true)]
|
[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)]
|
[DllImport("gdi32", SetLastError=true)]
|
||||||
public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
|
public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
|
||||||
[DllImport("gdi32", SetLastError=true)]
|
[DllImport("gdi32", SetLastError=true)]
|
||||||
|
@ -257,7 +257,7 @@ namespace GreenshotPlugin.UnmanagedHelpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||||
public struct BitmapFileHeader {
|
public struct BITMAPFILEHEADER {
|
||||||
public static readonly short BM = 0x4d42; // BM
|
public static readonly short BM = 0x4d42; // BM
|
||||||
public short bfType;
|
public short bfType;
|
||||||
public int bfSize;
|
public int bfSize;
|
||||||
|
@ -267,65 +267,165 @@ namespace GreenshotPlugin.UnmanagedHelpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct BitmapInfoHeader {
|
public struct BitfieldColorMask {
|
||||||
public uint biSize;
|
public uint blue;
|
||||||
public int biWidth;
|
public uint green;
|
||||||
public int biHeight;
|
public uint red;
|
||||||
public short biPlanes;
|
public void InitValues() {
|
||||||
public short biBitCount;
|
red = (uint)255 << 8;
|
||||||
public uint biCompression;
|
green = (uint)255 << 16;
|
||||||
public uint biSizeImage;
|
blue = (uint)255 << 24;
|
||||||
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)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct BitmapV5Header {
|
public struct CIEXYZ {
|
||||||
public uint bV5Size;
|
public uint ciexyzX; //FXPT2DOT30
|
||||||
public int bV5Width;
|
public uint ciexyzY; //FXPT2DOT30
|
||||||
public int bV5Height;
|
public uint ciexyzZ; //FXPT2DOT30
|
||||||
public UInt16 bV5Planes;
|
public CIEXYZ(uint FXPT2DOT30) {
|
||||||
public UInt16 bV5BitCount;
|
ciexyzX = FXPT2DOT30;
|
||||||
public uint bV5Compression;
|
ciexyzY = FXPT2DOT30;
|
||||||
public uint bV5SizeImage;
|
ciexyzZ = FXPT2DOT30;
|
||||||
public int bV5XPelsPerMeter;
|
}
|
||||||
public int bV5YPelsPerMeter;
|
}
|
||||||
public UInt16 bV5ClrUsed;
|
|
||||||
public UInt16 bV5ClrImportant;
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public UInt16 bV5RedMask;
|
public struct CIEXYZTRIPLE {
|
||||||
public UInt16 bV5GreenMask;
|
public CIEXYZ ciexyzRed;
|
||||||
public UInt16 bV5BlueMask;
|
public CIEXYZ ciexyzGreen;
|
||||||
public UInt16 bV5AlphaMask;
|
public CIEXYZ ciexyzBlue;
|
||||||
public UInt16 bV5CSType;
|
}
|
||||||
public IntPtr bV5Endpoints;
|
|
||||||
public UInt16 bV5GammaRed;
|
public enum BI_COMPRESSION : uint {
|
||||||
public UInt16 bV5GammaGreen;
|
BI_RGB = 0, // Uncompressed
|
||||||
public UInt16 bV5GammaBlue;
|
BI_RLE8 = 1, // RLE 8BPP
|
||||||
public UInt16 bV5Intent;
|
BI_RLE4 = 2, // RLE 4BPP
|
||||||
public UInt16 bV5ProfileData;
|
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.
|
||||||
public UInt16 bV5ProfileSize;
|
BI_JPEG = 4, // Indicates that the image is a JPEG image.
|
||||||
public UInt16 bV5Reserved;
|
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