Moving back to trunk!

git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@1602 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4
This commit is contained in:
RKrom 2012-01-24 19:24:36 +00:00
commit 8d458998a1
332 changed files with 17647 additions and 9466 deletions

View file

@ -0,0 +1,180 @@
/*
* 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.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
using System.Reflection;
using Microsoft.Win32;
using Greenshot.Plugin;
namespace GreenshotPlugin.Core {
/// <summary>
/// Description of AbstractDestination.
/// </summary>
public abstract class AbstractDestination : IDestination {
private const string PATH_KEY = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\";
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(AbstractDestination));
public static string GetExePath(string exeName) {
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(PATH_KEY + exeName, false)) {
if (key != null) {
// "" is the default key, which should point to the outlook location
return (string)key.GetValue("");
}
}
return null;
}
/// <summary>
/// Internaly used to create an icon
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static Bitmap GetExeIcon(string path) {
if (!File.Exists(path)) {
return null;
}
try {
using (Icon appIcon = Icon.ExtractAssociatedIcon(path)) {
if (appIcon != null) {
return appIcon.ToBitmap();
}
}
} catch {
}
return null;
}
public virtual int CompareTo(object obj) {
IDestination other = obj as IDestination;
if (other == null) {
return 1;
}
if (Priority == other.Priority) {
return Description.CompareTo(other.Description);
}
return Priority - other.Priority;
}
public abstract string Designation {
get;
}
public abstract string Description {
get;
}
public virtual int Priority {
get {
return 10;
}
}
public virtual Image DisplayIcon {
get {
return null;
}
}
public virtual Keys EditorShortcutKeys {
get {
return Keys.None;
}
}
/// <summary>
/// Return a menu item
/// </summary>
/// <param name="destinationClickHandler"></param>
/// <returns>ToolStripMenuItem</returns>
public virtual ToolStripMenuItem GetMenuItem(EventHandler destinationClickHandler) {
ToolStripMenuItem basisMenuItem;
basisMenuItem = new ToolStripMenuItem(Description);
basisMenuItem.Image = DisplayIcon;
basisMenuItem.Tag = this;
basisMenuItem.Text = Description;
if (isDynamic) {
basisMenuItem.DropDownOpening += delegate (object source, EventArgs eventArgs) {
if (basisMenuItem.DropDownItems.Count == 0) {
List<IDestination> subDestinations = new List<IDestination>();
subDestinations.AddRange(DynamicDestinations());
if (subDestinations.Count > 0) {
subDestinations.Sort();
ToolStripMenuItem destinationMenuItem = new ToolStripMenuItem(Description);
destinationMenuItem.Tag = this;
destinationMenuItem.Image = DisplayIcon;
destinationMenuItem.Click += destinationClickHandler;
basisMenuItem.DropDownItems.Add(destinationMenuItem);
foreach(IDestination subDestination in subDestinations) {
destinationMenuItem = new ToolStripMenuItem(subDestination.Description);
destinationMenuItem.Tag = subDestination;
destinationMenuItem.Image = subDestination.DisplayIcon;
destinationMenuItem.Click += destinationClickHandler;
basisMenuItem.DropDownItems.Add(destinationMenuItem);
}
} else {
// Setting base "click" only if there are no sub-destinations
// Make sure any previous handler is removed, otherwise it would be added multiple times!
basisMenuItem.Click -= destinationClickHandler;
basisMenuItem.Click += destinationClickHandler;
}
}
};
} else {
basisMenuItem.Click += destinationClickHandler;
}
return basisMenuItem;
}
public virtual IEnumerable<IDestination> DynamicDestinations() {
yield break;
}
public virtual void Dispose() {
}
public virtual bool isDynamic {
get {
return false;
}
}
public virtual bool isActive {
get {
return true;
}
}
public abstract bool ExportCapture(ISurface surface, ICaptureDetails captureDetails);
public override string ToString() {
return Description;
}
}
}

View file

@ -0,0 +1,75 @@
/*
* 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.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
using System.Reflection;
using Microsoft.Win32;
using Greenshot.Plugin;
namespace GreenshotPlugin.Core {
/// <summary>
/// Description of AbstractProcessor.
/// </summary>
public abstract class AbstractProcessor : IProcessor {
public virtual int CompareTo(object obj) {
IProcessor other = obj as IProcessor;
if (other == null) {
return 1;
}
if (Priority == other.Priority) {
return Description.CompareTo(other.Description);
}
return Priority - other.Priority;
}
public abstract string Designation {
get;
}
public abstract string Description {
get;
}
public virtual int Priority {
get {
return 10;
}
}
public virtual void Dispose() {
}
public virtual bool isActive {
get {
return true;
}
}
public abstract bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails);
}
}

View file

@ -0,0 +1,288 @@
/*
* 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.Runtime.InteropServices;
using Accessibility;
namespace GreenshotPlugin.Core {
/// <summary>
/// See: http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/03a8c835-e9e4-405b-8345-6c3d36bc8941
/// This should really be cleaned up, there is little OO behind this class!
/// Maybe move the basic Accessible functions to WindowDetails!?
/// </summary>
public class Accessible {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(Accessible));
#region Interop
private static int AccessibleObjectFromWindow(IntPtr hWnd, OBJID idObject, ref IAccessible acc) {
Guid guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessible
object obj = null;
int num = AccessibleObjectFromWindow(hWnd, (uint)idObject, ref guid, ref obj);
acc = (IAccessible)obj;
return num;
}
[DllImport("oleacc.dll")]
public static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject);
[DllImport("oleacc.dll")]
public static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] object[] rgvarChildren, out int pcObtained);
[DllImport("oleacc.dll", PreserveSig=false)]
[return: MarshalAs(UnmanagedType.Interface)]
public static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam);
#endregion
private enum OBJID : uint {
OBJID_WINDOW = 0x00000000,
}
private const int IE_ACTIVE_TAB = 2097154;
private const int CHILDID_SELF = 0;
private IAccessible accessible;
private Accessible[] Children {
get {
int num = 0;
object[] res = GetAccessibleChildren(accessible, out num);
if (res == null) {
return new Accessible[0];
}
List<Accessible> list = new List<Accessible>(res.Length);
foreach (object obj in res) {
IAccessible acc = obj as IAccessible;
if (acc != null) {
list.Add(new Accessible(acc));
}
}
return list.ToArray();
}
}
private string Name {
get {
return accessible.get_accName(CHILDID_SELF);
}
}
private int ChildCount {
get {
return accessible.accChildCount;
}
}
public Accessible(IntPtr hWnd) {
AccessibleObjectFromWindow(hWnd, OBJID.OBJID_WINDOW, ref accessible);
if (accessible == null) {
throw new Exception();
}
}
public void ActivateIETab(string tabCaptionToActivate) {
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
if (tab.Name == tabCaptionToActivate) {
tab.Activate();
return;
}
}
}
}
}
public void CloseIETab(string tabCaptionToClose) {
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
if (tab.Name == tabCaptionToClose) {
foreach (var CloseTab in tab.Children) {
CloseTab.Activate();
}
return;
}
}
}
}
}
public void ActivateIETab(int tabIndexToActivate) {
var index = 0;
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
if (tabIndexToActivate >= child.ChildCount -1) {
return;
}
if (index == tabIndexToActivate) {
tab.Activate();
return;
}
index++;
}
}
}
}
public string IEActiveTabUrl {
get {
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
object tabIndex = tab.accessible.get_accState(CHILDID_SELF);
if ((int)tabIndex == IE_ACTIVE_TAB) {
var description = tab.accessible.get_accDescription(CHILDID_SELF);
if (!string.IsNullOrEmpty(description)) {
if (description.Contains(Environment.NewLine)) {
var url = description.Substring(description.IndexOf(Environment.NewLine)).Trim();
return url;
}
}
}
}
}
}
return String.Empty;
}
}
public int IEActiveTabIndex {
get {
var index = 0;
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
object tabIndex = tab.accessible.get_accState(0);
if ((int)tabIndex == IE_ACTIVE_TAB) {
return index;
}
index++;
}
}
}
return -1;
}
}
public string IEActiveTabCaption {
get {
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
object tabIndex = tab.accessible.get_accState(0);
if ((int)tabIndex == IE_ACTIVE_TAB) {
return tab.Name;
}
}
}
}
return String.Empty;
}
}
public List<string> IETabCaptions {
get {
var captionList = new List<string>();
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
captionList.Add(tab.Name);
}
}
}
if (captionList.Count > 0) {
captionList.RemoveAt(captionList.Count - 1);
}
return captionList;
}
}
public List<string> IETabUrls {
get {
var urlList = new List<string>();
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
object tabIndex = tab.accessible.get_accState(CHILDID_SELF);
var description = tab.accessible.get_accDescription(CHILDID_SELF);
if (!string.IsNullOrEmpty(description)) {
if (description.Contains(Environment.NewLine)) {
var url = description.Substring(description.IndexOf(Environment.NewLine)).Trim();
urlList.Add(url);
}
}
}
}
}
return urlList;
}
}
public int IETabCount {
get {
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
return child.ChildCount - 1;
}
}
}
return 0;
}
}
private Accessible(IAccessible acc) {
if (acc == null) {
throw new Exception();
}
accessible = acc;
}
private void Activate() {
accessible.accDoDefaultAction(CHILDID_SELF);
}
private static object[] GetAccessibleChildren(IAccessible ao, out int childs) {
childs = 0;
object[] ret = null;
int count = ao.accChildCount;
if (count > 0) {
ret = new object[count];
AccessibleChildren(ao, 0, count, ret, out childs);
}
return ret;
}
}
}

View file

@ -0,0 +1,365 @@
/*
* 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.Drawing;
using System.Drawing.Imaging;
using System.Runtime.Serialization;
namespace GreenshotPlugin.Core {
/// <summary>
/// The BitmapBuffer is exactly what it says, it buffers a Bitmap.
/// And it is possible to Draw on the Bitmap with direct memory access for better performance
/// </summary>
[Serializable()]
public unsafe class BitmapBuffer : IDisposable {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BitmapBuffer));
private bool clone;
private Bitmap bitmap;
public Bitmap Bitmap {
get {return bitmap;}
}
[NonSerialized]
private BitmapData bmData;
[NonSerialized]
private Rectangle rect;
[NonSerialized]
private byte* pointer;
[NonSerialized]
private int stride; /* bytes per pixel row */
[NonSerialized]
private int aIndex = -1;
[NonSerialized]
private int rIndex = -1;
[NonSerialized]
private int gIndex = -1;
[NonSerialized]
private int bIndex = -1;
[NonSerialized]
private int bytesPerPixel;
[NonSerialized]
private bool bitsLocked = false;
public Size Size {
get {return rect.Size;}
}
public int Length {
get {return rect.Width*rect.Height;}
}
public int Width {
get {return rect.Width;}
}
public int Height {
get {return rect.Height;}
}
/// <summary>
/// Create a BitmapBuffer from a Bitmap
/// </summary>
/// <param name="sourceBmp">Bitmap</param>
public BitmapBuffer(Bitmap bmp) : this(bmp, Rectangle.Empty) {
}
/// <summary>
/// Create a BitmapBuffer from a Bitmap a flag if we need a clone
/// </summary>
/// <param name="sourceBmp">Bitmap</param>
/// <param name="clone">bool specifying if the bitmap needs to be cloned</param>
public BitmapBuffer(Bitmap sourceBmp, bool clone) : this(sourceBmp, Rectangle.Empty, clone) {
}
/// <summary>
/// Create a BitmapBuffer from a Bitmap and a Rectangle specifying what part from the Bitmap to take.
/// </summary>
/// <param name="sourceBmp">Bitmap</param>
/// <param name="applyRect">Rectangle</param>
public BitmapBuffer(Bitmap sourceBmp, Rectangle applyRect) : this(sourceBmp, applyRect, true) {
}
/// <summary>
/// Create a BitmapBuffer from a Bitmap, a Rectangle specifying what part from the Bitmap to take and a flag if we need a clone
/// </summary>
/// <param name="sourceBmp">Bitmap</param>
/// <param name="applyRect">Rectangle</param>
/// <param name="clone">bool specifying if the bitmap needs to be cloned</param>
public BitmapBuffer(Bitmap sourceBmp, Rectangle applyRect, bool clone) {
this.clone = clone;
Rectangle sourceRect = new Rectangle(applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height);
Rectangle bitmapRect = new Rectangle(0,0, sourceBmp.Width, sourceBmp.Height);
if(sourceRect.IsEmpty) {
sourceRect = bitmapRect;
} else {
sourceRect.Intersect(bitmapRect);
}
// Does the rect have any pixels?
if (sourceRect.Height <= 0 || sourceRect.Width <= 0) {
return;
}
if (SupportsPixelFormat(sourceBmp)) {
if (clone) {
// Create copy with supported format
this.bitmap = sourceBmp.Clone(sourceRect, sourceBmp.PixelFormat);
} else {
this.bitmap = sourceBmp;
}
} else {
// We can only clone, as we don't support the pixel format!
if (!clone) {
throw new ArgumentException("Not supported pixel format: " + sourceBmp.PixelFormat);
}
// When sourceRect is the whole bitmap there is a GDI+ bug in Clone
// Clone will than return the same PixelFormat as the source
// a quick workaround is using new Bitmap which uses a default of Format32bppArgb
if (sourceRect.Equals(bitmapRect)) {
this.bitmap = new Bitmap(sourceBmp);
} else {
this.bitmap = sourceBmp.Clone(sourceRect, PixelFormat.Format32bppArgb);
}
}
// Set "this" rect to location 0,0
// as the Cloned Bitmap is only the part we want to work with
this.rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
}
/**
* Destructor
*/
~BitmapBuffer() {
Dispose(false);
}
/**
* The public accessible Dispose
* Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice
*/
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
// The bulk of the clean-up code is implemented in Dispose(bool)
/**
* This Dispose is called from the Dispose and the Destructor.
* When disposing==true all non-managed resources should be freed too!
*/
protected virtual void Dispose(bool disposing) {
Unlock();
if (disposing) {
if (bitmap != null && clone) {
bitmap.Dispose();
}
}
bitmap = null;
bmData = null;
pointer = null;
}
/**
* This is called when deserializing the object
*/
public BitmapBuffer(SerializationInfo info, StreamingContext ctxt) {
this.bitmap = (Bitmap)info.GetValue("bitmap", typeof(Bitmap));
this.rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
// The rest will be set when Lock is called
}
/**
* This is called when serializing the object
*/
public void GetObjectData(SerializationInfo info, StreamingContext ctxt) {
Unlock();
info.AddValue("bitmap", this.bitmap);
}
/**
* Lock the bitmap so we have direct access to the memory
*/
public void Lock() {
if(rect.Width > 0 && rect.Height > 0) {
bmData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
bitsLocked = true;
System.IntPtr Scan0 = bmData.Scan0;
pointer = (byte*)(void*)Scan0;
PrepareForPixelFormat();
stride = bmData.Stride;
}
}
/**
* Unlock the System Memory
*/
private void Unlock() {
if(bitsLocked) {
bitmap.UnlockBits(bmData);
bitsLocked = false;
}
}
/**
* Draw the stored bitmap to the destionation bitmap at the supplied point
*/
public void DrawTo(Graphics graphics, Point destination) {
DrawTo(graphics, null, destination);
}
/**
* Draw the stored Bitmap on the Destination bitmap with the specified rectangle
* Be aware that the stored bitmap will be resized to the specified rectangle!!
*/
public void DrawTo(Graphics graphics, Rectangle destinationRect) {
DrawTo(graphics, destinationRect, null);
}
/**
* private helper to draw the bitmap
*/
private void DrawTo(Graphics graphics, Rectangle? destinationRect, Point? destination) {
if (destinationRect.HasValue) {
// Does the rect have any pixels?
if (destinationRect.Value.Height <= 0 || destinationRect.Value.Width <= 0) {
return;
}
}
// Make sure this.bitmap is unlocked
Unlock();
if (destinationRect.HasValue) {
graphics.DrawImage(this.bitmap, destinationRect.Value);
} else if (destination.HasValue) {
graphics.DrawImage(this.bitmap, destination.Value);
}
}
/**
* Retrieve the color at location x,y
* Before the first time this is called the Lock() should be called once!
*/
public Color GetColorAt(int x, int y) {
if(x>=0 && y>=0 && x<rect.Width && y<rect.Height) {
int offset = x*bytesPerPixel+y*stride;
int a = (aIndex==-1) ? 255 : (int)pointer[aIndex+offset];
return Color.FromArgb(a, pointer[rIndex+offset], pointer[gIndex+offset], pointer[bIndex+offset]);
} else {
return Color.Empty;
}
}
/**
* Retrieve the color at location x,y
* Before the first time this is called the Lock() should be called once!
*/
public Color GetColorAtWithoutAlpha(int x, int y) {
if(x>=0 && y>=0 && x<rect.Width && y<rect.Height) {
int offset = x*bytesPerPixel+y*stride;
return Color.FromArgb(255, pointer[rIndex+offset], pointer[gIndex+offset], pointer[bIndex+offset]);
} else {
return Color.Empty;
}
}
/**
* Set the color at location x,y
* Before the first time this is called the Lock() should be called once!
*/
public void SetColorAt(int x, int y, Color color) {
if(x>=0 && y>=0 && x<rect.Width && y<rect.Height) {
int offset = x*bytesPerPixel+y*stride;
if(aIndex!=-1) pointer[aIndex+offset] = color.A;
pointer[rIndex+offset] = color.R;
pointer[gIndex+offset] = color.G;
pointer[bIndex+offset] = color.B;
}
}
/**
* Retrieve the color at location x,y as an array
* Before the first time this is called the Lock() should be called once!
*/
public int[] GetColorArrayAt(int x, int y) {
if(x>=0 && y>=0 && x<rect.Width && y<rect.Height) {
int offset = x*bytesPerPixel+y*stride;
int a = (aIndex==-1) ? 255 : (int)pointer[aIndex+offset];
return new int[]{a, pointer[rIndex+offset], pointer[gIndex+offset], pointer[bIndex+offset]};
} else {
return new int[]{0,0,0,0};
}
}
/**
* Set the color at location x,y as an array
* Before the first time this is called the Lock() should be called once!
*/
public void SetColorArrayAt(int x, int y, int[] colors) {
if(x>=0 && y>=0 && x<rect.Width && y<rect.Height) {
int offset = x*bytesPerPixel+y*stride;
if(aIndex!=-1) pointer[aIndex+offset] = (byte)colors[0];
pointer[rIndex+offset] = (byte)colors[1];
pointer[gIndex+offset] = (byte)colors[2];
pointer[bIndex+offset] = (byte)colors[3];
}
}
/**
* Checks if the supplied Bitmap has a PixelFormat we support
*/
private bool SupportsPixelFormat(Bitmap bitmap) {
return (bitmap.PixelFormat.Equals(PixelFormat.Format32bppArgb) ||
bitmap.PixelFormat.Equals(PixelFormat.Format32bppRgb) ||
bitmap.PixelFormat.Equals(PixelFormat.Format24bppRgb));
}
/**
* Set some internal values for accessing the bitmap according to the PixelFormat
*/
private void PrepareForPixelFormat() {
// aIndex is only set if the pixel format supports "A".
aIndex = -1;
switch(bitmap.PixelFormat) {
case PixelFormat.Format32bppArgb:
bIndex = 0;
gIndex = 1;
rIndex = 2;
aIndex = 3;
bytesPerPixel = 4;
break;
case PixelFormat.Format32bppRgb:
bIndex = 0;
gIndex = 1;
rIndex = 2;
bytesPerPixel = 4;
break;
case PixelFormat.Format24bppRgb:
bIndex = 0;
gIndex = 1;
rIndex = 2;
bytesPerPixel = 3;
break;
default:
throw new FormatException("Bitmap.Pixelformat."+bitmap.PixelFormat+" is currently not supported. Supported: Format32bpp(A)Rgb, Format24bppRgb");
}
}
}
}

View file

@ -0,0 +1,145 @@
/*
* 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;
using System.Collections.Generic;
using System.Web;
using System.Web.Caching;
namespace GreenshotPlugin.Core {
public delegate void CacheObjectExpired(string key, object cacheValue);
/// <summary>
/// Description of CacheHelper.
/// </summary>
public class CacheHelper<T> {
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger("CacheHelper");
private Cache cache = HttpRuntime.Cache;
private string prefix;
private double defaultExpiration = 10*60; // 10 Minutes
private CacheItemRemovedCallback defaultCallback = null;
private CacheObjectExpired expiredCallback = null;
public CacheHelper(string prefix) {
defaultCallback = new CacheItemRemovedCallback(OnRemoved);
this.prefix = prefix + ".";
}
public CacheHelper(string prefix, double defaultExpiration) : this(prefix) {
this.defaultExpiration = defaultExpiration;
}
public CacheHelper(string prefix, double defaultExpiration, CacheObjectExpired expiredCallback) : this(prefix, defaultExpiration) {
this.expiredCallback = expiredCallback;
}
private void OnRemoved(string key, object cacheValue, CacheItemRemovedReason reason) {
LOG.DebugFormat("The item with key '{0}' is being removed from the cache with reason: {1}", key, reason);
switch (reason) {
case CacheItemRemovedReason.Expired:
if (expiredCallback != null) {
expiredCallback.Invoke(key, cacheValue);
}
break;
case CacheItemRemovedReason.Underused:
break;
}
}
/// <summary>
/// Insert value into the cache using default expiration & default callback
/// </summary>
/// <param name="o">Item to be cached</param>
/// <param name="key">Name of item</param>
public void Add(string key, T o) {
if (defaultCallback != null) {
cache.Insert(prefix + key, o, null, DateTime.Now.AddSeconds(defaultExpiration), Cache.NoSlidingExpiration, CacheItemPriority.Default, defaultCallback);
} else {
cache.Insert(prefix + key, o, null, DateTime.Now.AddSeconds(defaultExpiration), Cache.NoSlidingExpiration);
}
}
/// <summary>
/// Get all the methods for this cache
/// </summary>
/// <returns>IEnumerator of the type</returns>
public IEnumerable<T> GetElements() {
IDictionaryEnumerator cacheEnum = cache.GetEnumerator();
while (cacheEnum.MoveNext()) {
string key = cacheEnum.Key as string;
if (!string.IsNullOrEmpty(key) && key.StartsWith(prefix)) {
yield return (T)cacheEnum.Value;
}
}
}
/// <summary>
/// Insert value into the cache using the supplied expiration time in seconds
/// </summary>
/// <param name="o">Item to be cached</param>
/// <param name="key">Name of item</param>
/// <param name="seconds">expiration time in "double" seconds</param>
public void Add(string key, T o, double seconds) {
cache.Insert(prefix + key, o, null, DateTime.Now.AddSeconds(seconds), Cache.NoSlidingExpiration);
}
/// <summary>
/// Insert value into the cache using
/// appropriate name/value pairs
/// </summary>
/// <param name="o">Item to be cached</param>
/// <param name="key">Name of item</param>
public void Add(string key, T o, CacheItemRemovedCallback callback) {
cache.Insert(prefix + key, o, null, DateTime.Now.AddSeconds(defaultExpiration), Cache.NoSlidingExpiration, CacheItemPriority.Default, callback);
}
/// <summary>
/// Remove item from cache
/// </summary>
/// <param name="key">Name of cached item</param>
public void Remove(string key) {
cache.Remove(prefix + key);
}
/// <summary>
/// Check for item in cache
/// </summary>
/// <param name="key">Name of cached item</param>
/// <returns></returns>
public bool Exists(string key) {
return cache[prefix + key] != null;
}
/// <summary>
/// Retrieve cached item
/// </summary>
/// <param name="key">Name of cached item</param>
/// <returns>Cached item as type</returns>
public T Get(string key) {
try {
return (T) cache[prefix + key];
} catch {
return default(T);
}
}
}
}

View file

@ -1,726 +0,0 @@
/*
* 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.Drawing;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace GreenshotPlugin.Core {
/// <summary>
/// Attribute for telling that this class is linked to a section in the ini-configuration
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class IniSectionAttribute : Attribute {
private string name;
public IniSectionAttribute(string name) {
this.name = name;
}
public string Description;
public string Name {
get {return name;}
set {name = value;}
}
}
/// <summary>
/// Attribute for telling that a field is linked to a property in the ini-configuration selection
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple=false)]
public class IniPropertyAttribute : Attribute {
private string name;
public IniPropertyAttribute(string name) {
this.name = name;
}
public string Description;
public string Separator = ",";
public string DefaultValue;
public string Name {
get {return name;}
set {name = value;}
}
}
public static class IniReader{
private const string SECTION_START = "[";
private const string SECTION_END = "]";
private const string COMMENT = ";";
private static char[] ASSIGNMENT = new char[] { '=' };
/**
* Read an ini file to a Dictionary, each key is a section and the value is a Dictionary with name and values.
*/
public static Dictionary<string, Dictionary<string, string>> read(string path, Encoding encoding) {
Dictionary<string, Dictionary<string, string>> ini = new Dictionary<string, Dictionary<string,string>>();
using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 1024)) {
using (StreamReader reader = new StreamReader(fileStream, encoding)) {
Dictionary<string, string> nameValues = new Dictionary<string, string>();
while (!reader.EndOfStream) {
string line = reader.ReadLine();
if (line != null) {
string cleanLine = line.Trim();
if (cleanLine.Length == 0 || cleanLine.StartsWith(COMMENT)) {
continue;
}
if (cleanLine.StartsWith(SECTION_START)) {
string section = line.Replace(SECTION_START, "").Replace(SECTION_END, "").Trim();
nameValues = new Dictionary<string, string>();
ini.Add(section, nameValues);
} else {
string[] keyvalueSplitter = line.Split(ASSIGNMENT, 2);
string name = keyvalueSplitter[0];
string inivalue = keyvalueSplitter.Length > 1 ? keyvalueSplitter[1] : null;
if (nameValues.ContainsKey(name)) {
nameValues[name] = inivalue;
} else {
nameValues.Add(name, inivalue);
}
}
}
}
}
}
return ini;
}
}
/// <summary>
/// Base class for all IniSections
/// </summary>
public abstract class IniSection {
/// Flag to specify if values have been changed
public bool IsDirty = false;
/// <summary>
/// Supply values we can't put as defaults
/// </summary>
/// <param name="property">The property to return a default for</param>
/// <returns>object with the default value for the supplied property</returns>
public virtual object GetDefault(string property) {
return null;
}
/// <summary>
/// This method will be called before converting the property, making to possible to correct a certain value
/// Can be used when migration is needed
/// </summary>
/// <param name="propertyName">The name of the property</param>
/// <param name="propertyValue">The string value of the property</param>
/// <returns>string with the propertyValue, modified or not...</returns>
public virtual string PreCheckValue(string propertyName, string propertyValue) {
return propertyValue;
}
/// <summary>
/// This method will be called after reading the configuration, so eventually some corrections can be made
/// </summary>
public virtual void PostCheckValues() {
}
}
public class IniConfig {
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(IniConfig));
private const string CONFIG_FILE_NAME = "greenshot.ini";
private const string DEFAULTS_CONFIG_FILE_NAME = "greenshot-defaults.ini";
private const string FIXED_CONFIG_FILE_NAME = "greenshot-fixed.ini";
private const string SUBDIRECTORY_NAME = "Greenshot";
private static FileSystemWatcher watcher;
/// <summary>
/// Static code for loading
/// </summary>
static IniConfig() {
iniLocation = CreateIniLocation(CONFIG_FILE_NAME);
// Load the defaults
Read(CreateIniLocation(DEFAULTS_CONFIG_FILE_NAME));
// Load the normal
Read(CreateIniLocation(iniLocation));
// Load the fixed settings
Read(CreateIniLocation(FIXED_CONFIG_FILE_NAME));
WatchConfigFile(true);
}
private static string iniLocation = null;
private static Dictionary<string, IniSection> sectionMap = new Dictionary<string, IniSection>();
private static Dictionary<string, Dictionary<string, string >> iniProperties = new Dictionary<string, Dictionary<string, string>>();
public static event FileSystemEventHandler IniChanged;
private static void WatchConfigFile(bool sendEvents) {
// Wait with watching untill the file is there
if (Directory.Exists(Path.GetDirectoryName(iniLocation))) {
if (watcher == null) {
LOG.DebugFormat("Starting FileSystemWatcher for {0}", iniLocation);
// Monitor the ini file
watcher = new FileSystemWatcher();
watcher.Path = Path.GetDirectoryName(iniLocation);
watcher.Filter = "*.ini";
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Changed += new FileSystemEventHandler(ConfigFileChanged);
}
}
if (watcher != null) {
watcher.EnableRaisingEvents = sendEvents;
}
}
private static void ConfigFileChanged(object source, FileSystemEventArgs e) {
if (iniLocation.Equals(e.FullPath)) {
LOG.InfoFormat("Config file {0} was changed, reloading", e.FullPath);
// Try to reread the configuration
int retries = 10;
bool configRead = false;
while(!configRead && retries != 0) {
try {
IniConfig.Reload();
configRead = true;
} catch (IOException) {
retries--;
Thread.Sleep(100);
}
}
if (configRead && IniChanged != null) {
IniChanged.Invoke(source, e);
}
}
}
/// <summary>
/// Create the location of the configuration file
/// </summary>
private static string CreateIniLocation(string configFilename) {
// check if file is in the same location as started from, if this is the case
// we will use this file instead of the Applicationdate folder
// Done for Feature Request #2741508
if (File.Exists(Path.Combine(Application.StartupPath, configFilename))) {
return Path.Combine(Application.StartupPath, configFilename);
}
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), SUBDIRECTORY_NAME + @"\" + configFilename);
}
/// <summary>
/// Reload the Ini file
/// </summary>
public static void Reload() {
// Load the normal
Read(iniLocation);
// Load the fixed settings
Read(CreateIniLocation(FIXED_CONFIG_FILE_NAME));
foreach(IniSection section in sectionMap.Values) {
FillIniSection(section);
}
}
/// <summary>
/// Read the ini file into the Dictionary
/// </summary>
/// <param name="iniLocation">Path & Filename of ini file</param>
private static void Read(string iniLocation) {
if (!File.Exists(iniLocation)) {
LOG.Info("Can't find file: " + iniLocation);
return;
}
LOG.Info("Reading ini-properties from file: " + iniLocation);
iniProperties = IniReader.read(iniLocation, Encoding.UTF8);
}
/// <summary>
/// A generic method which returns an instance of the supplied type, filled with it's configuration
/// </summary>
/// <returns>Filled instance of IniSection type which was supplied</returns>
public static T GetIniSection<T>() where T : IniSection {
T section;
Type iniSectionType = typeof(T);
string sectionName = getSectionName(iniSectionType);
if (sectionMap.ContainsKey(sectionName)) {
LOG.Debug("Returning pre-mapped section " + sectionName);
section = (T)sectionMap[sectionName];
} else {
// Create instance of this type
section = (T)Activator.CreateInstance(iniSectionType);
// Store for later save & retrieval
sectionMap.Add(sectionName, section);
FillIniSection(section);
LOG.Debug("Returning newly mapped section " + sectionName);
}
if (section.IsDirty) {
IniConfig.Save();
}
return section;
}
private static void FillIniSection(IniSection section) {
Type iniSectionType = section.GetType();
string sectionName = getSectionName(iniSectionType);
// Get the properties for the section
Dictionary<string, string> properties = null;
if (iniProperties.ContainsKey(sectionName)) {
properties = iniProperties[sectionName];
} else {
iniProperties.Add(sectionName, new Dictionary<string, string>());
properties = iniProperties[sectionName];
}
// Iterate over the fields and fill them
FieldInfo[] fields = iniSectionType.GetFields();
foreach(FieldInfo field in fields) {
if (Attribute.IsDefined(field, typeof(IniPropertyAttribute))) {
IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute)field.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0];
string propertyName = iniPropertyAttribute.Name;
string propertyDefaultValue = iniPropertyAttribute.DefaultValue;
string fieldSeparator = iniPropertyAttribute.Separator;
// Get the type, or the underlying type for nullables
Type fieldType = field.FieldType;
// Get the value from the ini file, if there is none take the default
if (!properties.ContainsKey(propertyName) && propertyDefaultValue != null) {
// Mark as dirty, we didn't use properties from the file (even defaults from the default file are allowed)
section.IsDirty = true;
LOG.Debug("Passing default: " + propertyName + "=" + propertyDefaultValue);
}
// Try to get the field value from the properties or use the default value
object fieldValue = null;
try {
fieldValue = CreateFieldValue(fieldType, section, sectionName, propertyName, propertyDefaultValue, fieldSeparator);
} catch (Exception e) {
LOG.Warn("Couldn't parse field: " + sectionName + "." + propertyName, e);
}
// If still no value, check if the GetDefault delivers a value
if (fieldValue == null) {
// Use GetDefault to fill the field if none is set
fieldValue = section.GetDefault(propertyName);
}
// Set the value
try {
field.SetValue(section,fieldValue);
} catch (Exception e) {
LOG.Warn("Couldn't set field: " + sectionName + "." + propertyName, e);
}
}
}
}
/// <summary>
/// Helper method for creating a value
/// </summary>
/// <param name="fieldType">Type of the value to create</param>
/// <param name="propertyValue">Value as string</param>
/// <returns>object instance of the value</returns>
private static object CreateFieldValue(Type fieldType, IniSection section, string sectionName, string propertyName, string defaultValue, string arraySeparator) {
Dictionary<string, string> properties = iniProperties[sectionName];
bool defaultUsed = false;
string propertyValue = null;
if (properties.ContainsKey(propertyName) && properties[propertyName] != null) {
propertyValue = section.PreCheckValue(propertyName, properties[propertyName]);
} else if (defaultValue != null && defaultValue.Trim().Length != 0) {
propertyValue = defaultValue;
defaultUsed = true;
} else {
LOG.DebugFormat("Property {0} has no value or default value", propertyName);
}
// Now set the value
if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(List<>)) {
object list = Activator.CreateInstance(fieldType);
// Logic for List<>
if (propertyValue == null) {
return list;
}
string[] arrayValues = propertyValue.Split(new string[] {arraySeparator}, StringSplitOptions.None);
if (arrayValues == null || arrayValues.Length == 0) {
return list;
}
bool addedElements = false;
bool parseProblems = false;
MethodInfo addMethodInfo = fieldType.GetMethod("Add");
foreach(string arrayValue in arrayValues) {
if (arrayValue != null && arrayValue.Length > 0) {
object newValue = null;
try {
newValue = ConvertValueToFieldType(fieldType.GetGenericArguments()[0], arrayValue);
} catch (Exception e) {
LOG.Error("Problem converting " + arrayValue + " to type " + fieldType.FullName, e);
parseProblems = true;
}
if (newValue != null) {
addMethodInfo.Invoke(list, new object[] {newValue});
addedElements = true;
}
}
}
// Try to fallback on a default
if (!addedElements && parseProblems) {
try {
object fallbackValue = ConvertValueToFieldType(fieldType.GetGenericArguments()[0], defaultValue);
addMethodInfo.Invoke(list, new object[] {fallbackValue});
return list;
} catch (Exception e) {
LOG.Error("Problem converting " + defaultValue + " to type " + fieldType.FullName, e);
}
}
return list;
} else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) {
// Logic for Dictionary<,>
Type type1 = fieldType.GetGenericArguments()[0];
Type type2 = fieldType.GetGenericArguments()[1];
LOG.Info(String.Format("Found Dictionary<{0},{1}>",type1.Name, type2.Name));
object dictionary = Activator.CreateInstance(fieldType);
MethodInfo addMethodInfo = fieldType.GetMethod("Add");
bool addedElements = false;
foreach(string key in properties.Keys) {
if (key != null && key.StartsWith(propertyName + ".")) {
// What "key" do we need to store it under?
string subPropertyName = key.Substring(propertyName.Length + 1);
string stringValue = properties[key];
object newValue1 = null;
object newValue2 = null;
try {
newValue1 = ConvertValueToFieldType(type1, subPropertyName);
} catch (Exception e) {
LOG.Error("Problem converting " + subPropertyName + " to type " + type1.FullName, e);
}
try {
newValue2 = ConvertValueToFieldType(type2, stringValue);
} catch (Exception e) {
LOG.Error("Problem converting " + stringValue + " to type " + type2.FullName, e);
}
addMethodInfo.Invoke(dictionary, new object[] {newValue1, newValue2});
addedElements = true;
}
}
// No need to return something that isn't filled!
if (addedElements) {
return dictionary;
}
} else {
if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) {
// We are dealing with a generic type that is nullable
fieldType = Nullable.GetUnderlyingType(fieldType);
}
object newValue = null;
try {
newValue = ConvertValueToFieldType(fieldType, propertyValue);
} catch (Exception e1) {
newValue = null;
if (!defaultUsed) {
try {
newValue = ConvertValueToFieldType(fieldType, defaultValue);
} catch (Exception e2) {
LOG.Error("Problem converting " + propertyValue + " to type " + fieldType.FullName, e2);
}
} else {
LOG.Error("Problem converting " + propertyValue + " to type " + fieldType.FullName, e1);
}
}
return newValue;
}
return null;
}
private static object ConvertValueToFieldType(Type fieldType, string valueString) {
if (valueString == null) {
return null;
}
if (fieldType == typeof(string)) {
return valueString;
} else if (fieldType == typeof(bool) || fieldType == typeof(bool?)) {
if (valueString.Length > 0) {
return bool.Parse(valueString);
}
} else if (fieldType == typeof(int) || fieldType == typeof(int?)) {
if (valueString.Length > 0) {
return int.Parse(valueString);
}
} else if (fieldType == typeof(uint) || fieldType == typeof(uint?)) {
if (valueString.Length > 0) {
return uint.Parse(valueString);
}
return 0;
} else if (fieldType == typeof(Point)) {
if (valueString.Length > 0) {
string[] pointValues = valueString.Split(new Char[] {','});
int x = int.Parse(pointValues[0].Trim());
int y = int.Parse(pointValues[1].Trim());
return new Point(x, y);
}
} else if (fieldType == typeof(DateTime)) {
if (valueString.Length > 0) {
return DateTime.Parse(valueString);
}
} else if (fieldType == typeof(Size)) {
if (valueString.Length > 0) {
string[] sizeValues = valueString.Split(new Char[] {','});
int width = int.Parse(sizeValues[0].Trim());
int height = int.Parse(sizeValues[1].Trim());
return new Size(width, height);
}
} else if (fieldType == typeof(Rectangle)) {
if (valueString.Length > 0) {
string[] rectValues = valueString.Split(new Char[] {','});
int x = int.Parse(rectValues[0].Trim());
int y = int.Parse(rectValues[1].Trim());
int width = int.Parse(rectValues[2].Trim());
int height = int.Parse(rectValues[3].Trim());
return new Rectangle(x, y, width, height);
}
} else if (fieldType == typeof(Color)) {
if (valueString.Length > 0) {
string[] colorValues = valueString.Split(new Char[] {','});
int alpha = int.Parse(colorValues[0].Trim());
int red = int.Parse(colorValues[1].Trim());
int green = int.Parse(colorValues[2].Trim());
int blue = int.Parse(colorValues[3].Trim());
return Color.FromArgb(alpha, red, green, blue);
}
} else if (fieldType == typeof(object)) {
if (valueString.Length > 0) {
//LOG.Debug("Parsing: " + valueString);
string[] values = valueString.Split(new Char[] {':'});
//LOG.Debug("Type: " + values[0]);
//LOG.Debug("Value: " + values[1]);
Type fieldTypeForValue = Type.GetType(values[0], true);
//LOG.Debug("Type after GetType: " + fieldTypeForValue);
return ConvertValueToFieldType(fieldTypeForValue, values[1]);
}
} else if (fieldType.IsEnum) {
if (valueString.Length > 0) {
try {
return Enum.Parse(fieldType, valueString);
} catch (ArgumentException ae) {
LOG.InfoFormat("Couldn't match {0} to {1}, trying case-insentive match", valueString, fieldType);
foreach(Enum enumValue in Enum.GetValues(fieldType)) {
if (enumValue.ToString().Equals(valueString, StringComparison.InvariantCultureIgnoreCase)) {
LOG.Info("Match found...");
return enumValue;
}
}
throw ae;
}
}
}
return null;
}
private static string ConvertValueToString(Type fieldType, object valueObject) {
if (valueObject == null) {
// If there is nothing, deliver nothing!
return "";
}
if (fieldType == typeof(Point)) {
// Point to String
Point p = (Point)valueObject;
return String.Format("{0},{1}", p.X, p.Y);
} else if (fieldType == typeof(Size)) {
// Size to String
Size size = (Size)valueObject;
return String.Format("{0},{1}", size.Width, size.Height);
} else if (fieldType == typeof(Rectangle)) {
// Rectangle to String
Rectangle rectangle = (Rectangle)valueObject;
return String.Format("{0},{1},{2},{3}", rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
} else if (fieldType == typeof(Color)) {
// Color to String
Color color = (Color)valueObject;
return String.Format("{0},{1},{2},{3}", color.A, color.R, color.G, color.B);
} else if (fieldType == typeof(object)) {
// object to String, this is the hardest
// Format will be "FQTypename[,Assemblyname]:Value"
// Get the type so we can call ourselves recursive
Type valueType = valueObject.GetType();
// Get the value as string
string ourValue = ConvertValueToString(valueType, valueObject);
// Get the valuetype as string
string valueTypeName = valueType.FullName;
// Find the assembly name and only append it if it's not already in the fqtypename (like System.Drawing)
string assemblyName = valueType.Assembly.FullName;
// correct assemblyName, this also has version information etc.
if (assemblyName.StartsWith("Green")) {
assemblyName = assemblyName.Substring(0,assemblyName.IndexOf(','));
}
return String.Format("{0},{1}:{2}", valueTypeName, assemblyName, ourValue);
}
// All other types
return valueObject.ToString();
}
private static string getSectionName(Type iniSectionType) {
Attribute[] classAttributes = Attribute.GetCustomAttributes(iniSectionType);
foreach(Attribute attribute in classAttributes) {
if (attribute is IniSectionAttribute) {
IniSectionAttribute iniSectionAttribute = (IniSectionAttribute)attribute;
return iniSectionAttribute.Name;
}
}
return null;
}
private static Dictionary<string, string> getProperties(string section) {
if (iniProperties.ContainsKey(section)) {
return iniProperties[section];
}
return null;
}
public static string GetProperty(string section, string name) {
Dictionary<string, string> properties = getProperties(section);
if (properties != null && properties.ContainsKey(name)) {
return properties[name];
}
return null;
}
/// <summary>
/// Split property with ',' and return the splitted string as a string[]
/// </summary>
public static string[] GetPropertyAsArray(string section, string key) {
Dictionary<string, string> properties = getProperties(section);
string value = GetProperty(section, key);
if (value != null) {
return value.Split(new Char[] {','});
}
return null;
}
public static bool GetBoolProperty(string section, string key) {
Dictionary<string, string> properties = getProperties(section);
string value = GetProperty(section, key);
return bool.Parse(value);
}
public static int GetIntProperty(string section, string key) {
Dictionary<string, string> properties = getProperties(section);
string value = GetProperty(section, key);
return int.Parse(value);
}
public static void Save() {
try {
SaveInternally();
} catch (Exception e) {
LOG.Error("A problem occured while writing the configuration file to: " + iniLocation, e);
}
}
private static void SaveInternally() {
WatchConfigFile(false);
LOG.Info("Saving configuration to: " + iniLocation);
if (!Directory.Exists(Path.GetDirectoryName(iniLocation))) {
Directory.CreateDirectory(Path.GetDirectoryName(iniLocation));
}
TextWriter writer = new StreamWriter(iniLocation, false, Encoding.UTF8);
foreach(IniSection section in sectionMap.Values) {
Type classType = section.GetType();
Attribute[] classAttributes = Attribute.GetCustomAttributes(classType);
foreach(Attribute attribute in classAttributes) {
if (attribute is IniSectionAttribute) {
IniSectionAttribute iniSectionAttribute = (IniSectionAttribute)attribute;
writer.WriteLine("; {0}", iniSectionAttribute.Description);
writer.WriteLine("[{0}]", iniSectionAttribute.Name);
FieldInfo[] fields = classType.GetFields();
foreach(FieldInfo field in fields) {
if (Attribute.IsDefined(field, typeof(IniPropertyAttribute))) {
IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute)field.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0];
writer.WriteLine("; {0}", iniPropertyAttribute.Description);
object value = field.GetValue(section);
Type fieldType = field.FieldType;
if (value == null) {
value = iniPropertyAttribute.DefaultValue;
fieldType = typeof(string);
}
if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(List<>)) {
Type valueType = fieldType.GetGenericArguments()[0];
writer.Write("{0}=", iniPropertyAttribute.Name);
int listCount = (int)fieldType.GetProperty("Count").GetValue(value, null);
// Loop though generic list
for (int index = 0; index < listCount; index++) {
object item = fieldType.GetMethod("get_Item").Invoke(value, new object[] { index });
// Now you have an instance of the item in the generic list
if (index < listCount -1) {
writer.Write("{0}" + iniPropertyAttribute.Separator, ConvertValueToString(valueType, item));
} else {
writer.Write("{0}", ConvertValueToString(valueType, item));
}
}
writer.WriteLine();
} else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) {
// Handle dictionaries.
Type valueType1 = fieldType.GetGenericArguments()[0];
Type valueType2 = fieldType.GetGenericArguments()[1];
// Get the methods we need to deal with dictionaries.
var keys = fieldType.GetProperty("Keys").GetValue(value, null);
var item = fieldType.GetProperty("Item");
var enumerator = keys.GetType().GetMethod("GetEnumerator").Invoke(keys, null);
var moveNext = enumerator.GetType().GetMethod("MoveNext");
var current = enumerator.GetType().GetProperty("Current").GetGetMethod();
// Get all the values.
while ((bool)moveNext.Invoke(enumerator, null)) {
var key = current.Invoke(enumerator, null);
var valueObject = item.GetValue(value, new object[] { key });
// Write to ini file!
writer.WriteLine("{0}.{1}={2}", iniPropertyAttribute.Name, ConvertValueToString(valueType1, key), ConvertValueToString(valueType2, valueObject));
}
} else {
writer.WriteLine("{0}={1}", iniPropertyAttribute.Name, ConvertValueToString(fieldType, value));
}
}
}
}
}
writer.WriteLine();
section.IsDirty = false;
}
writer.WriteLine();
// Write left over properties
foreach(string sectionName in iniProperties.Keys) {
// Check if the section is one that is "registered", if so skip it!
if (!sectionMap.ContainsKey(sectionName)) {
writer.WriteLine("; The section {0} is not registered, maybe a plugin hasn't claimed it due to errors or some functionality isn't used yet.", sectionName);
// Write section name
writer.WriteLine("[{0}]", sectionName);
Dictionary<string, string> properties = iniProperties[sectionName];
// Loop and write properties
foreach(string propertyName in properties.Keys) {
writer.WriteLine("{0}={1}", propertyName, properties[propertyName]);
}
writer.WriteLine();
}
}
writer.Close();
WatchConfigFile(true);
}
}
}

View file

@ -20,12 +20,16 @@
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Greenshot.Plugin;
using IniFile;
namespace GreenshotPlugin.Core {
public enum Destination {
Editor, FileDefault, FileWithDialog, Clipboard, Printer, EMail
public enum ClipboardFormat {
PNG, DIB, HTML
}
public enum OutputFormat {
bmp, gif, jpg, png, tiff
@ -34,24 +38,19 @@ namespace GreenshotPlugin.Core {
Screen, GDI, Aero, AeroTransparent, Auto
}
public enum EmailFormat {
TXT, HTML
}
public enum UpdateCheckInterval {
Never,
Daily,
Weekly,
Monthly
MAPI, OUTLOOK_TXT, OUTLOOK_HTML
}
public enum EmailExport {
AlwaysNew,
TryOpenElseNew
}
/// <summary>
/// Description of CoreConfiguration.
/// </summary>
[IniSection("Core", Description="Greenshot core configuration")]
public class CoreConfiguration : IniSection {
[IniProperty("Language", Description="The language in IETF format (e.g. en-EN)", DefaultValue="en-EN")]
[IniProperty("Language", Description="The language in IETF format (e.g. en-EN)")]
public string Language;
[IniProperty("RegionHotkey", Description="Hotkey for starting the region capture", DefaultValue="PrintScreen")]
@ -68,7 +67,9 @@ namespace GreenshotPlugin.Core {
[IniProperty("IsFirstLaunch", Description="Is this the first time launch?", DefaultValue="true")]
public bool IsFirstLaunch;
[IniProperty("Destinations", Separator=",", Description="Which destinations? Options are: Editor, FileDefault, FileWithDialog, Clipboard, Printer, EMail", DefaultValue="Editor")]
public List<Destination> OutputDestinations = new List<Destination>();
public List<string> OutputDestinations = new List<string>();
[IniProperty("ClipboardFormats", Separator=",", Description="Specify which formats we copy on the clipboard? Options are: PNG,HTML and DIB", DefaultValue="PNG,HTML,DIB")]
public List<ClipboardFormat> ClipboardFormats = new List<ClipboardFormat>();
[IniProperty("CaptureMousepointer", Description="Should the mouse be captured?", DefaultValue="true")]
public bool CaptureMousepointer;
@ -78,11 +79,16 @@ namespace GreenshotPlugin.Core {
public int CaptureDelay;
[IniProperty("WindowCaptureMode", Description="The capture mode used to capture a Window.", DefaultValue="Auto")]
public WindowCaptureMode WindowCaptureMode;
[IniProperty("WindowCaptureAllChildLocations", Description="Enable/disable capture all children, very slow but will make it possible to use this information in the editor.", DefaultValue="False")]
public bool WindowCaptureAllChildLocations;
[IniProperty("DWMBackgroundColor", Description="The background color for a DWM window capture.")]
public Color DWMBackgroundColor;
[IniProperty("PlayCameraSound", Description="Play a camera sound after taking a capture.", DefaultValue="false")]
[IniProperty("PlayCameraSound", LanguageKey="settings_playsound",Description="Play a camera sound after taking a capture.", DefaultValue="false")]
public bool PlayCameraSound = false;
[IniProperty("ShowTrayNotification", LanguageKey="settings_shownotify",Description="Show a notification from the systray when a capture is taken.", DefaultValue="true")]
public bool ShowTrayNotification = true;
[IniProperty("OutputFilePath", Description="Output file path.")]
public string OutputFilePath;
@ -93,8 +99,8 @@ namespace GreenshotPlugin.Core {
[IniProperty("OutputFileReduceColors", Description="If set to true, than the colors of the output file are reduced to 256 (8-bit) colors", DefaultValue="false")]
public bool OutputFileReduceColors;
[IniProperty("OutputEMailFormat", Description="Default type for emails. (txt, html)", DefaultValue="html")]
public EmailFormat OutputEMailFormat = EmailFormat.HTML;
[IniProperty("OutputEMailFormat", Description="Default type for emails. (txt, html)")]
public EmailFormat OutputEMailFormat;
[IniProperty("OutputOutlookMethod", Description="How to export to outlook (AlwaysNew= always open a new one, TryOpenElseNew=look for open email else create a new)", DefaultValue="AlwaysNew")]
public EmailExport OutputOutlookMethod;
@ -107,27 +113,32 @@ namespace GreenshotPlugin.Core {
public int OutputFileJpegQuality;
[IniProperty("OutputFilePromptJpegQuality", Description="Ask for the JPEQ quality before saving?", DefaultValue="false")]
public bool OutputFilePromptJpegQuality;
[IniProperty("OutputFileIncrementingNumber", Description="The number for the %NUM% in the filename pattern, is increased automatically after each save.", DefaultValue="1")]
[IniProperty("OutputFileIncrementingNumber", Description="The number for the ${NUM} in the filename pattern, is increased automatically after each save.", DefaultValue="1")]
public uint OutputFileIncrementingNumber;
[IniProperty("OutputPrintPromptOptions", Description="Ask for print options when printing?", DefaultValue="true")]
[IniProperty("OutputPrintPromptOptions", LanguageKey="settings_alwaysshowprintoptionsdialog", Description="Ask for print options when printing?", DefaultValue="true")]
public bool OutputPrintPromptOptions;
[IniProperty("OutputPrintAllowRotate", Description="Allow rotating the picture for fitting on paper?", DefaultValue="true")]
[IniProperty("OutputPrintAllowRotate", LanguageKey="printoptions_allowrotate", Description="Allow rotating the picture for fitting on paper?", DefaultValue="true")]
public bool OutputPrintAllowRotate;
[IniProperty("OutputPrintAllowEnlarge", Description="Allow growing the picture for fitting on paper?", DefaultValue="true")]
[IniProperty("OutputPrintAllowEnlarge", LanguageKey="printoptions_allowenlarge", Description="Allow growing the picture for fitting on paper?", DefaultValue="true")]
public bool OutputPrintAllowEnlarge;
[IniProperty("OutputPrintAllowShrink", Description="Allow shrinking the picture for fitting on paper?", DefaultValue="true")]
[IniProperty("OutputPrintAllowShrink", LanguageKey="printoptions_allowshrink", Description="Allow shrinking the picture for fitting on paper?", DefaultValue="true")]
public bool OutputPrintAllowShrink;
[IniProperty("OutputPrintCenter", Description="Center image when printing?", DefaultValue="true")]
[IniProperty("OutputPrintCenter", LanguageKey="printoptions_allowcenter", Description="Center image when printing?", DefaultValue="true")]
public bool OutputPrintCenter;
[IniProperty("OutputPrintInverted", Description="Print image inverted (use e.g. for console captures)", DefaultValue="false")]
[IniProperty("OutputPrintInverted", LanguageKey="printoptions_inverted", Description="Print image inverted (use e.g. for console captures)", DefaultValue="false")]
public bool OutputPrintInverted;
[IniProperty("OutputPrintTimestamp", Description="Print timestamp on print?", DefaultValue="true")]
[IniProperty("OutputPrintTimestamp", LanguageKey="printoptions_timestamp", Description="Print timestamp on print?", DefaultValue="true")]
public bool OutputPrintTimestamp;
[IniProperty("UseProxy", Description="Use your global proxy?", DefaultValue="True")]
public bool UseProxy;
[IniProperty("IECapture", Description="Enable/disable IE capture", DefaultValue="True")]
public bool IECapture;
[IniProperty("IEFieldCapture", Description="Enable/disable IE field capture, very slow but will make it possible to annotate the fields of a capture in the editor.", DefaultValue="False")]
public bool IEFieldCapture;
[IniProperty("AutoCropDifference", Description="Sets how to compare the colors for the autocrop detection, the higher the more is 'selected'. Possible values are from 0 to 255, where everything above ~150 doesn't make much sense!", DefaultValue="10")]
public int AutoCropDifference;
[IniProperty("IncludePlugins", Description="Comma separated list of Plugins which are allowed. If something in the list, than every plugin not in the list will not be loaded!")]
public List<string> IncludePlugins;
@ -140,6 +151,78 @@ namespace GreenshotPlugin.Core {
[IniProperty("LastUpdateCheck", Description="Last update check")]
public DateTime LastUpdateCheck;
[IniProperty("ThumnailPreview", Description="Enable/disable thumbnail previews", DefaultValue="True")]
public bool ThumnailPreview;
[IniProperty("NoGDICaptureForProduct", Description="List of products for which GDI capturing doesn't work.", DefaultValue="IntelliJ IDEA")]
public List<string> NoGDICaptureForProduct;
[IniProperty("NoDWMCaptureForProduct", Description="List of products for which DWM capturing doesn't work.", DefaultValue="Citrix ICA Client")]
public List<string> NoDWMCaptureForProduct;
[IniProperty("OptimizeForRDP", Description="Make some optimizations for remote desktop usage", DefaultValue="False")]
public bool OptimizeForRDP;
[IniProperty("ActiveTitleFixes", Description="The fixes that are active.")]
public List<string> ActiveTitleFixes;
[IniProperty("TitleFixMatcher", Description="The regular expressions to match the title with.")]
public Dictionary<string, string> TitleFixMatcher;
[IniProperty("TitleFixReplacer", Description="The replacements for the matchers.")]
public Dictionary<string, string> TitleFixReplacer;
[IniProperty("ExperimentalFeatures", Description="A list which allows us to enable certain experimental features", ExcludeIfNull=true)]
public List<string> ExperimentalFeatures;
/// <summary>
/// A helper method which returns true if the supplied experimental feature is enabled
/// </summary>
/// <param name="experimentalFeature"></param>
/// <returns></returns>
public bool isExperimentalFeatureEnabled(string experimentalFeature) {
return (ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature));
}
/// <summary>
/// Helper method to check if it is allowed to capture the process using DWM
/// </summary>
/// <param name="process">Process owning the window</param>
/// <returns>true if it's allowed</returns>
public bool isDWMAllowed(Process process) {
if (process != null) {
if (NoDWMCaptureForProduct != null && NoDWMCaptureForProduct.Count > 0) {
try {
string productName = process.MainModule.FileVersionInfo.ProductName;
if (productName != null && NoDWMCaptureForProduct.Contains(productName.ToLower())) {
return false;
}
} catch {
}
}
}
return true;
}
/// <summary>
/// Helper method to check if it is allowed to capture the process using GDI
/// </summary>
/// <param name="processName">Process owning the window</param>
/// <returns>true if it's allowed</returns>
public bool isGDIAllowed(Process process) {
if (process != null) {
if (NoGDICaptureForProduct != null && NoGDICaptureForProduct.Count > 0) {
try {
string productName = process.MainModule.FileVersionInfo.ProductName;
if (productName != null && NoGDICaptureForProduct.Contains(productName.ToLower())) {
return false;
}
} catch {
}
}
}
return true;
}
// change to false for releases
public bool CheckUnstable = true;
@ -154,12 +237,51 @@ namespace GreenshotPlugin.Core {
case "PluginBacklist":
return new List<string>();
case "OutputFileAsFullpath":
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),"dummy.png");
if (IniConfig.IsPortable) {
return Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png");
} else {
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),"dummy.png");
}
case "OutputFilePath":
if (IniConfig.IsPortable) {
string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots");
if (!Directory.Exists(pafOutputFilePath)) {
try {
Directory.CreateDirectory(pafOutputFilePath);
return pafOutputFilePath;
} catch(Exception) {
// Problem creating directory, fallback to Desktop
}
} else {
return pafOutputFilePath;
}
}
return Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
case "DWMBackgroundColor":
return Color.White;
case "OutputEMailFormat":
if (EmailConfigHelper.HasOutlook()) {
return EmailFormat.OUTLOOK_HTML;
}
return EmailFormat.MAPI;
case "ActiveTitleFixes":
List<string> activeDefaults = new List<string>();
activeDefaults.Add("Firefox");
activeDefaults.Add("IE");
activeDefaults.Add("Chrome");
return activeDefaults;
case "TitleFixMatcher":
Dictionary<string, string> matcherDefaults = new Dictionary<string, string>();
matcherDefaults.Add("Firefox", " - Mozilla Firefox.*");
matcherDefaults.Add("IE", " - (Microsoft|Windows) Internet Explorer.*");
matcherDefaults.Add("Chrome", " - Google Chrome.*");
return matcherDefaults;
case "TitleFixReplacer":
Dictionary<string, string> replacerDefaults = new Dictionary<string, string>();
replacerDefaults.Add("Firefox", "");
replacerDefaults.Add("IE", "");
replacerDefaults.Add("Chrome", "");
return replacerDefaults;
}
return null;
}
@ -178,18 +300,51 @@ namespace GreenshotPlugin.Core {
return propertyValue.Replace('|',',');
}
}
if("OutputFilePath".Equals(propertyName)) {
if (string.IsNullOrEmpty(propertyValue)) {
return null;
}
}
return base.PreCheckValue(propertyName, propertyValue);
}
/// <summary>
/// This method will be called after reading the configuration, so eventually some corrections can be made
/// </summary>
public override void PostCheckValues() {
public override void AfterLoad() {
if (OutputDestinations == null) {
OutputDestinations = new List<Destination>();
OutputDestinations = new List<string>();
}
// Make sure there is an output!
if (OutputDestinations.Count == 0) {
OutputDestinations.Add(Destination.Editor);
OutputDestinations.Add("Editor");
}
// Check for Outlook, if it's not installed force email format to MAPI
if (OutputEMailFormat != EmailFormat.MAPI && !EmailConfigHelper.HasOutlook()) {
OutputEMailFormat = EmailFormat.MAPI;
}
// Prevent both settings at once, bug #3435056
if (OutputDestinations.Contains("Clipboard") && OutputFileCopyPathToClipboard) {
OutputFileCopyPathToClipboard = false;
}
// Make sure the lists are lowercase, to speedup the check
if (NoGDICaptureForProduct != null) {
for(int i=0; i< NoGDICaptureForProduct.Count; i++) {
NoGDICaptureForProduct[i] = NoGDICaptureForProduct[i].ToLower();
}
}
if (NoDWMCaptureForProduct != null) {
for(int i=0; i< NoDWMCaptureForProduct.Count; i++) {
NoDWMCaptureForProduct[i] = NoDWMCaptureForProduct[i].ToLower();
}
}
if (AutoCropDifference < 0) {
AutoCropDifference = 0;
}
if (AutoCropDifference > 255) {
AutoCropDifference = 255;
}
}
}

View file

@ -20,7 +20,6 @@
*/
using System;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

View file

@ -0,0 +1,38 @@
/*
* 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 GreenshotPlugin.Core {
[AttributeUsage(AttributeTargets.Field)]
public sealed class DisplayKeyAttribute : Attribute {
private readonly string value;
public string Value {
get { return value; }
}
public DisplayKeyAttribute(string v) {
this.value = v;
}
public DisplayKeyAttribute() {
}
}
}

View file

@ -0,0 +1,84 @@
/*
* 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.IO;
using Microsoft.Win32;
namespace GreenshotPlugin.Core {
/// <summary>
/// Description of EmailConfigHelper.
/// </summary>
public static class EmailConfigHelper {
private const string OUTLOOK_PATH_KEY = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE";
private const string MAPI_CLIENT_KEY = @"SOFTWARE\Clients\Mail";
private const string MAPI_LOCATION_KEY = @"SOFTWARE\Microsoft\Windows Messaging Subsystem";
private const string MAPI_KEY = @"MAPI";
public static string GetMapiClient() {
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(MAPI_CLIENT_KEY, false)) {
if (key != null) {
return (string)key.GetValue("");
}
}
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(MAPI_CLIENT_KEY, false)) {
if (key != null) {
return (string)key.GetValue("");
} else {
return null;
}
}
}
public static bool HasMAPI() {
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(MAPI_LOCATION_KEY, false)) {
if (key != null) {
return "1".Equals(key.GetValue(MAPI_KEY, "0"));
} else {
return false;
}
}
}
public static string GetOutlookExePath() {
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(OUTLOOK_PATH_KEY, false)) {
if (key != null) {
// "" is the default key, which should point to the outlook location
return (string)key.GetValue("");
}
}
return null;
}
/// <summary>
/// Check if Outlook is installed
/// </summary>
/// <returns>Returns true if outlook is installed</returns>
public static bool HasOutlook() {
string outlookPath = GetOutlookExePath();
if (outlookPath != null) {
if (File.Exists(outlookPath)) {
return true;
}
}
return false;
}
}
}

View file

@ -0,0 +1,90 @@
/*
* 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 GreenshotPlugin.Core {
public static class EnumerationExtensions {
public static bool Has<T>(this System.Enum type, T value) {
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
try {
if (underlyingType == typeof(int)) {
return (((int)(object)type & (int)(object)value) == (int)(object)value);
} else if (underlyingType == typeof(uint)) {
return (((uint)(object)type & (uint)(object)value) == (uint)(object)value);
}
} catch {
}
return false;
}
public static bool Is<T>(this System.Enum type, T value) {
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
try {
if (underlyingType == typeof(int)) {
return (int)(object)type == (int)(object)value;
} else if (underlyingType == typeof(uint)) {
return (uint)(object)type == (uint)(object)value;
}
} catch {
}
return false;
}
/// <summary>
/// Add a flag to an enum
/// </summary>
/// <param name="type"></param>
/// <param name="value"></param>
/// <returns></returns>
public static T Add<T>(this System.Enum type, T value) {
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
try {
if (underlyingType == typeof(int)) {
return (T)(object)(((int)(object)type | (int)(object)value));
} else if (underlyingType == typeof(uint)) {
return (T)(object)(((uint)(object)type | (uint)(object)value));
}
} catch(Exception ex) {
throw new ArgumentException(string.Format("Could not append value '{0}' to enumerated type '{1}'.", value, typeof(T).Name), ex);
}
throw new ArgumentException(string.Format("Could not append value '{0}' to enumerated type '{1}'.", value, typeof(T).Name));
}
/// <summary>
/// Remove a flag from an enum type
/// </summary>
/// <param name="type"></param>
/// <param name="value"></param>
/// <returns></returns>
public static T Remove<T>(this System.Enum type, T value) {
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
try {
if (underlyingType == typeof(int)) {
return (T)(object)(((int)(object)type & ~(int)(object)value));
} else if (underlyingType == typeof(uint)) {
return (T)(object)(((uint)(object)type & ~(uint)(object)value));
}
} catch(Exception ex) {
throw new ArgumentException(string.Format("Could not remove value '{0}' from enumerated type '{1}'.", value, typeof(T).Name), ex);
}
throw new ArgumentException(string.Format("Could not remove value '{0}' from enumerated type '{1}'.", value, typeof(T).Name));
}
}
}

View file

@ -0,0 +1,27 @@
/*
* 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 System.Runtime.CompilerServices {
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
public sealed class ExtensionAttribute : Attribute {}
}

View file

@ -26,7 +26,7 @@ namespace GreenshotPlugin.Core {
/// <summary>
/// Centralized storage of the icons & bitmaps
/// </summary>
public class GreenshotResources {
public static class GreenshotResources {
private static ComponentResourceManager greenshotResources = new ComponentResourceManager(typeof(GreenshotResources));
public static Image getImage(string imageName) {

View file

@ -19,13 +19,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using Microsoft.Win32;
namespace GreenshotPlugin.Core {
/// <summary>
/// Description of IEHelper.
/// </summary>
public class IEHelper {
public static class IEHelper {
// Internet explorer Registry key
private const string IE_KEY = @"Software\Microsoft\Internet Explorer";
/// <summary>
@ -33,20 +34,65 @@ namespace GreenshotPlugin.Core {
/// </summary>
/// <returns></returns>
public static int IEVersion() {
int version = 7;
int version = 7;
// Seeing if IE 9 is used, here we need another offset!
using (RegistryKey ieKey = Registry.LocalMachine.OpenSubKey(IE_KEY, false)) {
if (ieKey != null) {
object versionKey = ieKey.GetValue("Version");
if (versionKey != null) {
int.TryParse(versionKey.ToString().Substring(0,1), out version);
}
}
if (ieKey != null) {
object versionKey = ieKey.GetValue("Version");
if (versionKey != null) {
int.TryParse(versionKey.ToString().Substring(0,1), out version);
}
}
}
return version;
return version;
}
/// <summary>
/// Find the DirectUI window for MSAA (Accessible)
/// </summary>
/// <param name="browserWindowDetails">The browser WindowDetails</param>
/// <returns>WindowDetails for the DirectUI window</returns>
public static WindowDetails GetDirectUI(WindowDetails browserWindowDetails) {
WindowDetails tmpWD = browserWindowDetails;
// Since IE 9 the TabBandClass is less deep!
if (IEHelper.IEVersion() < 9) {
tmpWD = tmpWD.GetChild("CommandBarClass");
if (tmpWD != null) {
tmpWD = tmpWD.GetChild("ReBarWindow32");
}
}
if (tmpWD != null) {
tmpWD = tmpWD.GetChild("TabBandClass");
}
if (tmpWD != null) {
tmpWD = tmpWD.GetChild("DirectUIHWND");;
}
return tmpWD;
}
/// <summary>
/// Return an IEnumerable with the currently opened IE urls
/// </summary>
/// <returns></returns>
public static IEnumerable<string> GetIEUrls() {
List<string> urls = new List<string>();
// Find the IE window
foreach (WindowDetails ieWindow in WindowDetails.GetAllWindows("IEFrame")) {
WindowDetails directUIWD = GetDirectUI(ieWindow);
if (directUIWD != null) {
Accessible ieAccessible = new Accessible(directUIWD.Handle);
List<string> ieUrls = ieAccessible.IETabUrls;
if (ieUrls != null && ieUrls.Count > 0) {
foreach(string url in ieUrls) {
if (!urls.Contains(url)) {
urls.Add(url);
}
}
}
}
}
private IEHelper() {
return urls;
}
}
}

View file

@ -0,0 +1,301 @@
/*
* 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.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Drawing.Drawing2D;
using GreenshotPlugin.UnmanagedHelpers;
using GreenshotPlugin.Core;
using IniFile;
namespace GreenshotPlugin.Core {
/// <summary>
/// Description of ImageHelper.
/// </summary>
public static class ImageHelper {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ImageHelper));
private static CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight) {
return CreateThumbnail(image, thumbWidth, thumbHeight, -1, -1);
}
public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight, int maxWidth, int maxHeight) {
int srcWidth=image.Width;
int srcHeight=image.Height;
if (thumbHeight < 0) {
thumbHeight = (int)(thumbWidth * ((float)srcHeight / (float)srcWidth));
}
if (thumbWidth < 0) {
thumbWidth = (int)(thumbHeight * ((float)srcWidth / (float)srcHeight));
}
if (maxWidth > 0 && thumbWidth > maxWidth) {
thumbWidth = Math.Min(thumbWidth, maxWidth);
thumbHeight = (int)(thumbWidth * ((float)srcHeight / (float)srcWidth));
}
if (maxHeight > 0 && thumbHeight > maxHeight) {
thumbHeight = Math.Min(thumbHeight, maxHeight);
thumbWidth = (int)(thumbHeight * ((float)srcWidth / (float)srcHeight));
}
Bitmap bmp = new Bitmap(thumbWidth, thumbHeight);
using (Graphics gr = System.Drawing.Graphics.FromImage(bmp)) {
gr.SmoothingMode = SmoothingMode.HighQuality ;
gr.CompositingQuality = CompositingQuality.HighQuality;
gr.InterpolationMode = InterpolationMode.High;
System.Drawing.Rectangle rectDestination = new System.Drawing.Rectangle(0, 0, thumbWidth, thumbHeight);
gr.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel);
}
return bmp;
}
/// <summary>
/// Crops the image to the specified rectangle
/// </summary>
/// <param name="image">Image to crop</param>
/// <param name="cropRectangle">Rectangle with bitmap coordinates, will be "intersected" to the bitmap</param>
public static bool Crop(ref Image image, ref Rectangle cropRectangle) {
Image returnImage = null;
if (image != null && image is Bitmap && ((image.Width * image.Height) > 0)) {
cropRectangle.Intersect(new Rectangle(0,0, image.Width, image.Height));
if (cropRectangle.Width != 0 || cropRectangle.Height != 0) {
returnImage = (image as Bitmap).Clone(cropRectangle, image.PixelFormat);
image.Dispose();
image = returnImage;
return true;
}
}
LOG.Warn("Can't crop a null/zero size image!");
return false;
}
private static Rectangle FindAutoCropRectangle(BitmapBuffer buffer, Point colorPoint) {
Rectangle cropRectangle = Rectangle.Empty;
Color referenceColor = buffer.GetColorAtWithoutAlpha(colorPoint.X,colorPoint.Y);
Point min = new Point(int.MaxValue, int.MaxValue);
Point max = new Point(int.MinValue, int.MinValue);
if (conf.AutoCropDifference > 0) {
for(int y = 0; y < buffer.Height; y++) {
for(int x = 0; x < buffer.Width; x++) {
Color currentColor = buffer.GetColorAt(x, y);
int diffR = Math.Abs(currentColor.R - referenceColor.R);
int diffG = Math.Abs(currentColor.G - referenceColor.G);
int diffB = Math.Abs(currentColor.B - referenceColor.B);
if (((diffR+diffG+diffB)/3) > conf.AutoCropDifference) {
if (x < min.X) min.X = x;
if (y < min.Y) min.Y = y;
if (x > max.X) max.X = x;
if (y > max.Y) max.Y = y;
}
}
}
} else {
for(int y = 0; y < buffer.Height; y++) {
for(int x = 0; x < buffer.Width; x++) {
Color currentColor = buffer.GetColorAtWithoutAlpha(x, y);
if (referenceColor.Equals(currentColor)) {
if (x < min.X) min.X = x;
if (y < min.Y) min.Y = y;
if (x > max.X) max.X = x;
if (y > max.Y) max.Y = y;
}
}
}
}
if (!(Point.Empty.Equals(min) && max.Equals(new Point(buffer.Width-1, buffer.Height-1)))) {
if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) {
cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1);
}
}
return cropRectangle;
}
/// <summary>
/// Get a rectangle for the image which crops the image of all colors equal to that on 0,0
/// </summary>
/// <param name="image"></param>
/// <returns>Rectangle</returns>
public static Rectangle FindAutoCropRectangle(Image image) {
Rectangle cropRectangle = Rectangle.Empty;
using (BitmapBuffer buffer = new BitmapBuffer((Bitmap)image, false)) {
buffer.Lock();
Rectangle currentRectangle = Rectangle.Empty;
List<Point> checkPoints = new List<Point>();
// Top Left
checkPoints.Add(new Point(0, 0));
// Bottom Left
checkPoints.Add(new Point(0, image.Height-1));
// Top Right
checkPoints.Add(new Point(image.Width-1, 0));
// Bottom Right
checkPoints.Add( new Point(image.Width-1, image.Height-1));
// find biggest area
foreach(Point checkPoint in checkPoints) {
currentRectangle = FindAutoCropRectangle(buffer, checkPoint);
if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) {
cropRectangle = currentRectangle;
}
}
}
return cropRectangle;
}
public static Bitmap LoadBitmap(string filename) {
if (string.IsNullOrEmpty(filename)) {
return null;
}
Bitmap fileBitmap = null;
LOG.InfoFormat("Loading image from file {0}", filename);
// Fixed lock problem Bug #3431881
using (Stream imageFileStream = File.OpenRead(filename)) {
// And fixed problem that the bitmap stream is disposed... by Cloning the image
// This also ensures the bitmap is correctly created
if (filename.EndsWith(".ico")) {
// Icon logic, try to get the Vista icon, else the biggest possible
try {
using (Image tmpImage = ExtractVistaIcon(imageFileStream)) {
if (tmpImage != null) {
fileBitmap = CloneImageToBitmap(tmpImage);
}
}
} catch (Exception vistaIconException) {
LOG.Warn("Can't read icon from " + filename, vistaIconException);
}
if (fileBitmap == null) {
try {
// No vista icon, try normal icon
imageFileStream.Position = 0;
// We create a copy of the bitmap, so everything else can be disposed
using (Icon tmpIcon = new Icon(imageFileStream, new Size(1024,1024))) {
using (Image tmpImage = tmpIcon.ToBitmap()) {
fileBitmap = ImageHelper.CloneImageToBitmap(tmpImage);
}
}
} catch (Exception iconException) {
LOG.Warn("Can't read icon from " + filename, iconException);
}
}
}
if (fileBitmap == null) {
// We create a copy of the bitmap, so everything else can be disposed
imageFileStream.Position = 0;
using (Image tmpImage = Image.FromStream(imageFileStream, true, true)) {
fileBitmap = ImageHelper.CloneImageToBitmap(tmpImage);
}
}
}
return fileBitmap;
}
/// <summary>
/// Clone the image to a bitmap
/// </summary>
/// <param name="srcImage">Image to clone</param>
/// <returns>Bitmap</returns>
public static Bitmap CloneImageToBitmap(Image srcImage) {
Bitmap returnImage;
int width = srcImage.Width;
int height = srcImage.Height;
float horizontalResolution = srcImage.HorizontalResolution;
float verticalResolution = srcImage.VerticalResolution;
PixelFormat pixelFormat = srcImage.PixelFormat;
if (srcImage is Metafile) {
pixelFormat = PixelFormat.Format32bppArgb;
}
// Make sure Greenshot supports the pixelformat, if not convert to one we support
if (!isSupported(pixelFormat)) {
pixelFormat = PixelFormat.Format24bppRgb;
}
returnImage = new Bitmap(width, height, pixelFormat);
returnImage.SetResolution(horizontalResolution, verticalResolution);
using (Graphics graphics = Graphics.FromImage(returnImage)) {
if (Image.IsAlphaPixelFormat(pixelFormat)) {
graphics.Clear(Color.Transparent);
} else {
graphics.Clear(Color.White);
}
graphics.DrawImageUnscaled(srcImage, 0, 0);
}
return returnImage;
}
/**
* Checks if we support the supplied PixelFormat
*/
private static bool isSupported(PixelFormat pixelformat) {
return (PixelFormat.Format32bppArgb.Equals(pixelformat)||
PixelFormat.Format32bppRgb.Equals(pixelformat) ||
PixelFormat.Format24bppRgb.Equals(pixelformat));
}
// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx
// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx
public static Bitmap ExtractVistaIcon(Stream iconStream) {
const int SizeICONDIR = 6;
const int SizeICONDIRENTRY = 16;
Bitmap bmpPngExtracted = null;
try {
byte[] srcBuf = new byte[iconStream.Length];
iconStream.Read(srcBuf, 0, (int)iconStream.Length);
int iCount = BitConverter.ToInt16(srcBuf, 4);
for (int iIndex=0; iIndex<iCount; iIndex++) {
int iWidth = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex];
int iHeight = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex + 1];
int iBitCount = BitConverter.ToInt16(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 6);
if (iWidth == 0 && iHeight == 0) {
int iImageSize = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 8);
int iImageOffset = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 12);
using (MemoryStream destStream = new MemoryStream()) {
using (BinaryWriter writer = new BinaryWriter(destStream)) {
writer.Write(srcBuf, iImageOffset, iImageSize);
destStream.Seek(0, System.IO.SeekOrigin.Begin);
bmpPngExtracted = new Bitmap(destStream); // This is PNG! :)
}
}
break;
}
}
} catch {
return null;
}
return bmpPngExtracted;
}
public static Icon ExtractAssociatedIcon(this Icon icon, string location) {
IntPtr large;
IntPtr small;
Shell32.ExtractIconEx(location, 0, out large, out small, 1);
Icon returnIcon = Icon.FromHandle(small);
if (!IntPtr.Zero.Equals(small)){
User32.DestroyIcon(small);
}
if (!IntPtr.Zero.Equals(large)){
User32.DestroyIcon(large);
}
return returnIcon;
}
}
}

View file

@ -0,0 +1,73 @@
/*
* 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.Threading;
using System.Reflection;
using System.Collections.Generic;
using Greenshot.Plugin;
namespace GreenshotPlugin.Core {
/// <summary>
/// Description of InterfaceUtils.
/// </summary>
public static class InterfaceUtils {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(InterfaceUtils));
public static List<Type> GetSubclassesOf(Type type, bool excludeSystemTypes) {
List<Type> list = new List<Type>();
foreach(Assembly currentAssembly in Thread.GetDomain().GetAssemblies()) {
try {
Type[] types = currentAssembly.GetTypes();
if (!excludeSystemTypes || (excludeSystemTypes && !currentAssembly.FullName.StartsWith("System."))) {
foreach(Type currentType in types) {
if (type.IsInterface) {
if (currentType.GetInterface(type.FullName) != null) {
list.Add(currentType);
}
} else if (currentType.IsSubclassOf(type)) {
list.Add(currentType);
}
}
}
} catch {
}
}
return list;
}
public static List<IProcessor> GetProcessors() {
List<IProcessor> processors = new List<IProcessor>();
foreach(Type processorType in GetSubclassesOf(typeof(IProcessor), true)) {
if (!processorType.IsAbstract) {
IProcessor processor = (IProcessor)Activator.CreateInstance(processorType);
if (processor.isActive) {
LOG.DebugFormat("Found processor {0} with designation {1}", processorType.Name, processor.Designation);
processors.Add(processor);
} else {
LOG.DebugFormat("Ignoring processor {0} with designation {1}", processorType.Name, processor.Designation);
}
}
}
return processors;
}
}
}

View file

@ -22,17 +22,24 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using IniFile;
using Microsoft.Win32;
namespace GreenshotPlugin.Core {
public interface ILanguage {
void Load();
bool hasKey(Enum key);
bool hasKey(string key);
string GetString(Enum id);
string GetString(string id);
string GetFormattedString(Enum id, object param);
string GetFormattedString(string id, object param);
string GetHelpFilePath();
/// <summary>
@ -42,6 +49,8 @@ namespace GreenshotPlugin.Core {
/// <returns>Actuall IETF </returns>
string SetLanguage(string cultureInfo);
void SynchronizeLanguageToCulture();
void FreeResources();
string CurrentLanguage {
get;
}
@ -58,7 +67,6 @@ namespace GreenshotPlugin.Core {
LanguageConfiguration CurrentLanguageConfiguration {
get;
}
}
/// <summary>
/// Description of Language.
@ -68,13 +76,36 @@ namespace GreenshotPlugin.Core {
private static char [] TRIMCHARS = new char[] {' ', '\t', '\n', '\r'};
private const string DEFAULT_LANGUAGE= "en-US";
private static string APPLICATIONDATA_LANGUAGE_PATH = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),@"Greenshot\Languages\");
private static string STARTUP_LANGUAGE_PATH = Path.Combine(Application.StartupPath, @"Languages\");
private static string APPLICATION_PATH = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
private static string STARTUP_LANGUAGE_PATH = Path.Combine(APPLICATION_PATH, @"Languages");
private static string PAF_LANGUAGE_PATH = Path.Combine(APPLICATION_PATH, @"App\Greenshot\Languages");
private const string HELP_FILENAME_PATTERN = @"help-*.html";
private const string LANGUAGE_GROUPS_KEY = @"SYSTEM\CurrentControlSet\Control\Nls\Language Groups";
private Dictionary<string, string> strings = new Dictionary<string, string>();
private List<LanguageConfiguration> languages = new List<LanguageConfiguration>();
private string currentIETF = null;
private string languageFilePattern;
private static List<string> supportedLanguageGroups = new List<string>();
static LanguageContainer() {
try {
using (RegistryKey languageGroupsKey = Registry.LocalMachine.OpenSubKey(LANGUAGE_GROUPS_KEY, false)) {
if (languageGroupsKey != null) {
string [] groups = languageGroupsKey.GetValueNames();
foreach(string group in groups) {
string groupValue = (string)languageGroupsKey.GetValue(group);
bool isGroupInstalled = "1".Equals(groupValue);
if (isGroupInstalled) {
supportedLanguageGroups.Add(group.ToLower());
}
}
}
}
} catch(Exception e) {
LOG.Warn("Couldn't read the installed language groups.", e);
}
}
public LanguageContainer() {
}
@ -129,7 +160,7 @@ namespace GreenshotPlugin.Core {
public string SetLanguage(string wantedIETF) {
LOG.Debug("SetLanguage called for : " + wantedIETF);
Dictionary<string, LanguageConfiguration> identifiedLanguages = new Dictionary<string, LanguageConfiguration>();
if (languages == null || languages.Count == 0) {
throw new FileNotFoundException("No language files found!");
}
@ -137,7 +168,11 @@ namespace GreenshotPlugin.Core {
// Find selected languages in available languages
foreach(LanguageConfiguration language in languages) {
LOG.Debug("Found language: " + language.Ietf);
identifiedLanguages.Add(language.Ietf, language);
if (!identifiedLanguages.ContainsKey(language.Ietf)) {
identifiedLanguages.Add(language.Ietf, language);
} else {
LOG.WarnFormat("Found double language file: {0}", language.File);
}
}
LanguageConfiguration selectedLanguage = null;
@ -181,12 +216,23 @@ namespace GreenshotPlugin.Core {
foreach(Resource resource in selectedLanguage.Resources) {
AddResource(resource);
}
// Make sure we have all the missing resources, right after setting the language
// this way we can free all other resources.
AdoptMissingResourcesFromDefaultLanguage();
currentIETF = selectedLanguage.Ietf;
Thread.CurrentThread.CurrentUICulture = new CultureInfo(currentIETF);
return currentIETF;
}
/// <summary>
/// Free all language resources which aren't needed
/// </summary>
public void FreeResources() {
languages = null;
}
private void AddResource(Resource resource) {
try {
@ -205,18 +251,32 @@ namespace GreenshotPlugin.Core {
private List<LanguageConfiguration> LoadFiles(string languageFilePattern) {
List<LanguageConfiguration> loadedLanguages = new List<LanguageConfiguration>();
List<string> languageDirectories = new List<string>();
if (IniConfig.IsPortable) {
languageDirectories.Add(PAF_LANGUAGE_PATH);
} else {
languageDirectories.Add(APPLICATIONDATA_LANGUAGE_PATH);
}
languageDirectories.Add(STARTUP_LANGUAGE_PATH);
languageDirectories.Add(APPLICATIONDATA_LANGUAGE_PATH);
foreach(string path in languageDirectories) {
// Search in executable directory
if (Directory.Exists(path)) {
LOG.DebugFormat("Searching language directory '{0}' for language files with pattern '{1}'", path, languageFilePattern);
try {
foreach(string languageFile in Directory.GetFiles(path, languageFilePattern, SearchOption.AllDirectories)) {
LOG.DebugFormat("Found language file: {0}", languageFile);
LanguageConfiguration languageConfig = LanguageConfiguration.Load(languageFile);
if (languageConfig != null) {
LOG.Info("Loaded language: " + languageConfig.Description);
loadedLanguages.Add(languageConfig);
if (string.IsNullOrEmpty(languageConfig.LanguageGroup) || supportedLanguageGroups.Contains(languageConfig.LanguageGroup)) {
LOG.InfoFormat("Loaded language: {0}", languageConfig.Description);
loadedLanguages.Add(languageConfig);
} else {
LOG.InfoFormat("Skipping unsupported language: {0}", languageConfig.Description);
}
}
}
} catch (DirectoryNotFoundException) {
LOG.InfoFormat("Non existing language directory: {0}", path);
} catch (Exception e) {
LOG.Error("Error trying for read directory " + path, e);
}
}
return loadedLanguages;
@ -289,26 +349,36 @@ namespace GreenshotPlugin.Core {
EnumClass.AppendLine("}");
LOG.Debug("LangKeys should be: \r\n" + EnumClass.ToString());
}
public bool hasKey(Enum key) {
return hasKey(key.ToString());
}
public string GetString(Enum id) {
if(!strings.ContainsKey(id.ToString())) {
AdoptMissingResourcesFromDefaultLanguage();
}
public bool hasKey(string key) {
return strings.ContainsKey(key);
}
public string GetString(Enum key) {
return GetString(key.ToString());
}
public string GetString(string key) {
try {
return strings[id.ToString()];
return strings[key];
} catch (KeyNotFoundException) {
return "string ###"+id+"### not found";
return "string ###"+key+"### not found";
}
}
public string GetFormattedString(Enum id, object param) {
if(!strings.ContainsKey(id.ToString())) {
AdoptMissingResourcesFromDefaultLanguage();
}
public string GetFormattedString(Enum key, object param) {
return GetFormattedString(key.ToString(), param);
}
public string GetFormattedString(string key, object param) {
try {
return String.Format(strings[id.ToString()], param);
return String.Format(strings[key], param);
} catch (KeyNotFoundException) {
return "string ###"+id+"### not found";
return "string ###"+key+"### not found";
}
}
@ -399,6 +469,16 @@ namespace GreenshotPlugin.Core {
}
}
public string languageGroup;
public string LanguageGroup {
get {
return languageGroup;
}
set {
languageGroup = value;
}
}
public string file;
public string File {
get {
@ -431,6 +511,10 @@ namespace GreenshotPlugin.Core {
ret.Description = node.Attributes["description"].Value;
ret.Ietf = node.Attributes["ietf"].Value;
ret.Version = node.Attributes["version"].Value;
if (node.Attributes["languagegroup"] != null) {
string languageGroup = node.Attributes["languagegroup"].Value;
ret.LanguageGroup = languageGroup.ToLower();
}
XmlNodeList resourceNodes = doc.GetElementsByTagName("resource");
ret.Resources = new List<Resource>(resourceNodes.Count);

View file

@ -0,0 +1,61 @@
/*
* 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.IO;
using System.Windows.Forms;
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Repository.Hierarchy;
namespace GreenshotPlugin.Core {
/// <summary>
/// Description of LogHelper.
/// </summary>
public class LogHelper {
private const string LOG4NET_FILE = "log4net.xml";
// Initialize Log4J
public static string InitializeLog4NET() {
// Setup log4j, currently the file is called log4net.xml
string pafLog4NetFilename = Path.Combine(Application.StartupPath, @"App\Greenshot\" + LOG4NET_FILE);
string log4netFilename = Path.Combine(Application.StartupPath, LOG4NET_FILE);
if (File.Exists(log4netFilename)) {
XmlConfigurator.Configure(new FileInfo(log4netFilename));
} else if (File.Exists(pafLog4NetFilename)) {
XmlConfigurator.Configure(new FileInfo(pafLog4NetFilename));
} else {
MessageBox.Show("Can't find file " + LOG4NET_FILE);
}
// Get the logfile
try {
IAppender appender = ((Hierarchy)LogManager.GetRepository()).Root.Appenders[0];
if (appender is FileAppender) {
return ((FileAppender)appender).File;
}
} catch (Exception) {
// Ignore
}
return null;
}
}
}

View file

@ -24,11 +24,13 @@ using System.IO;
using System.Net;
using System.Text;
using IniFile;
namespace GreenshotPlugin.Core {
/// <summary>
/// Description of NetworkHelper.
/// </summary>
public class NetworkHelper {
public static class NetworkHelper {
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(NetworkHelper));
private static CoreConfiguration config = IniConfig.GetIniSection<CoreConfiguration>();
@ -64,8 +66,9 @@ namespace GreenshotPlugin.Core {
HttpWebRequest request = (HttpWebRequest)NetworkHelper.CreatedWebRequest(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (request.HaveResponse) {
Image image = Image.FromStream(response.GetResponseStream());
return (image.Height > 16 && image.Width > 16) ? new Bitmap(image, 16, 16) : new Bitmap(image);
using (Image image = Image.FromStream(response.GetResponseStream())) {
return (image.Height > 16 && image.Width > 16) ? new Bitmap(image, 16, 16) : new Bitmap(image);
}
}
} catch (Exception e) {

View file

@ -0,0 +1,84 @@
/*
* 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.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace GreenshotPlugin.Core {
public static class Objects {
/// <summary>
/// Perform a deep Copy of the object.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T Clone<T>(this T source) {
if (!typeof(T).IsSerializable) {
throw new ArgumentException("The type must be serializable.", "source");
}
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null)) {
return default(T);
}
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream) {
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
public static void CloneTo<T>(this T source, T destination) {
Type type = typeof(T);
FieldInfo[] myObjectFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
foreach (FieldInfo fi in myObjectFields) {
fi.SetValue(destination, fi.GetValue(source));
}
PropertyInfo[] myObjectProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo pi in myObjectProperties) {
pi.SetValue(destination, pi.GetValue(source, null), null);
}
}
public static bool CompareLists<T>(IList<T> l1, IList<T> l2) {
if (l1.Count != l2.Count) {
return false;
}
int matched = 0;
foreach(T item in l1) {
if (!l2.Contains(item)) {
return false;
}
matched++;
}
return matched == l1.Count;
}
}
}

View file

@ -19,17 +19,37 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Drawing;
using System.Windows.Forms;
using Greenshot.Plugin;
namespace GreenshotPlugin.Core {
/// <summary>
/// Description of PluginUtils.
/// </summary>
public class PluginUtils {
private PluginUtils() {
}
public static class PluginUtils {
/// <summary>
/// Helper method to add a MenuItem to the File MenuItem of an ImageEditor
/// </summary>
/// <param name="image">Image to display in the menu</param>
/// <param name="text">Text to display in the menu</param>
/// <param name="tag">The TAG value</param>
/// <param name="shortcutKeys">Keys which can be used as shortcut</param>
/// <param name="handler">The onclick handler</param>
public static void AddToFileMenu(IImageEditor imageEditor, Image image, string text, object tag, Keys? shortcutKeys, System.EventHandler handler) {
System.Windows.Forms.ToolStripMenuItem item = new System.Windows.Forms.ToolStripMenuItem();
item.Image = image;
item.Text = text;
item.Tag = tag;
if (shortcutKeys.HasValue) {
item.ShortcutKeys = shortcutKeys.Value;
}
item.Click += handler;
AddToFileMenu(imageEditor, item);
}
/// <summary>
/// Helper method to add a MenuItem to the File MenuItem of an ImageEditor
/// </summary>
@ -69,5 +89,28 @@ namespace GreenshotPlugin.Core {
toolStripMenuItem.DropDownItems.Add(item);
}
}
/// <summary>
/// Helper method to add a MenuItem to the Greenshot context menu
/// </summary>
/// <param name="imageEditor"></param>
/// <param name="item"></param>
public static void AddToContextMenu(IGreenshotHost host, ToolStripMenuItem item) {
// Here we can hang ourselves to the main context menu!
ContextMenuStrip contextMenu = host.MainMenu;
bool addedItem = false;
// Try to find a separator, so we insert ourselves after it
for(int i=0; i < contextMenu.Items.Count; i++) {
if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) {
contextMenu.Items.Insert(i+1, item);
addedItem = true;
break;
}
}
// If we didn't insert the item, we just add it...
if (!addedItem) {
contextMenu.Items.Add(item);
}
}
}
}

View file

@ -1,124 +0,0 @@
/*
* 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.IO;
namespace GreenshotPlugin.Core {
/// <summary>
/// A Class to representate a simple "java" properties file
/// </summary>
public class Properties : Dictionary<string, string >{
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(Properties));
public string GetProperty(string key) {
try {
return this[key];
} catch (KeyNotFoundException) {
return null;
}
}
/// <summary>
/// Split property with ',' and return the splitted string as a string[]
/// </summary>
public string[] GetPropertyAsArray(string key) {
try {
string array = this[key];
return array.Split(new Char[] {','});
} catch (KeyNotFoundException) {
return null;
}
}
public bool GetBoolProperty(string key) {
if (this.ContainsKey(key)) {
return bool.Parse(this[key]);
}
return false;
}
public uint GetUIntProperty(string key) {
return uint.Parse(this[key]);
}
public int GetIntProperty(string key) {
return int.Parse(this[key]);
}
public void AddProperty(string key, string value) {
Add(key, value);
}
public void AddBoolProperty(string key, bool value) {
AddProperty(key, value.ToString());
}
public void ChangeProperty(string key, string value) {
if (this.ContainsKey(key)) {
this[key] = value;
} else {
throw new KeyNotFoundException(key);
}
}
public void ChangeBoolProperty(string key, bool value) {
ChangeProperty(key, value.ToString());
}
public void write(string filename) {
using ( TextWriter textWriter = new StreamWriter(filename)) {
foreach(string key in Keys) {
textWriter.WriteLine(key +"=" + this[key]);
}
}
}
public void write(string filename, string header) {
using ( TextWriter textWriter = new StreamWriter(filename)) {
if (header != null) {
textWriter.WriteLine(header);
}
foreach(string key in Keys) {
textWriter.WriteLine(key +"=" + this[key]);
}
}
}
// Read properties file
public static Properties read(string filename) {
LOG.Debug("Reading properties from file: " + filename);
if (!File.Exists(filename)) {
return null;
}
Properties properties = new Properties();
foreach (string line in File.ReadAllLines(filename)) {
if (line == null) {
continue;
}
string currentLine = line.Trim();
if (!currentLine.StartsWith("#") && currentLine.IndexOf('=') > 0) {
string [] split = currentLine.Split(new Char[] {'='}, 2);
if (split != null && split.Length == 2) {
string name = split[0];
if (name == null || name.Length < 1) {
continue;
}
properties.Add(name.Trim(), split[1]);
}
}
}
return properties;
}
}
}

View file

@ -0,0 +1,182 @@
/*
* 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.Globalization;
using System.Net;
using System.Text.RegularExpressions;
using System.Xml;
namespace GreenshotPlugin.Core {
public class SourceforgeFile {
private string file;
public string File {
get {return file;}
}
private DateTime pubdate;
public DateTime Pubdate {
get {return pubdate;}
}
private string link;
public string Link {
get {return link;}
}
private string directLink;
public string DirectLink {
get {return directLink;}
}
private Version version;
public Version Version {
get {return version;}
set {
version = value;
}
}
private string language;
public string Language {
get {return language;}
set {language = value;}
}
public SourceforgeFile(string file, string pubdate, string link, string directLink) {
this.file = file;
this.pubdate = DateTime.Parse(pubdate);
this.link = link;
this.directLink = directLink;
}
}
/// <summary>
/// Description of SourceForgeHelper.
/// </summary>
public class SourceForgeHelper {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(SourceForgeHelper));
private const String RSSFEED = "http://sourceforge.net/api/file/index/project-id/191585/mtime/desc/rss";
/// <summary>
/// Read the Greenshot RSS feed, so we can use this information to check for updates
/// </summary>
/// <returns>Dictionary<string, Dictionary<string, RssFile>> with files and their RssFile "description"</returns>
public static Dictionary<string, Dictionary<string, SourceforgeFile>> readRSS() {
HttpWebRequest webRequest;
XmlDocument rssDoc = new XmlDocument();
try {
webRequest = (HttpWebRequest)GreenshotPlugin.Core.NetworkHelper.CreatedWebRequest(RSSFEED);
XmlTextReader rssReader = new XmlTextReader(webRequest.GetResponse().GetResponseStream());
// Load the XML content into a XmlDocument
rssDoc.Load(rssReader);
} catch (Exception wE) {
LOG.WarnFormat("Problem reading RSS from {0}", RSSFEED);
LOG.Warn(wE.Message);
return null;
}
// Loop for the <rss> tag
XmlNode nodeRss = null;
for (int i = 0; i < rssDoc.ChildNodes.Count; i++) {
// If it is the rss tag
if (rssDoc.ChildNodes[i].Name == "rss") {
// <rss> tag found
nodeRss = rssDoc.ChildNodes[i];
}
}
if (nodeRss == null) {
LOG.Debug("No RSS Feed!");
return null;
}
// Loop for the <channel> tag
XmlNode nodeChannel = null;
for (int i = 0; i < nodeRss.ChildNodes.Count; i++) {
// If it is the channel tag
if (nodeRss.ChildNodes[i].Name == "channel") {
// <channel> tag found
nodeChannel = nodeRss.ChildNodes[i];
}
}
if (nodeChannel == null) {
LOG.Debug("No channel in RSS feed!");
return null;
}
Dictionary<string, Dictionary<string, SourceforgeFile>> rssFiles = new Dictionary<string, Dictionary<string, SourceforgeFile>>();
// Loop for the <title>, <link>, <description> and all the other tags
for (int i = 0; i < nodeChannel.ChildNodes.Count; i++) {
// If it is the item tag, then it has children tags which we will add as items to the ListView
if (nodeChannel.ChildNodes[i].Name == "item") {
XmlNode nodeItem = nodeChannel.ChildNodes[i];
string sfLink = nodeItem["link"].InnerText;
string pubdate = nodeItem["pubDate"].InnerText;
try {
Match match= Regex.Match(Uri.UnescapeDataString(sfLink), @"^http.*sourceforge.*\/projects\/([^\/]+)\/files\/([^\/]+)\/([^\/]+)\/(.+)\/download$");
if (match.Success) {
string project = match.Groups[1].Value;
string subdir = match.Groups[2].Value;
string type = match.Groups[3].Value;
string file = match.Groups[4].Value;
// !!! Change this to the mirror !!!
string mirror = "kent";
string directLink = Uri.EscapeUriString("http://"+mirror+".dl.sourceforge.net/project/"+project+"/"+subdir+"/"+type+"/"+file);
Dictionary<string, SourceforgeFile> filesForType;
if (rssFiles.ContainsKey(type)) {
filesForType = rssFiles[type];
} else {
filesForType = new Dictionary<string, SourceforgeFile>();
rssFiles.Add(type, filesForType);
}
SourceforgeFile rssFile = new SourceforgeFile(file, pubdate, sfLink, directLink);
if (file.EndsWith(".exe") ||file.EndsWith(".zip")) {
string version = Regex.Replace(file, ".*[a-zA-Z]-", "");
version = version.Replace("-[a-zA-Z]+.*","");
version = Regex.Replace(version, ".exe$", "");
version = Regex.Replace(version, ".zip$", "");
if (version.Trim().Length > 0) {
version = version.Replace('-','.');
version = version.Replace(',','.');
try {
rssFile.Version = new Version(version);
} catch (Exception) {
LOG.DebugFormat("Found invalid version {0} in file {1}", version, file);
}
}
}
if (type.Equals("Translations")) {
string culture = Regex.Replace(file, @"[a-zA-Z]+-(..-..)\.(xml|html)", "$1");
CultureInfo cultureInfo = new CultureInfo(culture);
rssFile.Language = cultureInfo.NativeName;
}
filesForType.Add(file, rssFile);
}
} catch (Exception ex) {
LOG.WarnFormat("Couldn't read RSS entry for: {0}", nodeChannel["title"].InnerText);
LOG.Warn("Reason: ", ex);
}
}
}
return rssFiles;
}
}
}

View file

@ -0,0 +1,676 @@
/*
* 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.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Greenshot.Plugin;
using GreenshotPlugin.UnmanagedHelpers;
namespace GreenshotPlugin.Core {
/// <summary>
/// This Class is used to pass details about the capture around.
/// The time the Capture was taken and the Title of the window (or a region of) that is captured
/// </summary>
public class CaptureDetails : ICaptureDetails {
private string title;
public string Title {
get {return title;}
set {title = value;}
}
private string filename;
public string Filename {
get {return filename;}
set {filename = value;}
}
private DateTime dateTime;
public DateTime DateTime {
get {return dateTime;}
set {dateTime = value;}
}
private float dpiX;
public float DpiX {
get {
return dpiX;
}
set {
dpiX = value;
}
}
private float dpiY;
public float DpiY {
get {
return dpiY;
}
set {
dpiY = value;
}
}
private Dictionary<string, string> metaData = new Dictionary<string, string>();
public Dictionary<string, string> MetaData {
get {return metaData;}
}
public void AddMetaData(string key, string value) {
if (metaData.ContainsKey(key)) {
metaData[key] = value;
} else {
metaData.Add(key, value);
}
}
private CaptureMode captureMode;
public CaptureMode CaptureMode {
get {return captureMode;}
set {captureMode = value;}
}
private List<IDestination> captureDestinations = new List<IDestination>();
public List<IDestination> CaptureDestinations {
get {return captureDestinations;}
set {captureDestinations = value;}
}
public void ClearDestinations() {
captureDestinations.Clear();
}
public void RemoveDestination(IDestination destination) {
if (captureDestinations.Contains(destination)) {
captureDestinations.Remove(destination);
}
}
public void AddDestination(IDestination captureDestination) {
if (!captureDestinations.Contains(captureDestination)) {
captureDestinations.Add(captureDestination);
}
}
public bool HasDestination(string designation) {
foreach(IDestination destination in captureDestinations) {
if (designation.Equals(destination.Designation)) {
return true;
}
}
return false;
}
public CaptureDetails() {
dateTime = DateTime.Now;
}
}
/// <summary>
/// This class is used to pass an instance of the "Capture" around
/// Having the Bitmap, eventually the Windows Title and cursor all together.
/// </summary>
public class Capture : IDisposable, ICapture {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(Capture));
private List<ICaptureElement> elements = new List<ICaptureElement>();
private Rectangle screenBounds;
/// <summary>
/// Get/Set the Screenbounds
/// </summary>
public Rectangle ScreenBounds {
get {
if (screenBounds == null) {
screenBounds = WindowCapture.GetScreenBounds();
}
return screenBounds;
}
set {screenBounds = value;}
}
private Image image;
/// <summary>
/// Get/Set the Image
/// </summary>
public Image Image {
get {return image;}
set {
if (image != null) {
image.Dispose();
}
image = value;
if (value != null) {
if (value.PixelFormat.Equals(PixelFormat.Format8bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format1bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format4bppIndexed)) {
LOG.Debug("Converting Bitmap to PixelFormat.Format32bppArgb as we don't support: " + value.PixelFormat);
try {
// Default Bitmap PixelFormat is Format32bppArgb
this.image = new Bitmap(value);
} finally {
// Always dispose, even when a exception occured
value.Dispose();
}
}
LOG.Debug("Image is set with the following specifications: " + image.Width + "," + image.Height + " - " + image.PixelFormat);
} else {
LOG.Debug("Image is removed.");
}
}
}
public void NullImage() {
image = null;
}
private Icon cursor;
/// <summary>
/// Get/Set the image for the Cursor
/// </summary>
public Icon Cursor {
get {return cursor;}
set {
if (cursor != null) {
cursor.Dispose();
}
cursor = (Icon)value.Clone();
}
}
private bool cursorVisible = false;
/// <summary>
/// Set if the cursor is visible
/// </summary>
public bool CursorVisible {
get {return cursorVisible;}
set {cursorVisible = value;}
}
private Point cursorLocation = Point.Empty;
/// <summary>
/// Get/Set the CursorLocation
/// </summary>
public Point CursorLocation {
get {return cursorLocation;}
set {cursorLocation = value;}
}
private Point location = Point.Empty;
/// <summary>
/// Get/set the Location
/// </summary>
public Point Location {
get {return location;}
set {location = value;}
}
private CaptureDetails captureDetails;
/// <summary>
/// Get/set the CaptureDetails
/// </summary>
public ICaptureDetails CaptureDetails {
get {return captureDetails;}
set {captureDetails = (CaptureDetails)value;}
}
/// <summary>
/// Default Constructor
/// </summary>
public Capture() {
screenBounds = WindowCapture.GetScreenBounds();
captureDetails = new CaptureDetails();
}
/// <summary>
/// Constructor with Image
/// Note: the supplied bitmap can be disposed immediately or when constructor is called.
/// </summary>
/// <param name="newImage">Image</param>
public Capture(Image newImage) : this() {
this.Image = newImage;
}
/// <summary>
/// Destructor
/// </summary>
~Capture() {
Dispose(false);
}
/// <summary>
/// The public accessible Dispose
/// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice
/// </summary>
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// This Dispose is called from the Dispose and the Destructor.
/// When disposing==true all non-managed resources should be freed too!
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing) {
if (disposing) {
if (image != null) {
image.Dispose();
}
if (cursor != null) {
cursor.Dispose();
}
}
image = null;
cursor = null;
}
/// <summary>
/// Crops the capture to the specified rectangle (with Bitmap coordinates!)
/// </summary>
/// <param name="cropRectangle">Rectangle with bitmap coordinates</param>
public bool Crop(Rectangle cropRectangle) {
LOG.Debug("Cropping to: " + cropRectangle.ToString());
if (ImageHelper.Crop(ref image, ref cropRectangle)) {
location = cropRectangle.Location;
// Change mouse location according to the cropRegtangle (including screenbounds) offset
MoveMouseLocation(-cropRectangle.Location.X, -cropRectangle.Location.Y);
// Move all the elements
MoveElements(-cropRectangle.Location.X, -cropRectangle.Location.Y);
// Remove invisible elements
List <ICaptureElement> newElements = new List<ICaptureElement>();
foreach(ICaptureElement captureElement in elements) {
if (captureElement.Bounds.IntersectsWith(cropRectangle)) {
newElements.Add(captureElement);
}
}
elements = newElements;
return true;
}
return false;
}
/// <summary>
/// Apply a translate to the mouse location.
/// e.g. needed for crop
/// </summary>
/// <param name="x">x coordinates to move the mouse</param>
/// <param name="y">y coordinates to move the mouse</param>
public void MoveMouseLocation(int x, int y) {
cursorLocation.Offset(x, y);
}
/// <summary>
/// Apply a translate to the elements
/// e.g. needed for crop
/// </summary>
/// <param name="x">x coordinates to move the elements</param>
/// <param name="y">y coordinates to move the elements</param>
public void MoveElements(int x, int y) {
MoveElements(elements, x, y);
}
private void MoveElements(List<ICaptureElement> listOfElements, int x, int y) {
foreach(ICaptureElement childElement in listOfElements) {
Rectangle bounds = childElement.Bounds;
bounds.Offset(x, y);
childElement.Bounds = bounds;
MoveElements(childElement.Children, x, y);
}
}
/// <summary>
/// Add a new element to the capture
/// </summary>
/// <param name="element">CaptureElement</param>
public void AddElement(ICaptureElement element) {
int match = elements.IndexOf(element);
if (match >= 0) {
if (elements[match].Children.Count < element.Children.Count) {
elements.RemoveAt(match);
elements.Add(element);
}
} else {
elements.Add(element);
}
}
/// <summary>
/// Returns a list of rectangles which represent object that are on the capture
/// </summary>
public List<ICaptureElement> Elements {
get {
return elements;
}
set {
elements = value;
}
}
public ICaptureElement FindElementUnderPoint(Point p) {
foreach(ICaptureElement element in elements) {
if (element.Bounds.Contains(p)) {
return element.FindElementUnderPoint(p);
}
}
return null;
}
}
/// <summary>
/// A class representing an element in the capture
/// </summary>
public class CaptureElement : ICaptureElement {
public CaptureElement(Rectangle bounds) {
Bounds = bounds;
}
public CaptureElement(string name) {
Name = name;
}
public CaptureElement(string name, Rectangle bounds) {
Name = name;
Bounds = bounds;
}
private List<ICaptureElement> children = new List<ICaptureElement>();
public List<ICaptureElement> Children {
get {
return children;
}
set {
children = value;
}
}
public string Name {
get;
set;
}
public Rectangle Bounds {
get;
set;
}
public ICaptureElement FindElementUnderPoint(Point point) {
if (!Bounds.Contains(point)) {
return null;
}
foreach(CaptureElement childElement in children) {
if (childElement.Bounds.Contains(point)) {
ICaptureElement selectedElement = childElement.FindElementUnderPoint(point);
return selectedElement;
}
}
return this;
}
// CaptureElements are regarded equal if their bounds are equal. this should be sufficient.
public override bool Equals(object obj) {
bool ret = false;
if (obj != null && GetType().Equals(obj.GetType())) {
CaptureElement other = obj as CaptureElement;
if (Bounds.Equals(other.Bounds)) {
ret = true;
}
}
return ret;
}
public override int GetHashCode() {
return Bounds.GetHashCode();
}
}
/// <summary>
/// The Window Capture code
/// </summary>
public class WindowCapture {
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(WindowCapture));
private WindowCapture() {
}
/// <summary>
/// Get the bounds of all screens combined.
/// </summary>
/// <returns>A Rectangle of the bounds of the entire display area.</returns>
public static Rectangle GetScreenBounds() {
int left = 0, top = 0, bottom = 0, right = 0;
foreach (Screen screen in Screen.AllScreens) {
left = Math.Min(left, screen.Bounds.X);
top = Math.Min(top, screen.Bounds.Y);
int screenAbsRight = screen.Bounds.X + screen.Bounds.Width;
int screenAbsBottom = screen.Bounds.Y + screen.Bounds.Height;
right = Math.Max(right, screenAbsRight);
bottom = Math.Max(bottom, screenAbsBottom);
}
return new Rectangle(left, top, (right + Math.Abs(left)), (bottom + Math.Abs(top)));
}
/// <summary>
/// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7
/// <returns>Point with cursor location</returns>
public static Point GetCursorLocation() {
if (Environment.OSVersion.Version.Major >= 6) {
POINT cursorLocation;
if (User32.GetPhysicalCursorPos(out cursorLocation)) {
return new Point(cursorLocation.X, cursorLocation.Y);
} else {
Win32Error error = Win32.GetLastErrorCode();
LOG.ErrorFormat("Error retrieving PhysicalCursorPos : {0}", Win32.GetMessage(error));
}
}
return new Point(Cursor.Position.X, Cursor.Position.Y);
}
/// <summary>
/// This method will capture the current Cursor by using User32 Code
/// </summary>
/// <returns>A Capture Object with the Mouse Cursor information in it.</returns>
public static ICapture CaptureCursor(ICapture capture) {
LOG.Debug("Capturing the mouse cursor.");
if (capture == null) {
capture = new Capture();
}
int x,y;
IntPtr hicon;
CursorInfo cursorInfo = new CursorInfo();
IconInfo iconInfo;
cursorInfo.cbSize = Marshal.SizeOf(cursorInfo);
if (User32.GetCursorInfo(out cursorInfo)) {
if (cursorInfo.flags == User32.CURSOR_SHOWING) {
hicon = User32.CopyIcon(cursorInfo.hCursor);
if (User32.GetIconInfo(hicon, out iconInfo)) {
Point cursorLocation = GetCursorLocation();
// Allign cursor location to Bitmap coordinates (instead of Screen coordinates)
x = cursorLocation.X - iconInfo.xHotspot - capture.ScreenBounds.X;
y = cursorLocation.Y - iconInfo.yHotspot - capture.ScreenBounds.Y;
// Set the location
capture.CursorLocation = new Point(x, y);
using (Icon icon = Icon.FromHandle(hicon)) {
capture.Cursor = icon;
}
if (iconInfo.hbmMask != IntPtr.Zero) {
GDI32.DeleteObject(iconInfo.hbmMask);
}
if (iconInfo.hbmColor != IntPtr.Zero) {
GDI32.DeleteObject(iconInfo.hbmColor);
}
}
User32.DestroyIcon(hicon);
}
}
return capture;
}
/// <summary>
/// This method will call the CaptureRectangle with the screenbounds, therefor Capturing the whole screen.
/// </summary>
/// <returns>A Capture Object with the Screen as an Image</returns>
public static ICapture CaptureScreen(ICapture capture) {
if (capture == null) {
capture = new Capture();
}
return CaptureRectangle(capture, capture.ScreenBounds);
}
/// <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="capture">ICapture</param>
/// <param name="captureBounds">Rectangle of what we want to capture</param>
/// <returns></returns>
private static Exception CreateCaptureException(string method, Rectangle captureBounds) {
Exception exceptionToThrow = User32.CreateWin32Exception(method);
if (!captureBounds.IsEmpty) {
exceptionToThrow.Data.Add("Height", captureBounds.Height);
exceptionToThrow.Data.Add("Width", captureBounds.Width);
}
return exceptionToThrow;
}
/// <summary>
/// This method will use User32 code to capture the specified captureBounds from the screen
/// </summary>
/// <param name="capture">ICapture where the captured Bitmap will be stored</param>
/// <param name="captureBounds">Rectangle with the bounds to capture</param>
/// <returns>A Capture Object with a part of the Screen as an Image</returns>
public static ICapture CaptureRectangle(ICapture capture, Rectangle captureBounds) {
if (capture == null) {
capture = new Capture();
}
capture.Image = CaptureRectangle(captureBounds);
capture.Location = captureBounds.Location;
((Bitmap)capture.Image).SetResolution(capture.CaptureDetails.DpiX, capture.CaptureDetails.DpiY);
if (capture.Image == null) {
return null;
}
return capture;
}
/// <summary>
/// This method will use User32 code to capture the specified captureBounds from the screen
/// </summary>
/// <param name="captureBounds">Rectangle with the bounds to capture</param>
/// <returns>Bitmap which is captured from the screen at the location specified by the captureBounds</returns>
public static Bitmap CaptureRectangle(Rectangle captureBounds) {
Bitmap returnBitmap = null;
if (captureBounds.Height <= 0 || captureBounds.Width <= 0) {
LOG.Warn("Nothing to capture, ignoring!");
return null;
} else {
LOG.Debug("CaptureRectangle Called!");
}
// .NET GDI+ Solution, according to some post this has a GDI+ leak...
// See http://connect.microsoft.com/VisualStudio/feedback/details/344752/gdi-object-leak-when-calling-graphics-copyfromscreen
// Bitmap capturedBitmap = new Bitmap(captureBounds.Width, captureBounds.Height);
// using (Graphics graphics = Graphics.FromImage(capturedBitmap)) {
// graphics.CopyFromScreen(captureBounds.Location, Point.Empty, captureBounds.Size, CopyPixelOperation.CaptureBlt);
// }
// capture.Image = capturedBitmap;
// capture.Location = captureBounds.Location;
// "P/Invoke" Solution for capturing the screen
IntPtr hWndDesktop = User32.GetDesktopWindow();
// get te hDC of the target window
IntPtr hDCDesktop = User32.GetWindowDC(hWndDesktop);
// Make sure the last error is set to 0
Win32.SetLastError(0);
// create a device context we can copy to
IntPtr 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", captureBounds);
// Cleanup
User32.ReleaseDC(hWndDesktop, hDCDesktop);
// throw exception
throw exceptionToThrow;
}
// Create BitmapInfoHeader for CreateDIBSection
BitmapInfoHeader bmi = new BitmapInfoHeader(captureBounds.Width, captureBounds.Height, 24);
// Make sure the last error is set to 0
Win32.SetLastError(0);
// create a bitmap we can copy it to, using GetDeviceCaps to get the width/height
IntPtr bits0; // not used for our purposes. It returns a pointer to the raw bits that make up the bitmap.
IntPtr hDIBSection = GDI32.CreateDIBSection(hDCDesktop, ref bmi, BitmapInfoHeader.DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0);
if (hDIBSection == IntPtr.Zero) {
// Get Exception before the error is lost
Exception exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
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;
} else {
// select the bitmap object and store the old handle
IntPtr hOldObject = GDI32.SelectObject(hDCDest, hDIBSection);
// bitblt over (make copy)
GDI32.BitBlt(hDCDest, 0, 0, captureBounds.Width, captureBounds.Height, hDCDesktop, captureBounds.X, captureBounds.Y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
// restore selection (old handle)
GDI32.SelectObject(hDCDest, hOldObject);
// clean up
GDI32.DeleteDC(hDCDest);
User32.ReleaseDC(hWndDesktop, hDCDesktop);
// get a .NET image object for it
// A suggestion for the "A generic error occurred in GDI+." E_FAIL/0×80004005 error is to re-try...
bool success = false;
ExternalException exception = null;
for(int i = 0; i < 3; i++) {
try {
// assign image to Capture, the image will be disposed there..
returnBitmap = Bitmap.FromHbitmap(hDIBSection);
success = true;
break;
} catch (ExternalException ee) {
LOG.Warn("Problem getting bitmap at try " + i + " : ", ee);
exception = ee;
}
}
if (!success) {
LOG.Error("Still couldn't create Bitmap!");
throw exception;
}
// free up the Bitmap object
GDI32.DeleteObject(hDIBSection);
}
return returnBitmap;
}
}
}

File diff suppressed because it is too large Load diff