mirror of
https://github.com/greenshot/greenshot
synced 2025-08-19 21:13:23 -07:00
Added some missing files.
git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@1603 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4
This commit is contained in:
parent
8d458998a1
commit
e860872ae0
7 changed files with 2231 additions and 0 deletions
901
Greenshot/Helpers/AviHelper.cs
Normal file
901
Greenshot/Helpers/AviHelper.cs
Normal file
|
@ -0,0 +1,901 @@
|
|||
// AForge Video for Windows Library
|
||||
// AForge.NET framework
|
||||
// http://www.aforgenet.com/framework/
|
||||
//
|
||||
// Copyright © Andrew Kirillov, 2007-2009
|
||||
// andrew.kirillov@aforgenet.com
|
||||
//
|
||||
//
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using GreenshotPlugin.UnmanagedHelpers;
|
||||
|
||||
namespace Greenshot.Helpers {
|
||||
|
||||
/// <summary>
|
||||
/// AVI files writing using Video for Windows interface.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks><para>The class allows to write AVI files using Video for Windows API.</para>
|
||||
///
|
||||
/// <para>Sample usage:</para>
|
||||
/// /// // instantiate AVI writer, use WMV3 codec
|
||||
/// AVIWriter writer = new AVIWriter( "wmv3" );
|
||||
/// // create new AVI file and open it
|
||||
/// writer.Open( "test.avi", 320, 240 );
|
||||
/// // create frame image
|
||||
/// Bitmap image = new Bitmap( 320, 240 );
|
||||
///
|
||||
/// for ( int i = 0; i < 240; i++ )
|
||||
/// {
|
||||
/// // update image
|
||||
/// image.SetPixel( i, i, Color.Red );
|
||||
/// // add the image as a new frame of video file
|
||||
/// writer.AddFrame( image );
|
||||
/// }
|
||||
/// writer.Close( );
|
||||
///
|
||||
/// </remarks>
|
||||
///
|
||||
public class AVIWriter : IDisposable {
|
||||
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(AVIWriter));
|
||||
// AVI file
|
||||
private IntPtr file;
|
||||
// video stream
|
||||
private IntPtr stream;
|
||||
// compressed stream
|
||||
private IntPtr streamCompressed;
|
||||
// width of video frames
|
||||
private int width;
|
||||
// height of vide frames
|
||||
private int height;
|
||||
// length of one line
|
||||
private int stride;
|
||||
// quality
|
||||
private int quality = -1;
|
||||
// frame rate
|
||||
private int rate = 25;
|
||||
// current position
|
||||
private int position;
|
||||
// codec used for video compression
|
||||
private string codec = null; //"DIB ";
|
||||
|
||||
/// <summary>
|
||||
/// Width of video frames.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks><para>The property specifies the width of video frames, which are acceptable
|
||||
/// by <see cref="AddFrame"/> method for saving, which is set in <see cref="Open"/>
|
||||
/// method.</para></remarks>
|
||||
///
|
||||
public int Width {
|
||||
get { return width; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Height of video frames.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks><para>The property specifies the height of video frames, which are acceptable
|
||||
/// by <see cref="AddFrame"/> method for saving, which is set in <see cref="Open"/>
|
||||
/// method.</para></remarks>
|
||||
///
|
||||
public int Height {
|
||||
get { return height; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current position in video stream.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks><para>The property tell current position in video stream, which actually equals
|
||||
/// to the amount of frames added using <see cref="AddFrame"/> method.</para></remarks>
|
||||
///
|
||||
public int Position
|
||||
{
|
||||
get { return position; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Desired playing frame rate.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks><para>The property sets the video frame rate, which should be use during playing
|
||||
/// of the video to be saved.</para>
|
||||
///
|
||||
/// <para><note>The property should be set befor opening new file to take effect.</note></para>
|
||||
///
|
||||
/// <para>Default frame rate is set to <b>25</b>.</para></remarks>
|
||||
///
|
||||
public int FrameRate
|
||||
{
|
||||
get { return rate; }
|
||||
set { rate = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Codec used for video compression.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks><para>The property sets the FOURCC code of video compression codec, which needs to
|
||||
/// be used for video encoding.</para>
|
||||
///
|
||||
/// <para><note>The property should be set befor opening new file to take effect.</note></para>
|
||||
///
|
||||
/// <para>Default video codec is set <b>"DIB "</b>, which means no compression.</para></remarks>
|
||||
///
|
||||
public string Codec
|
||||
{
|
||||
get { return codec; }
|
||||
set { codec = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compression video quality.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks><para>The property sets video quality used by codec in order to balance compression rate
|
||||
/// and image quality. The quality is measured usually in the [0, 100] range.</para>
|
||||
///
|
||||
/// <para><note>The property should be set befor opening new file to take effect.</note></para>
|
||||
///
|
||||
/// <para>Default value is set to <b>-1</b> - default compression quality of the codec.</para></remarks>
|
||||
///
|
||||
public int Quality
|
||||
{
|
||||
get { return quality; }
|
||||
set { quality = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AVIWriter"/> class.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>Initializes Video for Windows library.</remarks>
|
||||
///
|
||||
public AVIWriter() {
|
||||
Avi32.AVIFileInit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AVIWriter"/> class.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="codec">Codec to use for compression. eg [CVID],[IV50]</param>
|
||||
///
|
||||
/// <remarks>Initializes Video for Windows library.</remarks>
|
||||
///
|
||||
public AVIWriter(string codec) : this() {
|
||||
this.codec = codec;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the instance of the <see cref="AVIWriter"/> class.
|
||||
/// </summary>
|
||||
///
|
||||
~AVIWriter() {
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the object.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>Frees unmanaged resources used by the object. The object becomes unusable
|
||||
/// after that.</remarks>
|
||||
///
|
||||
public void Dispose() {
|
||||
Dispose(true);
|
||||
// remove me from the Finalization queue
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the object.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="disposing">Indicates if disposing was initiated manually.</param>
|
||||
///
|
||||
protected virtual void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
// dispose managed resources
|
||||
}
|
||||
// close current AVI file if any opened and uninitialize AVI library
|
||||
Close();
|
||||
Avi32.AVIFileExit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create new AVI file and open it for writing.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="fileName">AVI file name to create.</param>
|
||||
/// <param name="width">Video width.</param>
|
||||
/// <param name="height">Video height.</param>
|
||||
///
|
||||
/// <remarks><para>The method opens (creates) a video files, configure video codec and prepares
|
||||
/// the stream for saving video frames with a help of <see cref="AddFrame"/> method.</para></remarks>
|
||||
///
|
||||
/// <exception cref="ApplicationException">Failure of opening video files (the exception message
|
||||
/// specifies the issues).</exception>
|
||||
///
|
||||
public bool Open(string fileName, int width, int height) {
|
||||
lock (this) {
|
||||
// calculate stride
|
||||
stride = width * 4;
|
||||
if ((stride % 4) != 0)
|
||||
stride += (4 - stride % 4);
|
||||
|
||||
// create new file
|
||||
if (Avi32.AVIFileOpen(out file, fileName, Avi32.OpenFileMode.Create | Avi32.OpenFileMode.Write, IntPtr.Zero) != 0) {
|
||||
throw new ApplicationException("Failed opening file");
|
||||
}
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
// describe new stream
|
||||
Avi32.AVISTREAMINFO info = new Avi32.AVISTREAMINFO();
|
||||
|
||||
info.type = Avi32.mmioFOURCC("vids");
|
||||
if (codec != null) {
|
||||
info.handler = Avi32.mmioFOURCC(codec);
|
||||
} else {
|
||||
info.handler = Avi32.mmioFOURCC("DIB ");
|
||||
}
|
||||
info.scale = 1;
|
||||
info.rate = rate;
|
||||
info.suggestedBufferSize = stride * height;
|
||||
|
||||
// create stream
|
||||
if (Avi32.AVIFileCreateStream(file, out stream, ref info) != 0) {
|
||||
throw new ApplicationException("Failed creating stream");
|
||||
}
|
||||
|
||||
// describe compression options
|
||||
Avi32.AVICOMPRESSOPTIONS options = new Avi32.AVICOMPRESSOPTIONS();
|
||||
|
||||
|
||||
// uncomment if video settings dialog is required to show
|
||||
if (codec == null) {
|
||||
int retCode = Avi32.AVISaveOptions( stream, ref options );
|
||||
if (retCode == 0) {
|
||||
LOG.Debug("Cancel clicked!");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
options.handler = Avi32.mmioFOURCC(codec);
|
||||
options.quality = quality;
|
||||
}
|
||||
|
||||
// create compressed stream
|
||||
int retval = Avi32.AVIMakeCompressedStream(out streamCompressed, stream, ref options, IntPtr.Zero);
|
||||
if (retval != 0) {
|
||||
throw new ApplicationException("Failed creating compressed stream: " + retval);
|
||||
}
|
||||
|
||||
// describe frame format
|
||||
BitmapInfoHeader bitmapInfoHeader = new BitmapInfoHeader(width, height, 32);
|
||||
|
||||
// set frame format
|
||||
retval = Avi32.AVIStreamSetFormat(streamCompressed, 0, ref bitmapInfoHeader, Marshal.SizeOf(bitmapInfoHeader.GetType()));
|
||||
if (retval != 0) {
|
||||
throw new ApplicationException("Failed creating compressed stream: "+ retval);
|
||||
}
|
||||
position = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close video file.
|
||||
/// </summary>
|
||||
///
|
||||
public void Close() {
|
||||
LOG.Debug("Close called");
|
||||
lock (this) {
|
||||
// release compressed stream
|
||||
if (streamCompressed != IntPtr.Zero) {
|
||||
LOG.Debug("AVIStreamRelease streamCompressed");
|
||||
Avi32.AVIStreamRelease(streamCompressed);
|
||||
streamCompressed = IntPtr.Zero;
|
||||
}
|
||||
|
||||
// release stream
|
||||
if (stream != IntPtr.Zero) {
|
||||
LOG.Debug("AVIStreamRelease stream");
|
||||
Avi32.AVIStreamRelease(stream);
|
||||
stream = IntPtr.Zero;
|
||||
}
|
||||
|
||||
// release file
|
||||
if (file != IntPtr.Zero) {
|
||||
LOG.Debug("AVIFileRelease file");
|
||||
Avi32.AVIFileRelease(file);
|
||||
file = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add new frame to the AVI file.
|
||||
/// </summary>
|
||||
/// <param name="frameData">New frame data.</param>
|
||||
public void AddLowLevelFrame(IntPtr frameData) {
|
||||
lock (this) {
|
||||
// write to stream
|
||||
if (Avi32.AVIStreamWrite(streamCompressed, position, 1, frameData, stride * height, 0, IntPtr.Zero, IntPtr.Zero) != 0) {
|
||||
throw new ApplicationException("Failed adding frame");
|
||||
}
|
||||
|
||||
position++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Windows API functions and structures.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>The class provides Video for Windows and some other Avi32 functions and structurs.</remarks>
|
||||
///
|
||||
internal static class Avi32 {
|
||||
/// <summary>
|
||||
/// Copy a block of memory.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="dst">Destination pointer.</param>
|
||||
/// <param name="src">Source pointer.</param>
|
||||
/// <param name="count">Memory block's length to copy.</param>
|
||||
///
|
||||
/// <returns>Return's the value of <b>dst</b> - pointer to destination.</returns>
|
||||
///
|
||||
[DllImport("ntdll.dll")]
|
||||
public static extern int memcpy(int dst, int src, int count);
|
||||
|
||||
|
||||
// --- Video for Windows Functions
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the AVIFile library.
|
||||
/// </summary>
|
||||
///
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern void AVIFileInit();
|
||||
|
||||
/// <summary>
|
||||
/// Exit the AVIFile library.
|
||||
/// </summary>
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern void AVIFileExit();
|
||||
|
||||
/// <summary>
|
||||
/// Open an AVI file.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="aviHandler">Opened AVI file interface.</param>
|
||||
/// <param name="fileName">AVI file name.</param>
|
||||
/// <param name="mode">Opening mode (see <see cref="OpenFileMode"/>).</param>
|
||||
/// <param name="handler">Handler to use (<b>null</b> to use default).</param>
|
||||
///
|
||||
/// <returns>Returns zero on success or error code otherwise.</returns>
|
||||
///
|
||||
[DllImport("avifil32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int AVIFileOpen(out IntPtr aviHandler, String fileName, OpenFileMode mode, IntPtr handler);
|
||||
|
||||
/// <summary>
|
||||
/// Release an open AVI stream.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="aviHandler">Open AVI file interface.</param>
|
||||
///
|
||||
/// <returns>Returns the reference count of the file.</returns>
|
||||
///
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVIFileRelease(IntPtr aviHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Get stream interface that is associated with a specified AVI file
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="aviHandler">Handler to an open AVI file.</param>
|
||||
/// <param name="streamHandler">Stream interface.</param>
|
||||
/// <param name="streamType">Stream type to open.</param>
|
||||
/// <param name="streamNumner">Count of the stream type. Identifies which occurrence of the specified stream type to access. </param>
|
||||
///
|
||||
/// <returns></returns>
|
||||
///
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVIFileGetStream(IntPtr aviHandler, out IntPtr streamHandler, int streamType, int streamNumner);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new stream in an existing file and creates an interface to the new stream.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="aviHandler">Handler to an open AVI file.</param>
|
||||
/// <param name="streamHandler">Stream interface.</param>
|
||||
/// <param name="streamInfo">Pointer to a structure containing information about the new stream.</param>
|
||||
///
|
||||
/// <returns>Returns zero if successful or an error otherwise.</returns>
|
||||
///
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVIFileCreateStream(IntPtr aviHandler, out IntPtr streamHandler, ref AVISTREAMINFO streamInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Release an open AVI stream.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="streamHandler">Handle to an open stream.</param>
|
||||
///
|
||||
/// <returns>Returns the current reference count of the stream.</returns>
|
||||
///
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVIStreamRelease(IntPtr streamHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Set the format of a stream at the specified position.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="streamHandler">Handle to an open stream.</param>
|
||||
/// <param name="position">Position in the stream to receive the format.</param>
|
||||
/// <param name="format">Pointer to a structure containing the new format.</param>
|
||||
/// <param name="formatSize">Size, in bytes, of the block of memory referenced by <b>format</b>.</param>
|
||||
///
|
||||
/// <returns>Returns zero if successful or an error otherwise.</returns>
|
||||
///
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVIStreamSetFormat(IntPtr streamHandler, int position, ref BitmapInfoHeader format, int formatSize);
|
||||
|
||||
/// <summary>
|
||||
/// Get the starting sample number for the stream.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="streamHandler">Handle to an open stream.</param>
|
||||
///
|
||||
/// <returns>Returns the number if successful or – 1 otherwise.</returns>
|
||||
///
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVIStreamStart(IntPtr streamHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Get the length of the stream.
|
||||
/// </summary>
|
||||
/// <param name="streamHandler">Handle to an open stream.</param>
|
||||
/// <returns>Returns the stream's length, in samples, if successful or -1 otherwise. </returns>
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVIStreamLength(IntPtr streamHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Obtain stream header information.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="streamHandler">Handle to an open stream.</param>
|
||||
/// <param name="streamInfo">Pointer to a structure to contain the stream information.</param>
|
||||
/// <param name="infoSize">Size, in bytes, of the structure used for <b>streamInfo</b>.</param>
|
||||
///
|
||||
/// <returns>Returns zero if successful or an error otherwise.</returns>
|
||||
///
|
||||
[DllImport("avifil32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int AVIStreamInfo(IntPtr streamHandler, ref AVISTREAMINFO streamInfo, int infoSize);
|
||||
|
||||
/// <summary>
|
||||
/// Prepare to decompress video frames from the specified video stream
|
||||
/// </summary>
|
||||
/// <param name="streamHandler">Pointer to the video stream used as the video source.</param>
|
||||
/// <param name="wantedFormat">Pointer to a structure that defines the desired video format. Specify NULL to use a default format.</param>
|
||||
/// <returns>Returns an object that can be used with the <see cref="AVIStreamGetFrame"/> function.</returns>
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern IntPtr AVIStreamGetFrameOpen(IntPtr streamHandler, ref BitmapInfoHeader wantedFormat);
|
||||
|
||||
/// <summary>
|
||||
/// Prepare to decompress video frames from the specified video stream.
|
||||
/// </summary>
|
||||
/// <param name="streamHandler">Pointer to the video stream used as the video source.</param>
|
||||
/// <param name="wantedFormat">Pointer to a structure that defines the desired video format. Specify NULL to use a default format.</param>
|
||||
/// <returns>Returns a <b>GetFrame</b> object that can be used with the <see cref="AVIStreamGetFrame"/> function.</returns>
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern IntPtr AVIStreamGetFrameOpen(IntPtr streamHandler, int wantedFormat);
|
||||
|
||||
/// <summary>
|
||||
/// Releases resources used to decompress video frames.
|
||||
/// </summary>
|
||||
/// <param name="getFrameObject">Handle returned from the <see cref="AVIStreamGetFrameOpen(IntPtr,int)"/> function.</param>
|
||||
/// <returns>Returns zero if successful or an error otherwise.</returns>
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVIStreamGetFrameClose(IntPtr getFrameObject);
|
||||
|
||||
/// <summary>
|
||||
/// Return the address of a decompressed video frame.
|
||||
/// </summary>
|
||||
/// <param name="getFrameObject">Pointer to a GetFrame object.</param>
|
||||
/// <param name="position">Position, in samples, within the stream of the desired frame.</param>
|
||||
/// <returns>Returns a pointer to the frame data if successful or NULL otherwise.</returns>
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern IntPtr AVIStreamGetFrame(IntPtr getFrameObject, int position);
|
||||
|
||||
/// <summary>
|
||||
/// Write data to a stream.
|
||||
/// </summary>
|
||||
/// <param name="streamHandler">Handle to an open stream.</param>
|
||||
/// <param name="start">First sample to write.</param>
|
||||
/// <param name="samples">Number of samples to write.</param>
|
||||
/// <param name="buffer">Pointer to a buffer containing the data to write. </param>
|
||||
/// <param name="bufferSize">Size of the buffer referenced by <b>buffer</b>.</param>
|
||||
/// <param name="flags">Flag associated with this data.</param>
|
||||
/// <param name="samplesWritten">Pointer to a buffer that receives the number of samples written. This can be set to NULL.</param>
|
||||
/// <param name="bytesWritten">Pointer to a buffer that receives the number of bytes written. This can be set to NULL.</param>
|
||||
///
|
||||
/// <returns>Returns zero if successful or an error otherwise.</returns>
|
||||
///
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVIStreamWrite(IntPtr streamHandler, int start, int samples, IntPtr buffer, int bufferSize, int flags, IntPtr samplesWritten, IntPtr bytesWritten);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the save options for a file and returns them in a buffer.
|
||||
/// </summary>
|
||||
/// <param name="window">Handle to the parent window for the Compression Options dialog box.</param>
|
||||
/// <param name="flags">Flags for displaying the Compression Options dialog box.</param>
|
||||
/// <param name="streams">Number of streams that have their options set by the dialog box.</param>
|
||||
/// <param name="streamInterfaces">Pointer to an array of stream interface pointers.</param>
|
||||
/// <param name="options">Pointer to an array of pointers to AVICOMPRESSOPTIONS structures.</param>
|
||||
/// <returns>Returns TRUE if the user pressed OK, FALSE for CANCEL, or an error otherwise.</returns>
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVISaveOptions(IntPtr window, int flags, int streams, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] streamInterfaces, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] options);
|
||||
|
||||
/// <summary>
|
||||
/// Free the resources allocated by the AVISaveOptions function.
|
||||
/// </summary>
|
||||
/// <param name="streams">Count of the AVICOMPRESSOPTIONS structures referenced in <b>options</b>.</param>
|
||||
/// <param name="options">Pointer to an array of pointers to AVICOMPRESSOPTIONS structures.</param>
|
||||
/// <returns>Returns 0.</returns>
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVISaveOptionsFree(int streams, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] options);
|
||||
|
||||
/// <summary>
|
||||
/// Create a compressed stream from an uncompressed stream and a
|
||||
/// compression filter, and returns the address of a pointer to
|
||||
/// the compressed stream.
|
||||
/// </summary>
|
||||
/// <param name="compressedStream">Pointer to a buffer that receives the compressed stream pointer.</param>
|
||||
/// <param name="sourceStream">Pointer to the stream to be compressed.</param>
|
||||
/// <param name="options">Pointer to a structure that identifies the type of compression to use and the options to apply.</param>
|
||||
/// <param name="clsidHandler">Pointer to a class identifier used to create the stream.</param>
|
||||
/// <returns>Returns 0 if successful or an error otherwise.</returns>
|
||||
[DllImport("avifil32.dll")]
|
||||
public static extern int AVIMakeCompressedStream(out IntPtr compressedStream, IntPtr sourceStream, ref AVICOMPRESSOPTIONS options, IntPtr clsidHandler);
|
||||
|
||||
// --- structures
|
||||
|
||||
/// <summary>
|
||||
/// Structure, which contains information for a single stream .
|
||||
/// </summary>
|
||||
///
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
|
||||
public struct AVISTREAMINFO
|
||||
{
|
||||
/// <summary>
|
||||
/// Four-character code indicating the stream type.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int type;
|
||||
|
||||
/// <summary>
|
||||
/// Four-character code of the compressor handler that will compress this video stream when it is saved.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int handler;
|
||||
|
||||
/// <summary>
|
||||
/// Applicable flags for the stream.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int flags;
|
||||
|
||||
/// <summary>
|
||||
/// Capability flags; currently unused.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int ñapabilities;
|
||||
|
||||
/// <summary>
|
||||
/// Priority of the stream.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I2)]
|
||||
public short priority;
|
||||
|
||||
/// <summary>
|
||||
/// Language of the stream.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I2)]
|
||||
public short language;
|
||||
|
||||
/// <summary>
|
||||
/// Time scale applicable for the stream.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>Dividing <b>rate</b> by <b>scale</b> gives the playback rate in number of samples per second.</remarks>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int scale;
|
||||
|
||||
/// <summary>
|
||||
/// Rate in an integer format.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int rate;
|
||||
|
||||
/// <summary>
|
||||
/// Sample number of the first frame of the AVI file.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int start;
|
||||
|
||||
/// <summary>
|
||||
/// Length of this stream.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>The units are defined by <b>rate</b> and <b>scale</b>.</remarks>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int length;
|
||||
|
||||
/// <summary>
|
||||
/// Audio skew. This member specifies how much to skew the audio data ahead of the video frames in interleaved files.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int initialFrames;
|
||||
|
||||
/// <summary>
|
||||
/// Recommended buffer size, in bytes, for the stream.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int suggestedBufferSize;
|
||||
|
||||
/// <summary>
|
||||
/// Quality indicator of the video data in the stream.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>Quality is represented as a number between 0 and 10,000.</remarks>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int quality;
|
||||
|
||||
/// <summary>
|
||||
/// Size, in bytes, of a single data sample.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int sampleSize;
|
||||
|
||||
/// <summary>
|
||||
/// Dimensions of the video destination rectangle.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.Struct, SizeConst = 16)]
|
||||
public RECT rectFrame;
|
||||
|
||||
/// <summary>
|
||||
/// Number of times the stream has been edited.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int editCount;
|
||||
|
||||
/// <summary>
|
||||
/// Number of times the stream format has changed.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int formatChangeCount;
|
||||
|
||||
/// <summary>
|
||||
/// Description of the stream.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
|
||||
public string name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Structure, which contains information about a stream and how it is compressed and saved.
|
||||
/// </summary>
|
||||
///
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct AVICOMPRESSOPTIONS
|
||||
{
|
||||
/// <summary>
|
||||
/// Four-character code indicating the stream type.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int type;
|
||||
|
||||
/// <summary>
|
||||
/// Four-character code for the compressor handler that will compress this video stream when it is saved.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int handler;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum period between video key frames.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int keyFrameEvery;
|
||||
|
||||
/// <summary>
|
||||
/// Quality value passed to a video compressor.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int quality;
|
||||
|
||||
/// <summary>
|
||||
/// Video compressor data rate.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int bytesPerSecond;
|
||||
|
||||
/// <summary>
|
||||
/// Flags used for compression.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int flags;
|
||||
|
||||
/// <summary>
|
||||
/// Pointer to a structure defining the data format.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int format;
|
||||
|
||||
/// <summary>
|
||||
/// Size, in bytes, of the data referenced by <b>format</b>.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int formatSize;
|
||||
|
||||
/// <summary>
|
||||
/// Video-compressor-specific data; used internally.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int parameters;
|
||||
|
||||
/// <summary>
|
||||
/// Size, in bytes, of the data referenced by <b>parameters</b>.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int parametersSize;
|
||||
|
||||
/// <summary>
|
||||
/// Interleave factor for interspersing stream data with data from the first stream.
|
||||
/// </summary>
|
||||
///
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int interleaveEvery;
|
||||
}
|
||||
|
||||
// --- enumerations
|
||||
|
||||
/// <summary>
|
||||
/// File access modes.
|
||||
/// </summary>
|
||||
///
|
||||
[Flags]
|
||||
public enum OpenFileMode {
|
||||
Read = 0x00000000,
|
||||
Write = 0x00000001,
|
||||
ReadWrite = 0x00000002,
|
||||
ShareCompat = 0x00000000,
|
||||
ShareExclusive = 0x00000010,
|
||||
ShareDenyWrite = 0x00000020,
|
||||
ShareDenyRead = 0x00000030,
|
||||
ShareDenyNone = 0x00000040,
|
||||
Parse = 0x00000100,
|
||||
Delete = 0x00000200,
|
||||
Verify = 0x00000400,
|
||||
Cancel = 0x00000800,
|
||||
Create = 0x00001000,
|
||||
Prompt = 0x00002000,
|
||||
Exist = 0x00004000,
|
||||
Reopen = 0x00008000
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// .NET replacement of mmioFOURCC macros. Converts four characters to code.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="str">Four characters string.</param>
|
||||
///
|
||||
/// <returns>Returns the code created from provided characters.</returns>
|
||||
///
|
||||
public static int mmioFOURCC(string str) {
|
||||
return ( ((int)(byte)(str[0])) |
|
||||
((int)(byte)(str[1]) << 8) |
|
||||
((int)(byte)(str[2]) << 16) |
|
||||
((int)(byte)(str[3]) << 24));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inverse to <see cref="mmioFOURCC"/>. Converts code to fout characters string.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="code">Code to convert.</param>
|
||||
///
|
||||
/// <returns>Returns four characters string.</returns>
|
||||
///
|
||||
public static string decode_mmioFOURCC(int code) {
|
||||
char[] chs = new char[4];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
chs[i] = (char)(byte)((code >> (i << 3)) & 0xFF);
|
||||
if (!char.IsLetterOrDigit(chs[i])) {
|
||||
chs[i] = ' ';
|
||||
}
|
||||
}
|
||||
return new string(chs);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Version of <see cref="AVISaveOptions(IntPtr, int, int, IntPtr[], IntPtr[])"/> for one stream only.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="stream">Stream to configure.</param>
|
||||
/// <param name="options">Stream options.</param>
|
||||
///
|
||||
/// <returns>Returns TRUE if the user pressed OK, FALSE for CANCEL, or an error otherwise.</returns>
|
||||
///
|
||||
public static int AVISaveOptions(IntPtr stream, ref AVICOMPRESSOPTIONS options) {
|
||||
IntPtr[] streams = new IntPtr[1];
|
||||
IntPtr[] infPtrs = new IntPtr[1];
|
||||
IntPtr mem;
|
||||
int ret;
|
||||
|
||||
// alloc unmanaged memory
|
||||
mem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(AVICOMPRESSOPTIONS)));
|
||||
|
||||
// copy from managed structure to unmanaged memory
|
||||
Marshal.StructureToPtr(options, mem, false);
|
||||
|
||||
streams[0] = stream;
|
||||
infPtrs[0] = mem;
|
||||
|
||||
// show dialog with a list of available compresors and configuration
|
||||
ret = AVISaveOptions(IntPtr.Zero, 0, 1, streams, infPtrs);
|
||||
|
||||
// copy from unmanaged memory to managed structure
|
||||
options = (AVICOMPRESSOPTIONS)Marshal.PtrToStructure(mem, typeof(AVICOMPRESSOPTIONS));
|
||||
|
||||
// free AVI compression options
|
||||
AVISaveOptionsFree(1, infPtrs);
|
||||
|
||||
// clear it, because the information already freed by AVISaveOptionsFree
|
||||
options.format = 0;
|
||||
options.parameters = 0;
|
||||
|
||||
// free unmanaged memory
|
||||
Marshal.FreeHGlobal(mem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
725
Greenshot/Helpers/CaptureHelper.cs
Normal file
725
Greenshot/Helpers/CaptureHelper.cs
Normal file
|
@ -0,0 +1,725 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Printing;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Greenshot.Configuration;
|
||||
using Greenshot.Drawing;
|
||||
using Greenshot.Helpers;
|
||||
using Greenshot.Forms;
|
||||
using Greenshot.Plugin;
|
||||
using GreenshotPlugin.UnmanagedHelpers;
|
||||
using GreenshotPlugin.Core;
|
||||
using IniFile;
|
||||
|
||||
namespace Greenshot.Helpers {
|
||||
/// <summary>
|
||||
/// CaptureHelper contains all the capture logic
|
||||
/// </summary>
|
||||
public class CaptureHelper {
|
||||
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(CaptureHelper));
|
||||
private static CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private static ScreenCaptureHelper screenCapture = null;
|
||||
private List<WindowDetails> windows = new List<WindowDetails>();
|
||||
private WindowDetails selectedCaptureWindow = null;
|
||||
private Rectangle captureRect = Rectangle.Empty;
|
||||
private bool captureMouseCursor = false;
|
||||
private ICapture capture = null;
|
||||
private ILanguage lang = Language.GetInstance();
|
||||
private CaptureMode captureMode;
|
||||
|
||||
public static void CaptureClipboard() {
|
||||
new CaptureHelper(CaptureMode.Clipboard).MakeCapture();
|
||||
}
|
||||
public static void CaptureRegion(bool captureMouse) {
|
||||
new CaptureHelper(CaptureMode.Region, captureMouse).MakeCapture();
|
||||
}
|
||||
public static void CaptureRegion(bool captureMouse, IDestination destination) {
|
||||
CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Region, captureMouse, destination);
|
||||
captureHelper.MakeCapture();
|
||||
}
|
||||
public static void CaptureFullscreen(bool captureMouse) {
|
||||
new CaptureHelper(CaptureMode.FullScreen, captureMouse).MakeCapture();
|
||||
}
|
||||
public static void CaptureLastRegion(bool captureMouse) {
|
||||
new CaptureHelper(CaptureMode.LastRegion, captureMouse).MakeCapture();
|
||||
}
|
||||
public static void CaptureIE(bool captureMouse) {
|
||||
new CaptureHelper(CaptureMode.IE, captureMouse).MakeCapture();
|
||||
}
|
||||
public static void CaptureWindow(bool captureMouse) {
|
||||
new CaptureHelper(CaptureMode.ActiveWindow, captureMouse).MakeCapture();
|
||||
}
|
||||
public static void CaptureWindow(WindowDetails windowToCapture) {
|
||||
CaptureHelper captureHelper = new CaptureHelper(CaptureMode.ActiveWindow);
|
||||
captureHelper.SelectedCaptureWindow = windowToCapture;
|
||||
captureHelper.MakeCapture();
|
||||
}
|
||||
public static void CaptureWindowInteractive(bool captureMouse) {
|
||||
new CaptureHelper(CaptureMode.Window, captureMouse).MakeCapture();
|
||||
}
|
||||
public static void CaptureFile(string filename) {
|
||||
new CaptureHelper(CaptureMode.File).MakeCapture(filename);
|
||||
}
|
||||
|
||||
public static void ImportCapture(ICapture captureToImport) {
|
||||
CaptureHelper captureHelper = new CaptureHelper(CaptureMode.File);
|
||||
captureHelper.capture = captureToImport;
|
||||
captureHelper.HandleCapture();
|
||||
}
|
||||
|
||||
public CaptureHelper(CaptureMode captureMode) {
|
||||
this.captureMode = captureMode;
|
||||
capture = new Capture();
|
||||
}
|
||||
|
||||
public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor) : this(captureMode) {
|
||||
this.captureMouseCursor = captureMouseCursor;
|
||||
}
|
||||
|
||||
public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor, IDestination destination) : this(captureMode, captureMouseCursor) {
|
||||
capture.CaptureDetails.AddDestination(destination);
|
||||
}
|
||||
|
||||
public WindowDetails SelectedCaptureWindow {
|
||||
get {
|
||||
return selectedCaptureWindow;
|
||||
}
|
||||
set {
|
||||
selectedCaptureWindow = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void DoCaptureFeedback() {
|
||||
if(conf.PlayCameraSound) {
|
||||
SoundHelper.Play();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make Capture with file name
|
||||
/// </summary>
|
||||
/// <param name="filename">filename</param>
|
||||
private void MakeCapture(string filename) {
|
||||
capture.CaptureDetails.Filename = filename;
|
||||
MakeCapture();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make Capture with specified destinations
|
||||
/// </summary>
|
||||
private void MakeCapture() {
|
||||
|
||||
// Experimental code
|
||||
if (screenCapture != null) {
|
||||
screenCapture.Stop();
|
||||
screenCapture = null;
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.Debug(String.Format("Capturing with mode {0} and using Cursor {1})", captureMode, captureMouseCursor));
|
||||
capture.CaptureDetails.CaptureMode = captureMode;
|
||||
|
||||
// Add destinations if no-one passed a handler
|
||||
if (capture.CaptureDetails.CaptureDestinations == null || capture.CaptureDetails.CaptureDestinations.Count == 0) {
|
||||
AddConfiguredDestination();
|
||||
}
|
||||
PrepareForCaptureWithFeedback();
|
||||
|
||||
// Workaround for proble with DPI retrieval, the FromHwnd activates the window...
|
||||
WindowDetails previouslyActiveWindow = WindowDetails.GetActiveWindow();
|
||||
// Workaround for changed DPI settings in Windows 7
|
||||
using (Graphics graphics = Graphics.FromHwnd(MainForm.instance.Handle)) {
|
||||
capture.CaptureDetails.DpiX = graphics.DpiX;
|
||||
capture.CaptureDetails.DpiY = graphics.DpiY;
|
||||
}
|
||||
if (previouslyActiveWindow != null) {
|
||||
// Set previouslyActiveWindow as foreground window
|
||||
previouslyActiveWindow.ToForeground();
|
||||
}
|
||||
|
||||
// Delay for the Context menu
|
||||
if (conf.CaptureDelay > 0) {
|
||||
System.Threading.Thread.Sleep(conf.CaptureDelay);
|
||||
} else {
|
||||
conf.CaptureDelay = 0;
|
||||
}
|
||||
|
||||
// Allways capture Mousecursor, only show when needed
|
||||
capture = WindowCapture.CaptureCursor(capture);
|
||||
capture.CursorVisible = false;
|
||||
// Check if needed
|
||||
if (captureMouseCursor && captureMode != CaptureMode.Clipboard && captureMode != CaptureMode.File) {
|
||||
capture.CursorVisible = conf.CaptureMousepointer;
|
||||
}
|
||||
|
||||
switch(captureMode) {
|
||||
case CaptureMode.Window:
|
||||
capture = WindowCapture.CaptureScreen(capture);
|
||||
capture.CaptureDetails.AddMetaData("source", "Screen");
|
||||
CaptureWithFeedback();
|
||||
break;
|
||||
case CaptureMode.ActiveWindow:
|
||||
if (CaptureActiveWindow()) {
|
||||
// Capture worked, offset mouse according to screen bounds and capture location
|
||||
capture.MoveMouseLocation(capture.ScreenBounds.Location.X-capture.Location.X, capture.ScreenBounds.Location.Y-capture.Location.Y);
|
||||
capture.MoveElements(capture.ScreenBounds.Location.X-capture.Location.X, capture.ScreenBounds.Location.Y-capture.Location.Y);
|
||||
capture.CaptureDetails.AddMetaData("source", "Window");
|
||||
} else {
|
||||
captureMode = CaptureMode.FullScreen;
|
||||
capture = WindowCapture.CaptureScreen(capture);
|
||||
capture.CaptureDetails.AddMetaData("source", "Screen");
|
||||
capture.CaptureDetails.Title = "Screen";
|
||||
}
|
||||
HandleCapture();
|
||||
break;
|
||||
case CaptureMode.IE:
|
||||
if (IECaptureHelper.CaptureIE(capture) != null) {
|
||||
capture.CaptureDetails.AddMetaData("source", "Internet Explorer");
|
||||
HandleCapture();
|
||||
}
|
||||
break;
|
||||
case CaptureMode.FullScreen:
|
||||
capture = WindowCapture.CaptureScreen(capture);
|
||||
HandleCapture();
|
||||
break;
|
||||
case CaptureMode.Clipboard:
|
||||
Image clipboardImage = null;
|
||||
string text = "Clipboard";
|
||||
if (ClipboardHelper.ContainsImage()) {
|
||||
clipboardImage = ClipboardHelper.GetImage();
|
||||
}
|
||||
if (clipboardImage != null) {
|
||||
if (capture != null) {
|
||||
capture.Image = clipboardImage;
|
||||
} else {
|
||||
capture = new Capture(clipboardImage);
|
||||
}
|
||||
string title = ClipboardHelper.GetText();
|
||||
if (title == null || title.Trim().Length == 0) {
|
||||
title = "Clipboard";
|
||||
}
|
||||
capture.CaptureDetails.Title = title;
|
||||
capture.CaptureDetails.AddMetaData("source", "Clipboard");
|
||||
// Force Editor, keep picker
|
||||
if (capture.CaptureDetails.HasDestination(Destinations.PickerDestination.DESIGNATION)) {
|
||||
capture.CaptureDetails.ClearDestinations();
|
||||
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.EditorDestination.DESIGNATION));
|
||||
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.PickerDestination.DESIGNATION));
|
||||
} else {
|
||||
capture.CaptureDetails.ClearDestinations();
|
||||
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.EditorDestination.DESIGNATION));
|
||||
}
|
||||
HandleCapture();
|
||||
} else {
|
||||
MessageBox.Show("Couldn't create bitmap from : " + text);
|
||||
}
|
||||
break;
|
||||
case CaptureMode.File:
|
||||
Bitmap fileBitmap = null;
|
||||
string filename = capture.CaptureDetails.Filename;
|
||||
if (!string.IsNullOrEmpty(filename)) {
|
||||
try {
|
||||
fileBitmap = ImageHelper.LoadBitmap(filename);
|
||||
} catch (Exception e) {
|
||||
LOG.Error(e.Message, e);
|
||||
MessageBox.Show(lang.GetFormattedString(LangKey.error_openfile, filename));
|
||||
}
|
||||
}
|
||||
if (fileBitmap != null) {
|
||||
capture.CaptureDetails.Title = Path.GetFileNameWithoutExtension(filename);
|
||||
capture.CaptureDetails.AddMetaData("file", filename);
|
||||
capture.CaptureDetails.AddMetaData("source", "file");
|
||||
if (capture != null) {
|
||||
capture.Image = fileBitmap;
|
||||
} else {
|
||||
capture = new Capture(fileBitmap);
|
||||
}
|
||||
// Force Editor, keep picker, this is currently the only usefull destination
|
||||
if (capture.CaptureDetails.HasDestination("Picker")) {
|
||||
capture.CaptureDetails.ClearDestinations();
|
||||
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.EditorDestination.DESIGNATION));
|
||||
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.PickerDestination.DESIGNATION));
|
||||
} else {
|
||||
capture.CaptureDetails.ClearDestinations();
|
||||
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.EditorDestination.DESIGNATION));
|
||||
}
|
||||
HandleCapture();
|
||||
}
|
||||
break;
|
||||
case CaptureMode.LastRegion:
|
||||
if (!RuntimeConfig.LastCapturedRegion.IsEmpty) {
|
||||
capture = WindowCapture.CaptureScreen(capture);
|
||||
capture.Crop(RuntimeConfig.LastCapturedRegion);
|
||||
capture.CaptureDetails.AddMetaData("source", "screen");
|
||||
HandleCapture();
|
||||
}
|
||||
break;
|
||||
case CaptureMode.Region:
|
||||
capture = WindowCapture.CaptureScreen(capture);
|
||||
capture.CaptureDetails.AddMetaData("source", "screen");
|
||||
CaptureWithFeedback();
|
||||
break;
|
||||
case CaptureMode.Video:
|
||||
capture = WindowCapture.CaptureScreen(capture);
|
||||
// Set the capturemode to be window
|
||||
captureMode = CaptureMode.Window;
|
||||
capture.CaptureDetails.AddMetaData("source", "Video");
|
||||
CaptureWithFeedback();
|
||||
break;
|
||||
default:
|
||||
LOG.Warn("Unknown capture mode: " + captureMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pre-Initialization for CaptureWithFeedback, this will get all the windows before we change anything
|
||||
/// </summary>
|
||||
private void PrepareForCaptureWithFeedback() {
|
||||
windows = new List<WindowDetails>();
|
||||
// Start Enumeration of "active" windows
|
||||
foreach (WindowDetails window in WindowDetails.GetAllWindows()) {
|
||||
// Window should be visible and not ourselves
|
||||
if (!window.Visible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip empty
|
||||
Rectangle windowRectangle = window.WindowRectangle;
|
||||
Size windowSize = windowRectangle.Size;
|
||||
if (windowSize.Width == 0 || windowSize.Height == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure the details are retrieved once
|
||||
window.FreezeDetails();
|
||||
|
||||
// Force children retrieval, sometimes windows close on losing focus and this is solved by caching
|
||||
int goLevelDeep = 3;
|
||||
if (conf.WindowCaptureAllChildLocations) {
|
||||
goLevelDeep = 20;
|
||||
}
|
||||
window.GetChildren(goLevelDeep);
|
||||
windows.Add(window);
|
||||
|
||||
// Get window rectangle as capture Element
|
||||
CaptureElement windowCaptureElement = new CaptureElement(windowRectangle);
|
||||
capture.Elements.Add(windowCaptureElement);
|
||||
|
||||
if (!window.HasParent) {
|
||||
// Get window client rectangle as capture Element, place all the other "children" in there
|
||||
Rectangle clientRectangle = window.ClientRectangle;
|
||||
CaptureElement windowClientCaptureElement = new CaptureElement(clientRectangle);
|
||||
windowCaptureElement.Children.Add(windowClientCaptureElement);
|
||||
AddCaptureElementsForWindow(windowClientCaptureElement, window, goLevelDeep);
|
||||
} else {
|
||||
AddCaptureElementsForWindow(windowCaptureElement, window, goLevelDeep);
|
||||
}
|
||||
|
||||
}
|
||||
windows = WindowDetails.SortByZOrder(IntPtr.Zero, windows);
|
||||
}
|
||||
|
||||
private void AddCaptureElementsForWindow(ICaptureElement parentElement, WindowDetails parentWindow, int level) {
|
||||
foreach(WindowDetails childWindow in parentWindow.Children) {
|
||||
// Make sure the details are retrieved once
|
||||
childWindow.FreezeDetails();
|
||||
Rectangle childRectangle = childWindow.WindowRectangle;
|
||||
Size s1 = childRectangle.Size;
|
||||
childRectangle.Intersect(parentElement.Bounds);
|
||||
if (childRectangle.Width > 0 && childRectangle.Height > 0) {
|
||||
CaptureElement childCaptureElement = new CaptureElement(childRectangle);
|
||||
parentElement.Children.Add(childCaptureElement);
|
||||
if (level > 0) {
|
||||
AddCaptureElementsForWindow(childCaptureElement, childWindow, level -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddConfiguredDestination() {
|
||||
foreach(string destinationDesignation in conf.OutputDestinations) {
|
||||
IDestination destination = DestinationHelper.GetDestination(destinationDesignation);
|
||||
if (destination != null) {
|
||||
capture.CaptureDetails.AddDestination(destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCapture() {
|
||||
// Flag to see if the image was "exported" so the FileEditor doesn't
|
||||
// ask to save the file as long as nothing is done.
|
||||
bool outputMade = false;
|
||||
|
||||
// Make sure the user sees that the capture is made
|
||||
if (capture.CaptureDetails.CaptureMode != CaptureMode.File && capture.CaptureDetails.CaptureMode != CaptureMode.Clipboard) {
|
||||
DoCaptureFeedback();
|
||||
} else {
|
||||
// If File || Clipboard
|
||||
// Maybe not "made" but the original is still there... somehow
|
||||
outputMade = true;
|
||||
}
|
||||
|
||||
LOG.Debug("A capture of: " + capture.CaptureDetails.Title);
|
||||
|
||||
// check if someone has passed a destination
|
||||
if (capture.CaptureDetails.CaptureDestinations == null || capture.CaptureDetails.CaptureDestinations.Count == 0) {
|
||||
AddConfiguredDestination();
|
||||
}
|
||||
|
||||
// Create Surface with capture, this way elements can be added automatically (like the mouse cursor)
|
||||
Surface surface = new Surface(capture);
|
||||
|
||||
// Register notify events if this is wanted
|
||||
if (conf.ShowTrayNotification) {
|
||||
surface.SurfaceMessage += delegate(object source, SurfaceMessageEventArgs eventArgs) {
|
||||
switch (eventArgs.MessageType) {
|
||||
case SurfaceMessageTyp.Error:
|
||||
MainForm.instance.notifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Error);
|
||||
break;
|
||||
case SurfaceMessageTyp.Info:
|
||||
MainForm.instance.notifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Info);
|
||||
break;
|
||||
case SurfaceMessageTyp.FileSaved:
|
||||
EventHandler balloonTipClickedHandler = null;
|
||||
EventHandler balloonTipClosedHandler = null;
|
||||
balloonTipClosedHandler = delegate(object sender, EventArgs e) {
|
||||
LOG.DebugFormat("Deregistering the BalloonTipClosed");
|
||||
MainForm.instance.notifyIcon.BalloonTipClicked -= balloonTipClickedHandler;
|
||||
MainForm.instance.notifyIcon.BalloonTipClosed -= balloonTipClosedHandler;
|
||||
};
|
||||
|
||||
balloonTipClickedHandler = delegate(object sender, EventArgs e) {
|
||||
if (surface.LastSaveFullPath != null) {
|
||||
ProcessStartInfo psi = new ProcessStartInfo("explorer");
|
||||
psi.Arguments = Path.GetDirectoryName(eventArgs.Surface.LastSaveFullPath);
|
||||
psi.UseShellExecute = false;
|
||||
Process p = new Process();
|
||||
p.StartInfo = psi;
|
||||
p.Start();
|
||||
}
|
||||
LOG.DebugFormat("Deregistering the BalloonTipClicked");
|
||||
MainForm.instance.notifyIcon.BalloonTipClicked -= balloonTipClickedHandler;
|
||||
MainForm.instance.notifyIcon.BalloonTipClosed -= balloonTipClosedHandler;
|
||||
};
|
||||
MainForm.instance.notifyIcon.BalloonTipClicked += balloonTipClickedHandler;
|
||||
MainForm.instance.notifyIcon.BalloonTipClosed += balloonTipClosedHandler;
|
||||
MainForm.instance.notifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Info);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
// Let the processors do their job
|
||||
foreach(IProcessor processor in ProcessorHelper.GetAllProcessors()) {
|
||||
if (processor.isActive) {
|
||||
LOG.InfoFormat("Calling processor {0}", processor.Description);
|
||||
processor.ProcessCapture(surface, capture.CaptureDetails);
|
||||
}
|
||||
}
|
||||
|
||||
// As the surfaces copies the reference to the image, make sure the image is not being disposed (a trick to save memory)
|
||||
capture.Image = null;
|
||||
|
||||
// Get CaptureDetails as we need it even after the capture is disposed
|
||||
ICaptureDetails captureDetails = capture.CaptureDetails;
|
||||
bool canDisposeSurface = true;
|
||||
|
||||
if (captureDetails.HasDestination(Destinations.PickerDestination.DESIGNATION)) {
|
||||
DestinationHelper.ExportCapture(Destinations.PickerDestination.DESIGNATION, surface, captureDetails);
|
||||
captureDetails.CaptureDestinations.Clear();
|
||||
canDisposeSurface = false;
|
||||
}
|
||||
|
||||
// Disable capturing
|
||||
captureMode = CaptureMode.None;
|
||||
// Dispose the capture, we don't need it anymore (the surface copied all information and we got the title (if any)).
|
||||
capture.Dispose();
|
||||
capture = null;
|
||||
|
||||
int destinationCount = captureDetails.CaptureDestinations.Count;
|
||||
if (destinationCount > 0) {
|
||||
// Flag to detect if we need to create a temp file for the email
|
||||
// or use the file that was written
|
||||
foreach(IDestination destination in captureDetails.CaptureDestinations) {
|
||||
if ("Picker".Equals(destination.Designation)) {
|
||||
continue;
|
||||
}
|
||||
LOG.InfoFormat("Calling destination {0}", destination.Description);
|
||||
|
||||
bool destinationOk = destination.ExportCapture(surface, captureDetails);
|
||||
if (Destinations.EditorDestination.DESIGNATION.Equals(destination.Designation) && destinationOk) {
|
||||
canDisposeSurface = false;
|
||||
}
|
||||
outputMade = outputMade || destinationOk;
|
||||
}
|
||||
}
|
||||
if (canDisposeSurface) {
|
||||
surface.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private bool CaptureActiveWindow() {
|
||||
bool presupplied = false;
|
||||
LOG.Debug("CaptureActiveWindow");
|
||||
if (selectedCaptureWindow != null) {
|
||||
LOG.Debug("Using supplied window");
|
||||
presupplied = true;
|
||||
} else {
|
||||
selectedCaptureWindow = WindowDetails.GetActiveWindow();
|
||||
if (selectedCaptureWindow != null) {
|
||||
LOG.DebugFormat("Capturing window: {0} with {1}", selectedCaptureWindow.Text, selectedCaptureWindow.WindowRectangle);
|
||||
}
|
||||
}
|
||||
if (selectedCaptureWindow == null || (!presupplied && selectedCaptureWindow.Iconic)) {
|
||||
LOG.Warn("No window to capture!");
|
||||
// Nothing to capture, code up in the stack will capture the full screen
|
||||
return false;
|
||||
}
|
||||
if (selectedCaptureWindow != null && selectedCaptureWindow.Iconic) {
|
||||
// Restore the window making sure it's visible!
|
||||
// This is done mainly for a screen capture, but some applications like Excel and TOAD have weird behaviour!
|
||||
selectedCaptureWindow.Restore();
|
||||
}
|
||||
selectedCaptureWindow.ToForeground();
|
||||
selectedCaptureWindow = SelectCaptureWindow(selectedCaptureWindow);
|
||||
if (selectedCaptureWindow == null) {
|
||||
LOG.Warn("No window to capture, after SelectCaptureWindow!");
|
||||
// Nothing to capture, code up in the stack will capture the full screen
|
||||
return false;
|
||||
}
|
||||
// Fix for Bug #3430560
|
||||
RuntimeConfig.LastCapturedRegion = selectedCaptureWindow.WindowRectangle;
|
||||
bool returnValue = CaptureWindow(selectedCaptureWindow, capture, conf.WindowCaptureMode) != null;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select the window to capture, this has logic which takes care of certain special applications
|
||||
/// like TOAD or Excel
|
||||
/// </summary>
|
||||
/// <param name="windowToCapture">WindowDetails with the target Window</param>
|
||||
/// <returns>WindowDetails with the target Window OR a replacement</returns>
|
||||
public static WindowDetails SelectCaptureWindow(WindowDetails windowToCapture) {
|
||||
Rectangle windowRectangle = windowToCapture.WindowRectangle;
|
||||
if (windowToCapture.Iconic || windowRectangle.Width == 0 || windowRectangle.Height == 0) {
|
||||
LOG.WarnFormat("Window {0} has nothing to capture, using workaround to find other window of same process.", windowToCapture.Text);
|
||||
// Trying workaround, the size 0 arrises with e.g. Toad.exe, has a different Window when minimized
|
||||
WindowDetails linkedWindow = WindowDetails.GetLinkedWindow(windowToCapture);
|
||||
if (linkedWindow != null) {
|
||||
windowRectangle = linkedWindow.WindowRectangle;
|
||||
windowToCapture = linkedWindow;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return windowToCapture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if Process uses PresentationFramework.dll -> meaning it uses WPF
|
||||
/// </summary>
|
||||
/// <param name="process"></param>
|
||||
/// <returns>true if the process uses WPF</returns>
|
||||
private static bool isWPF(Process process) {
|
||||
if (process != null) {
|
||||
foreach(ProcessModule module in process.Modules) {
|
||||
if (module.ModuleName.StartsWith("PresentationFramework")) {
|
||||
LOG.InfoFormat("Found that Process {0} uses {1}, assuming it's using WPF", process.ProcessName, module.FileName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Capture the supplied Window
|
||||
/// </summary>
|
||||
/// <param name="windowToCapture">Window to capture</param>
|
||||
/// <param name="captureForWindow">The capture to store the details</param>
|
||||
/// <param name="windowCaptureMode">What WindowCaptureMode to use</param>
|
||||
/// <returns></returns>
|
||||
public static ICapture CaptureWindow(WindowDetails windowToCapture, ICapture captureForWindow, WindowCaptureMode windowCaptureMode) {
|
||||
if (captureForWindow == null) {
|
||||
captureForWindow = new Capture();
|
||||
}
|
||||
Rectangle windowRectangle = windowToCapture.WindowRectangle;
|
||||
if (windowToCapture.Iconic) {
|
||||
// Restore the window making sure it's visible!
|
||||
windowToCapture.Restore();
|
||||
}
|
||||
|
||||
// When Vista & DWM (Aero) enabled
|
||||
bool dwmEnabled = DWM.isDWMEnabled();
|
||||
// get process name to be able to exclude certain processes from certain capture modes
|
||||
Process process = windowToCapture.Process;
|
||||
bool isAutoMode = windowCaptureMode == WindowCaptureMode.Auto;
|
||||
// For WindowCaptureMode.Auto we check:
|
||||
// 1) Is window IE, use IE Capture
|
||||
// 2) Is Windows >= Vista & DWM enabled: use DWM
|
||||
// 3) Otherwise use GDI (Screen might be also okay but might lose content)
|
||||
if (isAutoMode) {
|
||||
if (conf.IECapture && windowToCapture.ClassName == "IEFrame") {
|
||||
try {
|
||||
ICapture ieCapture = IECaptureHelper.CaptureIE(captureForWindow);
|
||||
if (ieCapture != null) {
|
||||
return ieCapture;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.WarnFormat("Problem capturing IE, skipping to normal capture. Exception message was: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// Take default screen
|
||||
windowCaptureMode = WindowCaptureMode.Screen;
|
||||
|
||||
// Change to GDI, if allowed
|
||||
if (conf.isGDIAllowed(process)) {
|
||||
if (!dwmEnabled && isWPF(process)) {
|
||||
// do not use GDI, as DWM is not enabled and the application uses PresentationFramework.dll -> isWPF
|
||||
LOG.InfoFormat("Not using GDI for windows of process {0}, as the process uses WPF", process.ProcessName);
|
||||
} else {
|
||||
windowCaptureMode = WindowCaptureMode.GDI;
|
||||
}
|
||||
}
|
||||
|
||||
// Change to DWM, if enabled and allowed
|
||||
if (dwmEnabled) {
|
||||
if (conf.isDWMAllowed(process)) {
|
||||
windowCaptureMode = WindowCaptureMode.Aero;
|
||||
}
|
||||
}
|
||||
} else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) {
|
||||
if (!dwmEnabled || !conf.isDWMAllowed(process)) {
|
||||
// Take default screen
|
||||
windowCaptureMode = WindowCaptureMode.Screen;
|
||||
// Change to GDI, if allowed
|
||||
if (conf.isGDIAllowed(process)) {
|
||||
windowCaptureMode = WindowCaptureMode.GDI;
|
||||
}
|
||||
}
|
||||
} else if (windowCaptureMode == WindowCaptureMode.GDI && !conf.isGDIAllowed(process)) {
|
||||
// GDI not allowed, take screen
|
||||
windowCaptureMode = WindowCaptureMode.Screen;
|
||||
}
|
||||
|
||||
LOG.InfoFormat("Capturing window with mode {0}", windowCaptureMode);
|
||||
bool captureTaken = false;
|
||||
// Try to capture
|
||||
while (!captureTaken) {
|
||||
if (windowCaptureMode == WindowCaptureMode.GDI) {
|
||||
ICapture tmpCapture = null;
|
||||
if (conf.isGDIAllowed(process)) {
|
||||
tmpCapture = windowToCapture.CaptureWindow(captureForWindow);
|
||||
}
|
||||
if (tmpCapture != null) {
|
||||
captureForWindow = tmpCapture;
|
||||
captureTaken = true;
|
||||
} else {
|
||||
// A problem, try Screen
|
||||
windowCaptureMode = WindowCaptureMode.Screen;
|
||||
}
|
||||
} else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) {
|
||||
ICapture tmpCapture = null;
|
||||
if (conf.isDWMAllowed(process)) {
|
||||
tmpCapture = windowToCapture.CaptureDWMWindow(captureForWindow, windowCaptureMode, isAutoMode);
|
||||
}
|
||||
if (tmpCapture != null) {
|
||||
captureForWindow = tmpCapture;
|
||||
captureTaken = true;
|
||||
} else {
|
||||
// A problem, try GDI
|
||||
windowCaptureMode = WindowCaptureMode.GDI;
|
||||
}
|
||||
} else {
|
||||
// Screen capture
|
||||
windowRectangle.Intersect(captureForWindow.ScreenBounds);
|
||||
try {
|
||||
captureForWindow = WindowCapture.CaptureRectangle(captureForWindow, windowRectangle);
|
||||
captureTaken = true;
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Problem capturing", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (captureForWindow != null && windowToCapture != null) {
|
||||
captureForWindow.CaptureDetails.Title = windowToCapture.Text;
|
||||
((Bitmap)captureForWindow.Image).SetResolution(captureForWindow.CaptureDetails.DpiX, captureForWindow.CaptureDetails.DpiY);
|
||||
}
|
||||
|
||||
return captureForWindow;
|
||||
}
|
||||
|
||||
#region capture with feedback
|
||||
private void CaptureWithFeedback() {
|
||||
using (CaptureForm captureForm = new CaptureForm(capture, windows)) {
|
||||
DialogResult result = captureForm.ShowDialog();
|
||||
if (result == DialogResult.OK) {
|
||||
selectedCaptureWindow = captureForm.SelectedCaptureWindow;
|
||||
captureRect = captureForm.CaptureRectangle;
|
||||
// Get title
|
||||
if (selectedCaptureWindow != null) {
|
||||
capture.CaptureDetails.Title = selectedCaptureWindow.Text;
|
||||
}
|
||||
|
||||
// Experimental code
|
||||
if (capture.CaptureDetails.CaptureMode == CaptureMode.Video) {
|
||||
if (captureForm.UsedCaptureMode == CaptureMode.Window) {
|
||||
screenCapture = new ScreenCaptureHelper(selectedCaptureWindow);
|
||||
} else if (captureForm.UsedCaptureMode == CaptureMode.Region) {
|
||||
screenCapture = new ScreenCaptureHelper(captureRect);
|
||||
}
|
||||
if (screenCapture != null) {
|
||||
screenCapture.RecordMouse = capture.CursorVisible;
|
||||
if (screenCapture.Start(15)) {
|
||||
return;
|
||||
}
|
||||
// User clicked cancel or a problem occured
|
||||
screenCapture.Stop();
|
||||
screenCapture = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (captureRect.Height > 0 && captureRect.Width > 0) {
|
||||
// Take the captureRect, this already is specified as bitmap coordinates
|
||||
capture.Crop(captureRect);
|
||||
// save for re-capturing later and show recapture context menu option
|
||||
RuntimeConfig.LastCapturedRegion = captureRect;
|
||||
HandleCapture();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
124
Greenshot/Helpers/DestinationHelper.cs
Normal file
124
Greenshot/Helpers/DestinationHelper.cs
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Greenshot.Plugin;
|
||||
using GreenshotPlugin.Core;
|
||||
|
||||
namespace Greenshot.Helpers {
|
||||
/// <summary>
|
||||
/// Description of DestinationHelper.
|
||||
/// </summary>
|
||||
public static class DestinationHelper {
|
||||
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(DestinationHelper));
|
||||
private static Dictionary<string, IDestination> RegisteredDestinations = new Dictionary<string, IDestination>();
|
||||
|
||||
/// Initialize the destinations
|
||||
static DestinationHelper() {
|
||||
foreach(Type destinationType in InterfaceUtils.GetSubclassesOf(typeof(IDestination),true)) {
|
||||
// Only take our own
|
||||
if (!"Greenshot.Destinations".Equals(destinationType.Namespace)) {
|
||||
continue;
|
||||
}
|
||||
if (!destinationType.IsAbstract) {
|
||||
IDestination destination;
|
||||
try {
|
||||
destination = (IDestination)Activator.CreateInstance(destinationType);
|
||||
} catch (Exception e) {
|
||||
LOG.ErrorFormat("Can't create instance of {0}", destinationType);
|
||||
LOG.Error(e);
|
||||
continue;
|
||||
}
|
||||
if (destination.isActive) {
|
||||
LOG.DebugFormat("Found destination {0} with designation {1}", destinationType.Name, destination.Designation);
|
||||
RegisterDestination(destination);
|
||||
} else {
|
||||
LOG.DebugFormat("Ignoring destination {0} with designation {1}", destinationType.Name, destination.Designation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register your destination here, if it doesn't come from a plugin and needs to be available
|
||||
/// </summary>
|
||||
/// <param name="destination"></param>
|
||||
public static void RegisterDestination(IDestination destination) {
|
||||
// don't test the key, an exception should happen wenn it's not unique
|
||||
RegisteredDestinations.Add(destination.Designation, destination);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of all destinations, registered or supplied by a plugin
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<IDestination> GetAllDestinations() {
|
||||
List<IDestination> destinations = new List<IDestination>();
|
||||
destinations.AddRange(RegisteredDestinations.Values);
|
||||
foreach(IGreenshotPlugin plugin in PluginHelper.instance.Plugins.Values) {
|
||||
destinations.AddRange(plugin.Destinations());
|
||||
}
|
||||
destinations.Sort();
|
||||
return destinations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a destination by a designation
|
||||
/// </summary>
|
||||
/// <param name="designation">Designation of the destination</param>
|
||||
/// <returns>IDestination or null</returns>
|
||||
public static IDestination GetDestination(string designation) {
|
||||
if (designation == null) {
|
||||
return null;
|
||||
}
|
||||
if (RegisteredDestinations.ContainsKey(designation)) {
|
||||
return RegisteredDestinations[designation];
|
||||
}
|
||||
foreach(IGreenshotPlugin plugin in PluginHelper.instance.Plugins.Values) {
|
||||
foreach(IDestination destination in plugin.Destinations()) {
|
||||
if (designation.Equals(destination.Designation)) {
|
||||
return destination;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A simple helper method which will call ExportCapture for the destination with the specified designation
|
||||
/// </summary>
|
||||
/// <param name="designation"></param>
|
||||
/// <param name="surface"></param>
|
||||
/// <param name="captureDetails"></param>
|
||||
public static void ExportCapture(string designation, ISurface surface, ICaptureDetails captureDetails) {
|
||||
if (RegisteredDestinations.ContainsKey(designation)) {
|
||||
IDestination destination = RegisteredDestinations[designation];
|
||||
if (destination.isActive) {
|
||||
if (destination.ExportCapture(surface, captureDetails)) {
|
||||
// Export worked, set the modified flag
|
||||
surface.Modified = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
63
Greenshot/Helpers/GeometryHelper.cs
Normal file
63
Greenshot/Helpers/GeometryHelper.cs
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace Greenshot.Helpers {
|
||||
/// <summary>
|
||||
/// Description of GeometryHelper.
|
||||
/// </summary>
|
||||
public static class GeometryHelper {
|
||||
/// <summary>
|
||||
/// Finds the distance between two points on a 2D surface.
|
||||
/// </summary>
|
||||
/// <param name="x1">The point on the x-axis of the first point</param>
|
||||
/// <param name="x2">The point on the x-axis of the second point</param>
|
||||
/// <param name="y1">The point on the y-axis of the first point</param>
|
||||
/// <param name="y2">The point on the y-axis of the second point</param>
|
||||
/// <returns></returns>
|
||||
public static int Distance2D(int x1, int y1, int x2, int y2) {
|
||||
//Our end result
|
||||
int result = 0;
|
||||
//Take x2-x1, then square it
|
||||
double part1 = Math.Pow((x2 - x1), 2);
|
||||
//Take y2-y1, then square it
|
||||
double part2 = Math.Pow((y2 - y1), 2);
|
||||
//Add both of the parts together
|
||||
double underRadical = part1 + part2;
|
||||
//Get the square root of the parts
|
||||
result = (int)Math.Sqrt(underRadical);
|
||||
//Return our result
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the angle of a line defined by two points on a 2D surface.
|
||||
/// </summary>
|
||||
/// <param name="x1">The point on the x-axis of the first point</param>
|
||||
/// <param name="x2">The point on the x-axis of the second point</param>
|
||||
/// <param name="y1">The point on the y-axis of the first point</param>
|
||||
/// <param name="y2">The point on the y-axis of the second point</param>
|
||||
/// <returns></returns>
|
||||
public static double Angle2D(int x1, int y1, int x2, int y2) {
|
||||
return Math.Atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
|
||||
}
|
||||
}
|
||||
}
|
121
Greenshot/Helpers/ProcessorHelper.cs
Normal file
121
Greenshot/Helpers/ProcessorHelper.cs
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Greenshot.Plugin;
|
||||
using GreenshotPlugin.Core;
|
||||
|
||||
namespace Greenshot.Helpers {
|
||||
/// <summary>
|
||||
/// Description of ProcessorHelper.
|
||||
/// </summary>
|
||||
public static class ProcessorHelper {
|
||||
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ProcessorHelper));
|
||||
private static Dictionary<string, IProcessor> RegisteredProcessors = new Dictionary<string, IProcessor>();
|
||||
|
||||
/// Initialize the Processors
|
||||
static ProcessorHelper() {
|
||||
foreach(Type ProcessorType in InterfaceUtils.GetSubclassesOf(typeof(IProcessor),true)) {
|
||||
// Only take our own
|
||||
if (!"Greenshot.Processors".Equals(ProcessorType.Namespace)) {
|
||||
continue;
|
||||
}
|
||||
if (!ProcessorType.IsAbstract) {
|
||||
IProcessor Processor;
|
||||
try {
|
||||
Processor = (IProcessor)Activator.CreateInstance(ProcessorType);
|
||||
} catch (Exception e) {
|
||||
LOG.ErrorFormat("Can't create instance of {0}", ProcessorType);
|
||||
LOG.Error(e);
|
||||
continue;
|
||||
}
|
||||
if (Processor.isActive) {
|
||||
LOG.DebugFormat("Found Processor {0} with designation {1}", ProcessorType.Name, Processor.Designation);
|
||||
RegisterProcessor(Processor);
|
||||
} else {
|
||||
LOG.DebugFormat("Ignoring Processor {0} with designation {1}", ProcessorType.Name, Processor.Designation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register your Processor here, if it doesn't come from a plugin and needs to be available
|
||||
/// </summary>
|
||||
/// <param name="Processor"></param>
|
||||
public static void RegisterProcessor(IProcessor Processor) {
|
||||
// don't test the key, an exception should happen wenn it's not unique
|
||||
RegisteredProcessors.Add(Processor.Designation, Processor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of all Processors, registered or supplied by a plugin
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<IProcessor> GetAllProcessors() {
|
||||
List<IProcessor> Processors = new List<IProcessor>();
|
||||
Processors.AddRange(RegisteredProcessors.Values);
|
||||
foreach(IGreenshotPlugin plugin in PluginHelper.instance.Plugins.Values) {
|
||||
Processors.AddRange(plugin.Processors());
|
||||
}
|
||||
Processors.Sort();
|
||||
return Processors;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a Processor by a designation
|
||||
/// </summary>
|
||||
/// <param name="designation">Designation of the Processor</param>
|
||||
/// <returns>IProcessor or null</returns>
|
||||
public static IProcessor GetProcessor(string designation) {
|
||||
if (designation == null) {
|
||||
return null;
|
||||
}
|
||||
if (RegisteredProcessors.ContainsKey(designation)) {
|
||||
return RegisteredProcessors[designation];
|
||||
}
|
||||
foreach(IGreenshotPlugin plugin in PluginHelper.instance.Plugins.Values) {
|
||||
foreach(IProcessor Processor in plugin.Processors()) {
|
||||
if (designation.Equals(Processor.Designation)) {
|
||||
return Processor;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A simple helper method which will call ProcessCapture for the Processor with the specified designation
|
||||
/// </summary>
|
||||
/// <param name="designation"></param>
|
||||
/// <param name="surface"></param>
|
||||
/// <param name="captureDetails"></param>
|
||||
public static void ProcessCapture(string designation, ISurface surface, ICaptureDetails captureDetails) {
|
||||
if (RegisteredProcessors.ContainsKey(designation)) {
|
||||
IProcessor Processor = RegisteredProcessors[designation];
|
||||
if (Processor.isActive) {
|
||||
Processor.ProcessCapture(surface, captureDetails);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
262
Greenshot/Helpers/ScreenCaptureHelper.cs
Normal file
262
Greenshot/Helpers/ScreenCaptureHelper.cs
Normal file
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Greenshot;
|
||||
using Greenshot.Configuration;
|
||||
using Greenshot.Plugin;
|
||||
using GreenshotPlugin.UnmanagedHelpers;
|
||||
using GreenshotPlugin.Core;
|
||||
using IniFile;
|
||||
|
||||
namespace Greenshot.Helpers {
|
||||
/// <summary>
|
||||
/// Description of ScreenCaptureHelper.
|
||||
/// </summary>
|
||||
public class ScreenCaptureHelper {
|
||||
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ScreenCaptureHelper));
|
||||
private static CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private const int MAX_FRAMES = 500;
|
||||
private IntPtr hWndDesktop = IntPtr.Zero;
|
||||
private IntPtr hDCDesktop = IntPtr.Zero;
|
||||
private IntPtr hDCDest = IntPtr.Zero;
|
||||
private IntPtr hDIBSection = IntPtr.Zero;
|
||||
private IntPtr hOldObject = IntPtr.Zero;
|
||||
private int framesPerSecond;
|
||||
private Thread backgroundTask;
|
||||
private bool stop = false;
|
||||
private AVIWriter aviWriter;
|
||||
private WindowDetails recordingWindow;
|
||||
private Rectangle recordingRectangle;
|
||||
public bool RecordMouse = false;
|
||||
private Size recordingSize;
|
||||
private IntPtr bits0 = IntPtr.Zero; //pointer to the raw bits that make up the bitmap.
|
||||
private Bitmap GDIBitmap;
|
||||
private string filename = null;
|
||||
|
||||
public ScreenCaptureHelper(Rectangle recordingRectangle) {
|
||||
this.recordingRectangle = recordingRectangle;
|
||||
}
|
||||
public ScreenCaptureHelper(WindowDetails recordingWindow) {
|
||||
this.recordingWindow = recordingWindow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to create an exception that might explain what is wrong while capturing
|
||||
/// </summary>
|
||||
/// <param name="method">string with current method</param>
|
||||
/// <param name="captureBounds">Rectangle of what we want to capture</param>
|
||||
/// <returns></returns>
|
||||
private static Exception CreateCaptureException(string method, Size size) {
|
||||
Exception exceptionToThrow = User32.CreateWin32Exception(method);
|
||||
if (size != Size.Empty) {
|
||||
exceptionToThrow.Data.Add("Height", size.Height);
|
||||
exceptionToThrow.Data.Add("Width", size.Width);
|
||||
}
|
||||
return exceptionToThrow;
|
||||
}
|
||||
|
||||
public bool Start(int framesPerSecond) {
|
||||
if (recordingWindow != null) {
|
||||
string windowTitle = Regex.Replace(recordingWindow.Text, @"[^\x20\d\w]", "");
|
||||
if (string.IsNullOrEmpty(windowTitle)) {
|
||||
windowTitle = "greenshot-recording";
|
||||
}
|
||||
filename = Path.Combine(conf.OutputFilePath, windowTitle + ".avi");
|
||||
|
||||
} else {
|
||||
filename = Path.Combine(conf.OutputFilePath, "greenshot-recording.avi");
|
||||
}
|
||||
if (File.Exists(filename)) {
|
||||
try {
|
||||
File.Delete(filename);
|
||||
} catch {}
|
||||
}
|
||||
LOG.InfoFormat("Capturing to {0}", filename);
|
||||
|
||||
if (recordingWindow != null) {
|
||||
LOG.InfoFormat("Starting recording Window '{0}', {1}", recordingWindow.Text, recordingWindow.WindowRectangle);
|
||||
recordingSize = recordingWindow.WindowRectangle.Size;
|
||||
} else {
|
||||
LOG.InfoFormat("Starting recording rectangle {0}", recordingRectangle);
|
||||
recordingSize = recordingRectangle.Size;
|
||||
}
|
||||
if (recordingSize.Width % 8 > 0) {
|
||||
LOG.InfoFormat("Correcting width to be factor 8, {0} => {1}", recordingSize.Width, recordingSize.Width + (8-(recordingSize.Width % 8)));
|
||||
recordingSize = new Size(recordingSize.Width + (8-(recordingSize.Width % 8)), recordingSize.Height);
|
||||
}
|
||||
if (recordingSize.Height % 8 > 0) {
|
||||
LOG.InfoFormat("Correcting Height to be factor 8, {0} => {1}", recordingSize.Height, recordingSize.Height + (8-(recordingSize.Height % 8)));
|
||||
recordingSize = new Size(recordingSize.Width, recordingSize.Height + (8-(recordingSize.Height % 8)));
|
||||
}
|
||||
this.framesPerSecond = framesPerSecond;
|
||||
// "P/Invoke" Solution for capturing the screen
|
||||
hWndDesktop = User32.GetDesktopWindow();
|
||||
// get te hDC of the target window
|
||||
hDCDesktop = User32.GetWindowDC(hWndDesktop);
|
||||
// Make sure the last error is set to 0
|
||||
Win32.SetLastError(0);
|
||||
|
||||
// create a device context we can copy to
|
||||
hDCDest = GDI32.CreateCompatibleDC(hDCDesktop);
|
||||
// Check if the device context is there, if not throw an error with as much info as possible!
|
||||
if (hDCDest == IntPtr.Zero) {
|
||||
// Get Exception before the error is lost
|
||||
Exception exceptionToThrow = CreateCaptureException("CreateCompatibleDC", recordingSize);
|
||||
// Cleanup
|
||||
User32.ReleaseDC(hWndDesktop, hDCDesktop);
|
||||
// throw exception
|
||||
throw exceptionToThrow;
|
||||
}
|
||||
|
||||
// Create BitmapInfoHeader for CreateDIBSection
|
||||
BitmapInfoHeader bitmapInfoHeader = new BitmapInfoHeader(recordingSize.Width, recordingSize.Height, 32);
|
||||
|
||||
// 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
|
||||
hDIBSection = GDI32.CreateDIBSection(hDCDesktop, ref bitmapInfoHeader, BitmapInfoHeader.DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0);
|
||||
|
||||
if (hDIBSection == IntPtr.Zero) {
|
||||
// Get Exception before the error is lost
|
||||
Exception exceptionToThrow = CreateCaptureException("CreateDIBSection", recordingSize);
|
||||
exceptionToThrow.Data.Add("hdcDest", hDCDest.ToInt32());
|
||||
exceptionToThrow.Data.Add("hdcSrc", hDCDesktop.ToInt32());
|
||||
|
||||
// clean up
|
||||
GDI32.DeleteDC(hDCDest);
|
||||
User32.ReleaseDC(hWndDesktop, hDCDesktop);
|
||||
|
||||
// Throw so people can report the problem
|
||||
throw exceptionToThrow;
|
||||
}
|
||||
// Create a GDI Bitmap so we can use GDI and GDI+ operations on the same memory
|
||||
GDIBitmap = new Bitmap(recordingSize.Width, recordingSize.Height, 32, PixelFormat.Format32bppArgb, bits0);
|
||||
// select the bitmap object and store the old handle
|
||||
hOldObject = GDI32.SelectObject(hDCDest, hDIBSection);
|
||||
stop = false;
|
||||
|
||||
aviWriter = new AVIWriter();
|
||||
// Comment the following 2 lines to make the user select it's own codec
|
||||
//aviWriter.Codec = "msvc";
|
||||
//aviWriter.Quality = 99;
|
||||
|
||||
aviWriter.FrameRate = framesPerSecond;
|
||||
if (aviWriter.Open(filename, recordingSize.Width, recordingSize.Height)) {
|
||||
// Start update check in the background
|
||||
backgroundTask = new Thread (new ThreadStart(CaptureFrame));
|
||||
backgroundTask.IsBackground = true;
|
||||
backgroundTask.Start();
|
||||
return true;
|
||||
} else {
|
||||
// Cancel
|
||||
aviWriter.Dispose();
|
||||
aviWriter = null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CaptureFrame() {
|
||||
int MSBETWEENCAPTURES = 1000/framesPerSecond;
|
||||
int msToNextCapture = MSBETWEENCAPTURES;
|
||||
while (!stop) {
|
||||
DateTime nextCapture = DateTime.Now.AddMilliseconds(msToNextCapture);
|
||||
Point captureLocation;
|
||||
if (recordingWindow != null) {
|
||||
recordingWindow.Reset();
|
||||
captureLocation = recordingWindow.Location;
|
||||
} else {
|
||||
captureLocation = new Point(recordingRectangle.X, recordingRectangle.Y);
|
||||
}
|
||||
// "Capture"
|
||||
GDI32.BitBlt(hDCDest, 0, 0, recordingSize.Width, recordingSize.Height, hDCDesktop, captureLocation.X, captureLocation.Y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
|
||||
|
||||
// Mouse
|
||||
if (RecordMouse) {
|
||||
CursorInfo cursorInfo = new CursorInfo();
|
||||
cursorInfo.cbSize = Marshal.SizeOf(cursorInfo);
|
||||
Point mouseLocation = Cursor.Position;
|
||||
mouseLocation.Offset(-captureLocation.X, -captureLocation.Y);
|
||||
if (User32.GetCursorInfo(out cursorInfo)) {
|
||||
User32.DrawIcon(hDCDest, mouseLocation.X, mouseLocation.Y, cursorInfo.hCursor);
|
||||
}
|
||||
}
|
||||
// add to avi
|
||||
try {
|
||||
aviWriter.AddLowLevelFrame(bits0);
|
||||
} catch (Exception) {
|
||||
LOG.Error("Error adding frame to avi, stopping capturing.");
|
||||
break;
|
||||
}
|
||||
int sleeptime = (int)(nextCapture.Subtract(DateTime.Now).Ticks / TimeSpan.TicksPerMillisecond);
|
||||
if (sleeptime > 0) {
|
||||
Thread.Sleep(sleeptime);
|
||||
msToNextCapture = MSBETWEENCAPTURES;
|
||||
} else {
|
||||
// Compensating
|
||||
msToNextCapture = Math.Max(0, MSBETWEENCAPTURES - sleeptime);
|
||||
}
|
||||
}
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
public void Stop() {
|
||||
stop = true;
|
||||
if (backgroundTask != null) {
|
||||
backgroundTask.Join();
|
||||
}
|
||||
Cleanup();
|
||||
}
|
||||
/// <summary>
|
||||
/// Free resources
|
||||
/// </summary>
|
||||
private void Cleanup() {
|
||||
if (hOldObject != IntPtr.Zero && hDCDest != IntPtr.Zero) {
|
||||
// restore selection (old handle)
|
||||
GDI32.SelectObject(hDCDest, hOldObject);
|
||||
GDI32.DeleteDC(hDCDest);
|
||||
}
|
||||
if (hDCDesktop != IntPtr.Zero) {
|
||||
User32.ReleaseDC(hWndDesktop, hDCDesktop);
|
||||
}
|
||||
if (hDIBSection != IntPtr.Zero) {
|
||||
// free up the Bitmap object
|
||||
GDI32.DeleteObject(hDIBSection);
|
||||
}
|
||||
if (aviWriter != null) {
|
||||
aviWriter.Dispose();
|
||||
aviWriter = null;
|
||||
MessageBox.Show("Recording written to " + filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
Greenshot/Helpers/WindowWrapper.cs
Normal file
35
Greenshot/Helpers/WindowWrapper.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace Greenshot.Helpers {
|
||||
public class WindowWrapper : System.Windows.Forms.IWin32Window {
|
||||
public WindowWrapper(IntPtr handle) {
|
||||
_hwnd = handle;
|
||||
}
|
||||
|
||||
public IntPtr Handle {
|
||||
get { return _hwnd; }
|
||||
}
|
||||
|
||||
private IntPtr _hwnd;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue