mirror of
https://github.com/greenshot/greenshot.git
synced 2025-03-12 05:25:25 -07:00
Starting to port the old clipboard code to a newer API
This commit is contained in:
parent
3b36090d5a
commit
3950090416
src/Greenshot.Addons
282
src/Greenshot.Addons/Extensions/ClipboardBitmapExtensions.cs
Normal file
282
src/Greenshot.Addons/Extensions/ClipboardBitmapExtensions.cs
Normal file
@ -0,0 +1,282 @@
|
||||
#region Greenshot GNU General Public License
|
||||
|
||||
// Greenshot - a free and open source screenshot tool
|
||||
// Copyright (C) 2007-2018 Thomas Braun, Jens Klingen, Robin Krom
|
||||
//
|
||||
// For more information see: http://getgreenshot.org/
|
||||
// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dapplo.Log;
|
||||
using Dapplo.Windows.Clipboard;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Dapplo.Windows.Gdi32.Enums;
|
||||
using Dapplo.Windows.Gdi32.Structs;
|
||||
using Greenshot.Addons.Core;
|
||||
using Greenshot.Addons.Core.Enums;
|
||||
using Greenshot.Addons.Interfaces;
|
||||
using Greenshot.Addons.Interfaces.Plugin;
|
||||
using Greenshot.Gfx;
|
||||
|
||||
namespace Greenshot.Addons.Extensions
|
||||
{
|
||||
public static class ClipboardBitmapExtensions
|
||||
{
|
||||
private static readonly LogSource Log = new LogSource();
|
||||
private static readonly string[] SupportedBitmapFormats =
|
||||
{
|
||||
"PNG",
|
||||
"PNG+Office Art",
|
||||
"Format17",
|
||||
"JPG",
|
||||
"JFIF",
|
||||
"JFIF+Office Art",
|
||||
"GIF",
|
||||
StandardClipboardFormats.Bitmap.AsString()
|
||||
};
|
||||
|
||||
private static readonly string[] SupportedExtensions =
|
||||
{
|
||||
".png",
|
||||
".jpeg",
|
||||
".jpg",
|
||||
".bmp",
|
||||
".gif"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Place the bitmap on the clipboard
|
||||
/// </summary>
|
||||
/// <param name="clipboardAccessToken">IClipboardAccessToken</param>
|
||||
/// <param name="surface">ISurface</param>
|
||||
/// <param name="outputSettings">SurfaceOutputSettings specifying how to output the surface</param>
|
||||
public static void SetAsBitmap(this IClipboardAccessToken clipboardAccessToken, ISurface surface, SurfaceOutputSettings outputSettings)
|
||||
{
|
||||
using (var bitmapStream = new MemoryStream())
|
||||
{
|
||||
ImageOutput.SaveToStream(surface, bitmapStream, outputSettings);
|
||||
bitmapStream.Seek(0, SeekOrigin.Begin);
|
||||
// Set the stream
|
||||
var clipboardFormat = ClipboardFormatExtensions.MapFormatToId(outputSettings.Format.ToString().ToUpperInvariant());
|
||||
clipboardAccessToken.SetAsStream(clipboardFormat, bitmapStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is there a Bitmap on the clipboard?
|
||||
/// </summary>
|
||||
/// <param name="clipboardAccessToken">IClipboardAccessToken</param>
|
||||
/// <returns>bool</returns>
|
||||
public static bool HasImage(this IClipboardAccessToken clipboardAccessToken)
|
||||
{
|
||||
var formats = clipboardAccessToken.AvailableFormats();
|
||||
if (formats.Intersect(SupportedBitmapFormats).Any())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return clipboardAccessToken.GetFilenames()
|
||||
.Select(filename => Path.GetExtension(filename).ToLowerInvariant())
|
||||
.Intersect(SupportedExtensions)
|
||||
.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A special format 17 bitmap reader
|
||||
/// </summary>
|
||||
/// <param name="clipboardAccessToken">IClipboardAccessToken</param>
|
||||
/// <returns>Bitmap or null</returns>
|
||||
public static Bitmap GetAsFormat17(this IClipboardAccessToken clipboardAccessToken)
|
||||
{
|
||||
var formats = clipboardAccessToken.AvailableFormats().ToList();
|
||||
if (!formats.Contains("Format17"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var format17Bytes = clipboardAccessToken.GetAsBytes("Format17");
|
||||
var infoHeader = BinaryStructHelper.FromByteArray<BitmapInfoHeader>(format17Bytes);
|
||||
if (!infoHeader.IsDibV5)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Using special DIBV5 / Format17 format reader
|
||||
// CF_DIBV5
|
||||
var gcHandle = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
var handle = GCHandle.Alloc(format17Bytes, GCHandleType.Pinned);
|
||||
gcHandle = GCHandle.ToIntPtr(handle);
|
||||
return
|
||||
new Bitmap(infoHeader.Width, infoHeader.Height,
|
||||
-(int)(infoHeader.SizeImage / infoHeader.Height),
|
||||
infoHeader.BitCount == 32 ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb,
|
||||
new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels + (infoHeader.Height - 1) * (int)(infoHeader.SizeImage / infoHeader.Height))
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error().WriteLine(ex, "Problem retrieving Format17 from clipboard.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (gcHandle == IntPtr.Zero)
|
||||
{
|
||||
GCHandle.FromIntPtr(gcHandle).Free();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a DIB from the Clipboard
|
||||
/// </summary>
|
||||
/// <param name="clipboardAccessToken"></param>
|
||||
/// <returns>Bitmap or null</returns>
|
||||
public static Bitmap GetAsDeviceIndependendBitmap(this IClipboardAccessToken clipboardAccessToken)
|
||||
{
|
||||
var formats = clipboardAccessToken.AvailableFormats().ToList();
|
||||
if (!formats.Contains(StandardClipboardFormats.Bitmap.AsString()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var format17Bytes = clipboardAccessToken.GetAsBytes(StandardClipboardFormats.Bitmap.AsString());
|
||||
var infoHeader = BinaryStructHelper.FromByteArray<BitmapInfoHeader>(format17Bytes);
|
||||
if (infoHeader.IsDibV5)
|
||||
{
|
||||
Log.Warn().WriteLine("Getting DIBV5 (format 17) when requesting DIB");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Bitmap version older than 5
|
||||
var fileHeaderSize = Marshal.SizeOf(typeof(BitmapFileHeader));
|
||||
var fileHeader = BitmapFileHeader.Create(infoHeader);
|
||||
var fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader);
|
||||
|
||||
using (var bitmapStream = new MemoryStream())
|
||||
{
|
||||
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
|
||||
bitmapStream.Write(format17Bytes, 0, format17Bytes.Length);
|
||||
bitmapStream.Seek(0, SeekOrigin.Begin);
|
||||
var image = BitmapHelper.FromStream(bitmapStream);
|
||||
if (image != null)
|
||||
{
|
||||
return image;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Place the surface as Format17 bitmap on the clipboard
|
||||
/// </summary>
|
||||
/// <param name="clipboardAccessToken">IClipboardAccessToken</param>
|
||||
/// <param name="surface">ISurface</param>
|
||||
public static void SetAsFormat17(this IClipboardAccessToken clipboardAccessToken, ISurface surface)
|
||||
{
|
||||
// Create the stream for the clipboard
|
||||
using (var dibV5Stream = new MemoryStream())
|
||||
{
|
||||
var outputSettings = new SurfaceOutputSettings(OutputFormats.png, 100, false);
|
||||
bool dispose = ImageOutput.CreateBitmapFromSurface(surface, outputSettings, out var bitmapToSave);
|
||||
// Create the BITMAPINFOHEADER
|
||||
var header = BitmapInfoHeader.Create(bitmapToSave.Width, bitmapToSave.Height, 32);
|
||||
// Make sure we have BI_BITFIELDS, this seems to be normal for Format17?
|
||||
header.Compression = BitmapCompressionMethods.BI_BITFIELDS;
|
||||
|
||||
var headerBytes = BinaryStructHelper.ToByteArray(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
|
||||
var colorMask = BitfieldColorMask.Create();
|
||||
// Create the byte[] from the struct
|
||||
var colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask);
|
||||
Array.Reverse(colorMaskBytes);
|
||||
// Write to the stream
|
||||
dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length);
|
||||
|
||||
// Create the raw bytes for the pixels only
|
||||
var bitmapBytes = BitmapToByteArray(bitmapToSave);
|
||||
// Write to the stream
|
||||
dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length);
|
||||
|
||||
// Set the DIBv5 to the clipboard DataObject
|
||||
clipboardAccessToken.SetAsStream("Format17", dibV5Stream);
|
||||
if (dispose)
|
||||
{
|
||||
bitmapToSave.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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.
|
||||
var rect = new NativeRect(0, 0, bitmap.Width, bitmap.Height);
|
||||
var bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||
|
||||
var absStride = Math.Abs(bmpData.Stride);
|
||||
var bytes = absStride * bitmap.Height;
|
||||
long ptr = bmpData.Scan0.ToInt32();
|
||||
// Declare an array to hold the bytes of the bitmap.
|
||||
var rgbValues = new byte[bytes];
|
||||
|
||||
for (var i = 0; i < bitmap.Height; i++)
|
||||
{
|
||||
var 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>
|
||||
/// Place the bitmap on the clipboard as DIB
|
||||
/// </summary>
|
||||
/// <param name="clipboardAccessToken">IClipboardAccessToken</param>
|
||||
/// <param name="surface">ISurface</param>
|
||||
public static void SetAsDeviceIndependendBitmap(this IClipboardAccessToken clipboardAccessToken, ISurface surface)
|
||||
{
|
||||
using (var bitmapStream = new MemoryStream())
|
||||
{
|
||||
ImageOutput.SaveToStream(surface, bitmapStream, new SurfaceOutputSettings{Format = OutputFormats.bmp});
|
||||
bitmapStream.Seek(Marshal.SizeOf(typeof(BitmapFileHeader)), SeekOrigin.Begin);
|
||||
// Set the stream
|
||||
clipboardAccessToken.SetAsStream(StandardClipboardFormats.DeviceIndependentBitmap, bitmapStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -207,6 +207,7 @@
|
||||
<Compile Include="Core\CaptureHandler.cs" />
|
||||
<Compile Include="Core\EventDelay.cs" />
|
||||
<Compile Include="Core\WmInputLangChangeRequestFilter.cs" />
|
||||
<Compile Include="Extensions\ClipboardBitmapExtensions.cs" />
|
||||
<Compile Include="Extensions\ClipboardHtmlExtensions.cs" />
|
||||
<Compile Include="Extensions\DestinationExtensions.cs" />
|
||||
<Compile Include="Extensions\LanguageExtensions.cs" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user