diff --git a/Directory.Build.props b/Directory.Build.props
index 37b63badc..1415521cf 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -56,7 +56,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/Greenshot/Drawing/Adorners/AbstractAdorner.cs
index 7539f809b..f6032d62f 100644
--- a/Greenshot/Drawing/Adorners/AbstractAdorner.cs
+++ b/Greenshot/Drawing/Adorners/AbstractAdorner.cs
@@ -118,6 +118,18 @@ namespace Greenshot.Drawing.Adorners
}
}
+ ///
+ /// Return the bounds of the Adorner as displayed on the parent Surface
+ ///
+ protected virtual Rectangle BoundsOnSurface
+ {
+ get
+ {
+ Point displayLocation = Owner.Parent.ToSurfaceCoordinates(Location);
+ return new Rectangle(displayLocation.X - _size.Width / 2, displayLocation.Y - _size.Height / 2, _size.Width, _size.Height);
+ }
+ }
+
///
/// The adorner is active if the edit status is not idle or undrawn
///
diff --git a/Greenshot/Drawing/Adorners/MoveAdorner.cs b/Greenshot/Drawing/Adorners/MoveAdorner.cs
index 894fcf6fc..1eee0c832 100644
--- a/Greenshot/Drawing/Adorners/MoveAdorner.cs
+++ b/Greenshot/Drawing/Adorners/MoveAdorner.cs
@@ -142,7 +142,7 @@ namespace Greenshot.Drawing.Adorners
{
Graphics targetGraphics = paintEventArgs.Graphics;
- var bounds = Bounds;
+ var bounds = BoundsOnSurface;
GraphicsState state = targetGraphics.Save();
targetGraphics.SmoothingMode = SmoothingMode.None;
diff --git a/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/Greenshot/Drawing/Adorners/ResizeAdorner.cs
index 1284b678a..836e65007 100644
--- a/Greenshot/Drawing/Adorners/ResizeAdorner.cs
+++ b/Greenshot/Drawing/Adorners/ResizeAdorner.cs
@@ -169,7 +169,7 @@ namespace Greenshot.Drawing.Adorners
{
Graphics targetGraphics = paintEventArgs.Graphics;
- var bounds = Bounds;
+ var bounds = BoundsOnSurface;
GraphicsState state = targetGraphics.Save();
targetGraphics.SmoothingMode = SmoothingMode.None;
diff --git a/Greenshot/Drawing/Adorners/TargetAdorner.cs b/Greenshot/Drawing/Adorners/TargetAdorner.cs
index 3c397e7f0..9fa3e6205 100644
--- a/Greenshot/Drawing/Adorners/TargetAdorner.cs
+++ b/Greenshot/Drawing/Adorners/TargetAdorner.cs
@@ -1,119 +1,119 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2020 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 .
- */
-
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Windows.Forms;
-using GreenshotPlugin.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Adorners
-{
- ///
- /// This implements the special "gripper" for the Speech-Bubble tail
- ///
- public class TargetAdorner : AbstractAdorner
- {
-
- public TargetAdorner(IDrawableContainer owner, Point location) : base(owner)
- {
- Location = location;
- }
-
- ///
- /// Handle the mouse down
- ///
- ///
- ///
- public override void MouseDown(object sender, MouseEventArgs mouseEventArgs)
- {
- EditStatus = EditStatus.MOVING;
- }
-
- ///
- /// Handle the mouse move
- ///
- ///
- ///
- public override void MouseMove(object sender, MouseEventArgs mouseEventArgs)
- {
- if (EditStatus != EditStatus.MOVING)
- {
- return;
- }
-
- Owner.Invalidate();
- Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y);
- Rectangle surfaceBounds = new Rectangle(0, 0, Owner.Parent.Width, Owner.Parent.Height);
- // Check if gripper inside the parent (surface), if not we need to move it inside
- // This was made for BUG-1682
- if (!surfaceBounds.Contains(newGripperLocation))
- {
- if (newGripperLocation.X > surfaceBounds.Right)
- {
- newGripperLocation.X = surfaceBounds.Right - 5;
- }
- if (newGripperLocation.X < surfaceBounds.Left)
- {
- newGripperLocation.X = surfaceBounds.Left;
- }
- if (newGripperLocation.Y > surfaceBounds.Bottom)
- {
- newGripperLocation.Y = surfaceBounds.Bottom - 5;
- }
- if (newGripperLocation.Y < surfaceBounds.Top)
- {
- newGripperLocation.Y = surfaceBounds.Top;
- }
- }
-
- Location = newGripperLocation;
- Owner.Invalidate();
- }
-
- ///
- /// Draw the adorner
- ///
- /// PaintEventArgs
- public override void Paint(PaintEventArgs paintEventArgs)
- {
- Graphics targetGraphics = paintEventArgs.Graphics;
-
- var bounds = Bounds;
- targetGraphics.FillRectangle(Brushes.Green, bounds);
- targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds);
- }
-
- ///
- /// Made sure this adorner is transformed
- ///
- /// Matrix
- public override void Transform(Matrix matrix)
- {
- if (matrix == null)
- {
- return;
- }
- Point[] points = new[] { Location };
- matrix.TransformPoints(points);
- Location = points[0];
- }
- }
-}
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2020 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 .
+ */
+
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+using GreenshotPlugin.Interfaces.Drawing;
+
+namespace Greenshot.Drawing.Adorners
+{
+ ///
+ /// This implements the special "gripper" for the Speech-Bubble tail
+ ///
+ public class TargetAdorner : AbstractAdorner
+ {
+
+ public TargetAdorner(IDrawableContainer owner, Point location) : base(owner)
+ {
+ Location = location;
+ }
+
+ ///
+ /// Handle the mouse down
+ ///
+ ///
+ ///
+ public override void MouseDown(object sender, MouseEventArgs mouseEventArgs)
+ {
+ EditStatus = EditStatus.MOVING;
+ }
+
+ ///
+ /// Handle the mouse move
+ ///
+ ///
+ ///
+ public override void MouseMove(object sender, MouseEventArgs mouseEventArgs)
+ {
+ if (EditStatus != EditStatus.MOVING)
+ {
+ return;
+ }
+
+ Owner.Invalidate();
+ Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y);
+ Rectangle imageBounds = new Rectangle(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height);
+ // Check if gripper inside the parent (surface), if not we need to move it inside
+ // This was made for BUG-1682
+ if (!imageBounds.Contains(newGripperLocation))
+ {
+ if (newGripperLocation.X > imageBounds.Right)
+ {
+ newGripperLocation.X = imageBounds.Right - 5;
+ }
+ if (newGripperLocation.X < imageBounds.Left)
+ {
+ newGripperLocation.X = imageBounds.Left;
+ }
+ if (newGripperLocation.Y > imageBounds.Bottom)
+ {
+ newGripperLocation.Y = imageBounds.Bottom - 5;
+ }
+ if (newGripperLocation.Y < imageBounds.Top)
+ {
+ newGripperLocation.Y = imageBounds.Top;
+ }
+ }
+
+ Location = newGripperLocation;
+ Owner.Invalidate();
+ }
+
+ ///
+ /// Draw the adorner
+ ///
+ /// PaintEventArgs
+ public override void Paint(PaintEventArgs paintEventArgs)
+ {
+ Graphics targetGraphics = paintEventArgs.Graphics;
+
+ var bounds = BoundsOnSurface;
+ targetGraphics.FillRectangle(Brushes.Green, bounds);
+ targetGraphics.DrawRectangle(new Pen(Brushes.Green), bounds);
+ }
+
+ ///
+ /// Made sure this adorner is transformed
+ ///
+ /// Matrix
+ public override void Transform(Matrix matrix)
+ {
+ if (matrix == null)
+ {
+ return;
+ }
+ Point[] points = new[] { Location };
+ matrix.TransformPoints(points);
+ Location = points[0];
+ }
+ }
+}
diff --git a/Greenshot/Drawing/CropContainer.cs b/Greenshot/Drawing/CropContainer.cs
index 2dc9761c0..58cee17b1 100644
--- a/Greenshot/Drawing/CropContainer.cs
+++ b/Greenshot/Drawing/CropContainer.cs
@@ -56,7 +56,15 @@ namespace Greenshot.Drawing {
/// We need to override the DrawingBound, return a rectangle in the size of the image, to make sure this element is always draw
/// (we create a transparent brown over the complete picture)
///
- public override Rectangle DrawingBounds => new Rectangle(0,0,_parent?.Width??0, _parent?.Height ?? 0);
+ public override Rectangle DrawingBounds {
+ get {
+ if (_parent?.Image is Image image) {
+ return new Rectangle(0, 0, image.Width, image.Height);
+ } else {
+ return Rectangle.Empty;
+ }
+ }
+ }
public override void Draw(Graphics g, RenderMode rm) {
if (_parent == null)
@@ -67,17 +75,18 @@ namespace Greenshot.Drawing {
using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100));
Rectangle cropRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
Rectangle selectionRect = new Rectangle(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1);
+ Size imageSize = _parent.Image.Size;
DrawSelectionBorder(g, selectionRect);
// top
- g.FillRectangle(cropBrush, new Rectangle(0, 0, _parent.Width, cropRectangle.Top));
+ g.FillRectangle(cropBrush, new Rectangle(0, 0, imageSize.Width, cropRectangle.Top));
// left
g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height));
// right
- g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, _parent.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height));
+ g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, imageSize.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height));
// bottom
- g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, _parent.Width, _parent.Height - (cropRectangle.Top + cropRectangle.Height)));
+ g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, imageSize.Width, imageSize.Height - (cropRectangle.Top + cropRectangle.Height)));
}
public override bool HasContextMenu {
diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs
index 0749805d4..a85cee791 100644
--- a/Greenshot/Drawing/DrawableContainer.cs
+++ b/Greenshot/Drawing/DrawableContainer.cs
@@ -33,7 +33,6 @@ using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.Serialization;
-using System.Windows.Forms;
using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Drawing.Adorners;
@@ -298,34 +297,7 @@ namespace Greenshot.Drawing
public virtual void Invalidate() {
if (Status != EditStatus.UNDRAWN) {
- _parent?.Invalidate(DrawingBounds);
- }
- }
-
- public void AlignToParent(HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) {
- if (_parent == null)
- {
- return;
- }
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- if (horizontalAlignment == HorizontalAlignment.Left) {
- Left = lineThickness/2;
- }
- if (horizontalAlignment == HorizontalAlignment.Right) {
- Left = _parent.Width - Width - lineThickness/2;
- }
- if (horizontalAlignment == HorizontalAlignment.Center) {
- Left = (_parent.Width / 2) - (Width / 2) - lineThickness/2;
- }
-
- if (verticalAlignment == VerticalAlignment.TOP) {
- Top = lineThickness/2;
- }
- if (verticalAlignment == VerticalAlignment.BOTTOM) {
- Top = _parent.Height - Height - lineThickness/2;
- }
- if (verticalAlignment == VerticalAlignment.CENTER) {
- Top = (_parent.Height / 2) - (Height / 2) - lineThickness/2;
+ _parent?.InvalidateElements(DrawingBounds);
}
}
diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs
index 8d04238f2..666986002 100644
--- a/Greenshot/Drawing/DrawableContainerList.cs
+++ b/Greenshot/Drawing/DrawableContainerList.cs
@@ -235,6 +235,30 @@ namespace Greenshot.Drawing {
return false;
}
+ ///
+ /// A rectangle containing DrawingBounds of all drawableContainers in this list,
+ /// or empty rectangle if nothing is there.
+ ///
+ public Rectangle DrawingBounds
+ {
+ get
+ {
+ if (Count == 0)
+ {
+ return Rectangle.Empty;
+ }
+ else
+ {
+ var result = this[0].DrawingBounds;
+ for (int i = 1; i < Count; i++)
+ {
+ result = Rectangle.Union(result, this[i].DrawingBounds);
+ }
+ return result;
+ }
+ }
+ }
+
///
/// Triggers all elements in the list ot be redrawn.
///
@@ -286,7 +310,7 @@ namespace Greenshot.Drawing {
{
region = Rectangle.Union(region, dc.DrawingBounds);
}
- Parent.Invalidate(region);
+ Parent.InvalidateElements(region);
}
///
/// Indicates whether the given list of elements can be pulled up,
@@ -523,9 +547,9 @@ namespace Greenshot.Drawing {
}
}
- public virtual void ShowContextMenu(MouseEventArgs e, ISurface surface)
+ public virtual void ShowContextMenu(MouseEventArgs e, ISurface iSurface)
{
- if (!(surface is Surface))
+ if (!(iSurface is Surface surface))
{
return;
}
@@ -542,8 +566,7 @@ namespace Greenshot.Drawing {
ContextMenuStrip menu = new ContextMenuStrip();
AddContextMenuItems(menu, surface);
if (menu.Items.Count > 0) {
- // TODO: cast should be somehow avoided
- menu.Show((Surface)surface, e.Location);
+ menu.Show(surface, surface.ToSurfaceCoordinates(e.Location));
while (true) {
if (menu.Visible) {
Application.DoEvents();
diff --git a/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs
index b4a4283e4..70581bc10 100644
--- a/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs
+++ b/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs
@@ -35,13 +35,13 @@ namespace Greenshot.Drawing.Fields.Binding {
}
protected override float convert(decimal o) {
- return Convert.ToInt16(o);
+ return Convert.ToSingle(o);
}
public static DecimalFloatConverter GetInstance()
- {
- return _uniqueInstance ??= new DecimalFloatConverter();
- }
+ {
+ return _uniqueInstance ??= new DecimalFloatConverter();
+ }
}
}
diff --git a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs
index d71d27528..693e532dd 100644
--- a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs
+++ b/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs
@@ -1,4 +1,4 @@
-/*
+/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
*
@@ -35,13 +35,13 @@ namespace Greenshot.Drawing.Fields.Binding {
}
protected override int convert(decimal o) {
- return Convert.ToInt16(o);
+ return Convert.ToInt32(o);
}
public static DecimalIntConverter GetInstance()
- {
- return _uniqueInstance ??= new DecimalIntConverter();
- }
+ {
+ return _uniqueInstance ??= new DecimalIntConverter();
+ }
}
}
diff --git a/Greenshot/Drawing/FreehandContainer.cs b/Greenshot/Drawing/FreehandContainer.cs
index 129ba4822..c7d5cf1e8 100644
--- a/Greenshot/Drawing/FreehandContainer.cs
+++ b/Greenshot/Drawing/FreehandContainer.cs
@@ -47,8 +47,8 @@ namespace Greenshot.Drawing {
/// Constructor
///
public FreehandContainer(Surface parent) : base(parent) {
- Width = parent.Width;
- Height = parent.Height;
+ Width = parent.Image.Width;
+ Height = parent.Image.Height;
Top = 0;
Left = 0;
}
@@ -236,7 +236,14 @@ namespace Greenshot.Drawing {
int safetymargin = 10;
return new Rectangle(myBounds.Left + Left - (safetymargin+lineThickness), myBounds.Top + Top - (safetymargin+lineThickness), myBounds.Width + 2*(lineThickness+safetymargin), myBounds.Height + 2*(lineThickness+safetymargin));
}
- return new Rectangle(0, 0, _parent?.Width??0, _parent?.Height?? 0);
+ if (_parent?.Image is Image image)
+ {
+ return new Rectangle(0, 0, image.Width, image.Height);
+ }
+ else
+ {
+ return Rectangle.Empty;
+ }
}
}
diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs
index efc018c1e..d7a4487fc 100644
--- a/Greenshot/Drawing/Surface.cs
+++ b/Greenshot/Drawing/Surface.cs
@@ -1,4 +1,4 @@
-/*
+/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
*
@@ -298,10 +298,39 @@ namespace Greenshot.Drawing
set
{
_image = value;
- Size = _image.Size;
+ UpdateSize();
}
}
+ [NonSerialized]
+ private Matrix _zoomMatrix = new Matrix(1, 0, 0, 1, 0, 0);
+ [NonSerialized]
+ private Matrix _inverseZoomMatrix = new Matrix(1, 0, 0, 1, 0, 0);
+ [NonSerialized]
+ private Fraction _zoomFactor = Fraction.Identity;
+ public Fraction ZoomFactor
+ {
+ get => _zoomFactor;
+ set
+ {
+ _zoomFactor = value;
+ var inverse = _zoomFactor.Inverse();
+ _zoomMatrix = new Matrix(_zoomFactor, 0, 0, _zoomFactor, 0, 0);
+ _inverseZoomMatrix = new Matrix(inverse, 0, 0, inverse, 0, 0);
+ UpdateSize();
+ }
+ }
+
+
+ ///
+ /// Sets the surface size as zoomed image size.
+ ///
+ private void UpdateSize()
+ {
+ var size = _image.Size;
+ Size = new Size((int)(size.Width * _zoomFactor), (int)(size.Height * _zoomFactor));
+ }
+
///
/// The field aggregator is that which is used to have access to all the fields inside the currently selected elements.
/// e.g. used to decided if and which line thickness is shown when multiple elements are selected.
@@ -458,7 +487,6 @@ namespace Greenshot.Drawing
// Set new values
Image = newImage;
- Size = newImage.Size;
_modified = true;
}
@@ -790,9 +818,9 @@ namespace Greenshot.Drawing
return cursorContainer;
}
- public ITextContainer AddTextContainer(string text, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor)
+ public ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor)
{
- TextContainer textContainer = new TextContainer(this) {Text = text};
+ TextContainer textContainer = new TextContainer(this) {Text = text, Left = x, Top = y};
textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name);
textContainer.SetFieldValue(FieldType.FONT_BOLD, bold);
textContainer.SetFieldValue(FieldType.FONT_ITALIC, italic);
@@ -803,8 +831,6 @@ namespace Greenshot.Drawing
textContainer.SetFieldValue(FieldType.SHADOW, shadow);
// Make sure the Text fits
textContainer.FitToText();
- // Align to Surface
- textContainer.AlignToParent(horizontalAlignment, verticalAlignment);
//AggregatedProperties.UpdateElement(textContainer);
AddElement(textContainer);
@@ -978,13 +1004,13 @@ namespace Greenshot.Drawing
{
cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top);
}
- if (cropRectangle.Left + cropRectangle.Width > Width)
+ if (cropRectangle.Left + cropRectangle.Width > Image.Width)
{
- cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Width - cropRectangle.Left, cropRectangle.Height);
+ cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Image.Width - cropRectangle.Left, cropRectangle.Height);
}
- if (cropRectangle.Top + cropRectangle.Height > Height)
+ if (cropRectangle.Top + cropRectangle.Height > Image.Height)
{
- cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Height - cropRectangle.Top);
+ cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top);
}
if (cropRectangle.Height > 0 && cropRectangle.Width > 0)
{
@@ -1097,6 +1123,12 @@ namespace Greenshot.Drawing
return null;
}
+ ///
+ /// Translate mouse coordinates as if they were applied directly to unscaled image.
+ ///
+ private MouseEventArgs InverseZoomMouseCoordinates(MouseEventArgs e)
+ => new MouseEventArgs(e.Button, e.Clicks, (int)(e.X / _zoomFactor), (int)(e.Y / _zoomFactor), e.Delta);
+
///
/// This event handler is called when someone presses the mouse on a surface.
///
@@ -1104,6 +1136,7 @@ namespace Greenshot.Drawing
///
private void SurfaceMouseDown(object sender, MouseEventArgs e)
{
+ e = InverseZoomMouseCoordinates(e);
// Handle Adorners
var adorner = FindActiveAdorner(e);
@@ -1198,6 +1231,7 @@ namespace Greenshot.Drawing
///
private void SurfaceMouseUp(object sender, MouseEventArgs e)
{
+ e = InverseZoomMouseCoordinates(e);
// Handle Adorners
var adorner = FindActiveAdorner(e);
@@ -1287,6 +1321,8 @@ namespace Greenshot.Drawing
///
private void SurfaceMouseMove(object sender, MouseEventArgs e)
{
+ e = InverseZoomMouseCoordinates(e);
+
// Handle Adorners
var adorner = FindActiveAdorner(e);
if (adorner != null)
@@ -1382,6 +1418,25 @@ namespace Greenshot.Drawing
return GetImage(RenderMode.EXPORT);
}
+ private static Rectangle ZoomClipRectangle(Rectangle rc, double scale, int inflateAmount = 0)
+ {
+ rc = new Rectangle(
+ (int)(rc.X * scale),
+ (int)(rc.Y * scale),
+ (int)(rc.Width * scale) + 1,
+ (int)(rc.Height * scale) + 1
+ );
+ if (scale > 1)
+ {
+ inflateAmount = (int)(inflateAmount * scale);
+ }
+ rc.Inflate(inflateAmount, inflateAmount);
+ return rc;
+ }
+
+ public void InvalidateElements(Rectangle rc)
+ => Invalidate(ZoomClipRectangle(rc, _zoomFactor, 1));
+
///
/// This is the event handler for the Paint Event, try to draw as little as possible!
///
@@ -1390,14 +1445,34 @@ namespace Greenshot.Drawing
private void SurfacePaint(object sender, PaintEventArgs paintEventArgs)
{
Graphics targetGraphics = paintEventArgs.Graphics;
- Rectangle clipRectangle = paintEventArgs.ClipRectangle;
- if (Rectangle.Empty.Equals(clipRectangle))
+ Rectangle targetClipRectangle = paintEventArgs.ClipRectangle;
+ if (Rectangle.Empty.Equals(targetClipRectangle))
{
LOG.Debug("Empty cliprectangle??");
return;
}
- if (_elements.HasIntersectingFilters(clipRectangle))
+ // Correction to prevent rounding errors at certain zoom levels.
+ // When zooming to N/M, clip rectangle top and left coordinates should be multiples of N.
+ if (_zoomFactor.Numerator > 1 && _zoomFactor.Denominator > 1)
+ {
+ int horizontalCorrection = targetClipRectangle.Left % (int)_zoomFactor.Numerator;
+ int verticalCorrection = targetClipRectangle.Top % (int)_zoomFactor.Numerator;
+ if (horizontalCorrection != 0)
+ {
+ targetClipRectangle.X -= horizontalCorrection;
+ targetClipRectangle.Width += horizontalCorrection;
+ }
+ if (verticalCorrection != 0)
+ {
+ targetClipRectangle.Y -= verticalCorrection;
+ targetClipRectangle.Height += verticalCorrection;
+ }
+ }
+
+ Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, _zoomFactor.Inverse(), 2);
+
+ if (_elements.HasIntersectingFilters(imageClipRectangle) || _zoomFactor > Fraction.Identity)
{
if (_buffer != null)
{
@@ -1420,18 +1495,44 @@ namespace Greenshot.Drawing
//graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
//graphics.CompositingQuality = CompositingQuality.HighQuality;
//graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- DrawBackground(graphics, clipRectangle);
- graphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel);
- graphics.SetClip(targetGraphics);
- _elements.Draw(graphics, _buffer, RenderMode.EDIT, clipRectangle);
+ DrawBackground(graphics, imageClipRectangle);
+ graphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
+ graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), _zoomFactor.Inverse(), 2));
+ _elements.Draw(graphics, _buffer, RenderMode.EDIT, imageClipRectangle);
+ }
+ if (_zoomFactor == Fraction.Identity)
+ {
+ targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
+ }
+ else
+ {
+ targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor);
+ if (_zoomFactor > Fraction.Identity)
+ {
+ DrawSharpImage(targetGraphics, _buffer, imageClipRectangle);
+ }
+ else
+ {
+ DrawSmoothImage(targetGraphics, _buffer, imageClipRectangle);
+ }
+ targetGraphics.ResetTransform();
}
- targetGraphics.DrawImage(_buffer, clipRectangle, clipRectangle, GraphicsUnit.Pixel);
}
else
{
- DrawBackground(targetGraphics, clipRectangle);
- targetGraphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel);
- _elements.Draw(targetGraphics, null, RenderMode.EDIT, clipRectangle);
+ DrawBackground(targetGraphics, targetClipRectangle);
+ if (_zoomFactor == Fraction.Identity)
+ {
+ targetGraphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
+ _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle);
+ }
+ else
+ {
+ targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor);
+ DrawSmoothImage(targetGraphics, Image, imageClipRectangle);
+ _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle);
+ targetGraphics.ResetTransform();
+ }
}
// No clipping for the adorners
@@ -1446,6 +1547,32 @@ namespace Greenshot.Drawing
}
}
+ private void DrawSmoothImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle)
+ {
+ var state = targetGraphics.Save();
+ targetGraphics.SmoothingMode = SmoothingMode.HighQuality;
+ targetGraphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
+ targetGraphics.CompositingQuality = CompositingQuality.HighQuality;
+ targetGraphics.PixelOffsetMode = PixelOffsetMode.None;
+
+ targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
+
+ targetGraphics.Restore(state);
+ }
+
+ private void DrawSharpImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle)
+ {
+ var state = targetGraphics.Save();
+ targetGraphics.SmoothingMode = SmoothingMode.None;
+ targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;
+ targetGraphics.CompositingQuality = CompositingQuality.HighQuality;
+ targetGraphics.PixelOffsetMode = PixelOffsetMode.None;
+
+ targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
+
+ targetGraphics.Restore(state);
+ }
+
private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle)
{
// check if we need to draw the checkerboard
@@ -1753,43 +1880,79 @@ namespace Greenshot.Drawing
}
else if (ClipboardHelper.ContainsImage(clipboard))
{
- int x = 10;
- int y = 10;
-
- // FEATURE-995: Added a check for the current mouse cursor location, to paste the image on that location.
- var mousePositionOnControl = PointToClient(MousePosition);
- if (ClientRectangle.Contains(mousePositionOnControl))
- {
- x = mousePositionOnControl.X;
- y = mousePositionOnControl.Y;
- }
+ Point pasteLocation = GetPasteLocation(0.1f, 0.1f);
foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard))
{
if (clipboardImage != null)
{
DeselectAllElements();
- IImageContainer container = AddImageContainer(clipboardImage as Bitmap, x, y);
+ IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y);
SelectElement(container);
clipboardImage.Dispose();
- x += 10;
- y += 10;
+ pasteLocation.X += 10;
+ pasteLocation.Y += 10;
}
}
}
else if (ClipboardHelper.ContainsText(clipboard))
{
+ Point pasteLocation = GetPasteLocation(0.4f, 0.4f);
+
string text = ClipboardHelper.GetText(clipboard);
if (text != null)
{
DeselectAllElements();
- ITextContainer textContainer = AddTextContainer(text, HorizontalAlignment.Center, VerticalAlignment.CENTER,
+ ITextContainer textContainer = AddTextContainer(text, pasteLocation.X, pasteLocation.Y,
FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent);
SelectElement(textContainer);
}
}
}
+ ///
+ /// Find a location to paste elements.
+ /// If mouse is over the surface - use it's position, otherwise use the visible area.
+ /// Return a point in image coordinate space.
+ ///
+ /// 0.0f for the left edge of visible area, 1.0f for the right edge of visible area.
+ /// 0.0f for the top edge of visible area, 1.0f for the bottom edge of visible area.
+ private Point GetPasteLocation(float horizontalRatio = 0.5f, float verticalRatio = 0.5f)
+ {
+ var point = PointToClient(MousePosition);
+ var rc = GetVisibleRectangle();
+ if (!rc.Contains(point))
+ {
+ point = new Point(
+ rc.Left + (int)(rc.Width * horizontalRatio),
+ rc.Top + (int)(rc.Height * verticalRatio)
+ );
+ }
+ return ToImageCoordinates(point);
+ }
+
+ ///
+ /// Get the rectangle bounding the part of this Surface currently visible in the editor (in surface coordinate space).
+ ///
+ public Rectangle GetVisibleRectangle()
+ {
+ var bounds = Bounds;
+ var clientArea = Parent.ClientRectangle;
+ return new Rectangle(
+ Math.Max(0, -bounds.Left),
+ Math.Max(0, -bounds.Top),
+ clientArea.Width,
+ clientArea.Height
+ );
+ }
+
+ ///
+ /// Get the rectangle bounding all selected elements (in surface coordinates space),
+ /// or empty rectangle if nothing is selcted.
+ ///
+ public Rectangle GetSelectionRectangle()
+ => ToSurfaceCoordinates(selectedElements.DrawingBounds);
+
///
/// Duplicate all the selecteded elements
///
@@ -2045,5 +2208,57 @@ namespace Greenshot.Drawing
{
return _elements.Contains(container);
}
+
+ public Point ToSurfaceCoordinates(Point point)
+ {
+ Point[] points = { point };
+ _zoomMatrix.TransformPoints(points);
+ return points[0];
+ }
+
+ public Rectangle ToSurfaceCoordinates(Rectangle rc)
+ {
+ if (_zoomMatrix.IsIdentity)
+ {
+ return rc;
+ }
+ else
+ {
+ Point[] points = { rc.Location, rc.Location + rc.Size };
+ _zoomMatrix.TransformPoints(points);
+ return new Rectangle(
+ points[0].X,
+ points[0].Y,
+ points[1].X - points[0].X,
+ points[1].Y - points[0].Y
+ );
+ }
+ }
+
+ public Point ToImageCoordinates(Point point)
+ {
+ Point[] points = { point };
+ _inverseZoomMatrix.TransformPoints(points);
+ return points[0];
+ }
+
+ public Rectangle ToImageCoordinates(Rectangle rc)
+ {
+ if (_inverseZoomMatrix.IsIdentity)
+ {
+ return rc;
+ }
+ else
+ {
+ Point[] points = { rc.Location, rc.Location + rc.Size };
+ _inverseZoomMatrix.TransformPoints(points);
+ return new Rectangle(
+ points[0].X,
+ points[0].Y,
+ points[1].X - points[0].X,
+ points[1].Y - points[0].Y
+ );
+ }
+ }
}
}
diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs
index 0f4866d71..939dd3de6 100644
--- a/Greenshot/Drawing/TextContainer.cs
+++ b/Greenshot/Drawing/TextContainer.cs
@@ -22,6 +22,7 @@
using Greenshot.Drawing.Fields;
using Greenshot.Helpers;
using Greenshot.Memento;
+using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces.Drawing;
using System;
using System.ComponentModel;
@@ -155,6 +156,24 @@ namespace Greenshot.Drawing
FieldChanged += TextContainer_FieldChanged;
}
+ protected override void SwitchParent(Surface newParent)
+ {
+ _parent.SizeChanged -= Parent_SizeChanged;
+ base.SwitchParent(newParent);
+ _parent.SizeChanged += Parent_SizeChanged;
+ }
+
+ private void Parent_SizeChanged(object sender, EventArgs e)
+ {
+ UpdateTextBoxPosition();
+ UpdateTextBoxFont();
+ }
+
+ public override void ApplyBounds(RectangleF newBounds)
+ {
+ base.ApplyBounds(newBounds);
+ UpdateTextBoxPosition();
+ }
public override void Invalidate()
{
@@ -255,7 +274,8 @@ namespace Greenshot.Drawing
AcceptsTab = true,
AcceptsReturn = true,
BorderStyle = BorderStyle.None,
- Visible = false
+ Visible = false,
+ Font = new Font(FontFamily.GenericSansSerif, 1) // just need something non-default here
};
_textBox.DataBindings.Add("Text", this, "Text", false, DataSourceUpdateMode.OnPropertyChanged);
@@ -388,7 +408,6 @@ namespace Greenshot.Drawing
var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize);
_font?.Dispose();
_font = newFont;
- _textBox.Font = _font;
}
catch (Exception ex)
{
@@ -400,7 +419,6 @@ namespace Greenshot.Drawing
var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize);
_font?.Dispose();
_font = newFont;
- _textBox.Font = _font;
}
catch (Exception)
{
@@ -413,6 +431,8 @@ namespace Greenshot.Drawing
}
}
+ UpdateTextBoxFont();
+
UpdateAlignment();
}
@@ -423,12 +443,34 @@ namespace Greenshot.Drawing
}
///
- /// This will create the textbox exactly to the inner size of the element
+ /// Set TextBox font according to the TextContainer font and the parent zoom factor.
+ ///
+ private void UpdateTextBoxFont()
+ {
+ if (_textBox == null || _font == null)
+ {
+ return;
+ }
+
+ var textBoxFontScale = _parent?.ZoomFactor ?? Fraction.Identity;
+
+ var newFont = new Font(
+ _font.FontFamily,
+ _font.Size * textBoxFontScale,
+ _font.Style,
+ GraphicsUnit.Pixel
+ );
+ _textBox.Font.Dispose();
+ _textBox.Font = newFont;
+ }
+
+ ///
+ /// This will align the textbox exactly to the inner size of the element
/// is a bit of a hack, but for now it seems to work...
///
private void UpdateTextBoxPosition()
{
- if (_textBox == null)
+ if (_textBox == null || Parent == null)
{
return;
}
@@ -442,22 +484,20 @@ namespace Greenshot.Drawing
correction = -1;
}
Rectangle absRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- _textBox.Left = absRectangle.Left + lineWidth;
- _textBox.Top = absRectangle.Top + lineWidth;
+ Rectangle displayRectangle = Parent.ToSurfaceCoordinates(absRectangle);
+ _textBox.Left = displayRectangle.X + lineWidth;
+ _textBox.Top = displayRectangle.Y + lineWidth;
if (lineThickness <= 1)
{
lineWidth = 0;
}
- _textBox.Width = absRectangle.Width - 2 * lineWidth + correction;
- _textBox.Height = absRectangle.Height - 2 * lineWidth + correction;
- }
-
- public override void ApplyBounds(RectangleF newBounds)
- {
- base.ApplyBounds(newBounds);
- UpdateTextBoxPosition();
+ _textBox.Width = displayRectangle.Width - 2 * lineWidth + correction;
+ _textBox.Height = displayRectangle.Height - 2 * lineWidth + correction;
}
+ ///
+ /// Set TextBox text align and fore color according to field values.
+ ///
private void UpdateTextBoxFormat()
{
if (_textBox == null)
diff --git a/Greenshot/Forms/ImageEditorForm.Designer.cs b/Greenshot/Forms/ImageEditorForm.Designer.cs
index 9a653cc21..04da3d0a0 100644
--- a/Greenshot/Forms/ImageEditorForm.Designer.cs
+++ b/Greenshot/Forms/ImageEditorForm.Designer.cs
@@ -194,6 +194,26 @@ namespace Greenshot {
this.alignLeftToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem();
this.alignCenterToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem();
this.alignRightToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem();
+ this.zoomMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.zoomInMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoomOutMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoomMenuSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+ this.zoomBestFitMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoomMenuSeparator2 = new System.Windows.Forms.ToolStripSeparator();
+ this.zoom25MenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoom50MenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoom66MenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoom75MenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoomMenuSeparator3 = new System.Windows.Forms.ToolStripSeparator();
+ this.zoomActualSizeMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoomMenuSeparator4 = new System.Windows.Forms.ToolStripSeparator();
+ this.zoom200MenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoom300MenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoom400MenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoom600MenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.zoomStatusDropDownBtn = new System.Windows.Forms.ToolStripDropDownButton();
+ this.zoomMainMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.statusStripSpacer = new System.Windows.Forms.ToolStripStatusLabel();
this.topToolStripContainer.BottomToolStripPanel.SuspendLayout();
this.topToolStripContainer.ContentPanel.SuspendLayout();
this.topToolStripContainer.LeftToolStripPanel.SuspendLayout();
@@ -203,6 +223,7 @@ namespace Greenshot {
this.tableLayoutPanel1.SuspendLayout();
this.toolsToolStrip.SuspendLayout();
this.menuStrip1.SuspendLayout();
+ this.zoomMenuStrip.SuspendLayout();
this.destinationsToolStrip.SuspendLayout();
this.propertiesToolStrip.SuspendLayout();
this.fileSavedStatusContextMenu.SuspendLayout();
@@ -238,7 +259,9 @@ namespace Greenshot {
this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None;
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.dimensionsLabel,
- this.statusLabel});
+ this.statusLabel,
+ this.statusStripSpacer,
+ this.zoomStatusDropDownBtn});
this.statusStrip1.Location = new System.Drawing.Point(0, 0);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(785, 24);
@@ -538,6 +561,7 @@ namespace Greenshot {
this.editToolStripMenuItem,
this.objectToolStripMenuItem,
this.pluginToolStripMenuItem,
+ this.zoomMainMenuItem,
this.helpToolStripMenuItem});
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.BackColor = System.Drawing.SystemColors.Control;
@@ -1624,6 +1648,171 @@ namespace Greenshot {
this.alignRightToolStripMenuItem.Name = "alignRightToolStripMenuItem";
this.alignRightToolStripMenuItem.Tag = System.Drawing.StringAlignment.Far;
//
+ // zoomMainMenuItem
+ //
+ this.zoomMainMenuItem.DropDown = this.zoomMenuStrip;
+ this.zoomMainMenuItem.Name = "zoomMainMenuItem";
+ this.zoomMainMenuItem.Size = new System.Drawing.Size(51, 20);
+ this.zoomMainMenuItem.Text = "Zoom";
+ //
+ // zoomMenuStrip
+ //
+ this.zoomMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.zoomInMenuItem,
+ this.zoomOutMenuItem,
+ this.zoomMenuSeparator1,
+ this.zoomBestFitMenuItem,
+ this.zoomMenuSeparator2,
+ this.zoom25MenuItem,
+ this.zoom50MenuItem,
+ this.zoom66MenuItem,
+ this.zoom75MenuItem,
+ this.zoomMenuSeparator3,
+ this.zoomActualSizeMenuItem,
+ this.zoomMenuSeparator4,
+ this.zoom200MenuItem,
+ this.zoom300MenuItem,
+ this.zoom400MenuItem,
+ this.zoom600MenuItem});
+ this.zoomMenuStrip.Name = "zoomMenuStrip";
+ this.zoomMenuStrip.Size = new System.Drawing.Size(210, 292);
+ //
+ // zoomInMenuItem
+ //
+ this.zoomInMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomInMenuItem.Image")));
+ this.zoomInMenuItem.Name = "zoomInMenuItem";
+ this.zoomInMenuItem.ShortcutKeyDisplayString = "Ctrl++";
+ this.zoomInMenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoomInMenuItem.Text = "Zoom In";
+ this.zoomInMenuItem.Click += new System.EventHandler(this.ZoomInMenuItemClick);
+ //
+ // zoomOutMenuItem
+ //
+ this.zoomOutMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomOutMenuItem.Image")));
+ this.zoomOutMenuItem.Name = "zoomOutMenuItem";
+ this.zoomOutMenuItem.ShortcutKeyDisplayString = "Ctrl+-";
+ this.zoomOutMenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoomOutMenuItem.Text = "Zoom Out";
+ this.zoomOutMenuItem.Click += new System.EventHandler(this.ZoomOutMenuItemClick);
+ //
+ // zoomMenuSeparator1
+ //
+ this.zoomMenuSeparator1.Name = "zoomMenuSeparator1";
+ this.zoomMenuSeparator1.Size = new System.Drawing.Size(206, 6);
+ //
+ // zoomBestFitMenuItem
+ //
+ this.zoomBestFitMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomBestFitMenuItem.Image")));
+ this.zoomBestFitMenuItem.Name = "zoomBestFitMenuItem";
+ this.zoomBestFitMenuItem.ShortcutKeyDisplayString = "Ctrl+9";
+ this.zoomBestFitMenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoomBestFitMenuItem.Text = "Best Fit";
+ this.zoomBestFitMenuItem.Click += new System.EventHandler(this.ZoomBestFitMenuItemClick);
+ //
+ // zoomMenuSeparator2
+ //
+ this.zoomMenuSeparator2.Name = "zoomMenuSeparator2";
+ this.zoomMenuSeparator2.Size = new System.Drawing.Size(206, 6);
+ //
+ // zoom25MenuItem
+ //
+ this.zoom25MenuItem.Name = "zoom25MenuItem";
+ this.zoom25MenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoom25MenuItem.Tag = "1/4";
+ this.zoom25MenuItem.Text = "25%";
+ this.zoom25MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
+ //
+ // zoom50MenuItem
+ //
+ this.zoom50MenuItem.Name = "zoom50MenuItem";
+ this.zoom50MenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoom50MenuItem.Tag = "1/2";
+ this.zoom50MenuItem.Text = "50%";
+ this.zoom50MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
+ //
+ // zoom66MenuItem
+ //
+ this.zoom66MenuItem.Name = "zoom66MenuItem";
+ this.zoom66MenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoom66MenuItem.Tag = "2/3";
+ this.zoom66MenuItem.Text = "66%";
+ this.zoom66MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
+ //
+ // zoom75MenuItem
+ //
+ this.zoom75MenuItem.Name = "zoom75MenuItem";
+ this.zoom75MenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoom75MenuItem.Tag = "3/4";
+ this.zoom75MenuItem.Text = "75%";
+ this.zoom75MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
+ //
+ // zoomMenuSeparator3
+ //
+ this.zoomMenuSeparator3.Name = "zoomMenuSeparator3";
+ this.zoomMenuSeparator3.Size = new System.Drawing.Size(206, 6);
+ //
+ // zoomActualSizeMenuItem
+ //
+ this.zoomActualSizeMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomActualSizeMenuItem.Image")));
+ this.zoomActualSizeMenuItem.Name = "zoomActualSizeMenuItem";
+ this.zoomActualSizeMenuItem.ShortcutKeyDisplayString = "Ctrl+0";
+ this.zoomActualSizeMenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoomActualSizeMenuItem.Tag = "1/1";
+ this.zoomActualSizeMenuItem.Text = "100% - Actual Size";
+ this.zoomActualSizeMenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
+ //
+ // zoomMenuSeparator4
+ //
+ this.zoomMenuSeparator4.Name = "zoomMenuSeparator4";
+ this.zoomMenuSeparator4.Size = new System.Drawing.Size(206, 6);
+ //
+ // zoom200MenuItem
+ //
+ this.zoom200MenuItem.Name = "zoom200MenuItem";
+ this.zoom200MenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoom200MenuItem.Tag = "2/1";
+ this.zoom200MenuItem.Text = "200%";
+ this.zoom200MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
+ //
+ // zoom300MenuItem
+ //
+ this.zoom300MenuItem.Name = "zoom300MenuItem";
+ this.zoom300MenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoom300MenuItem.Tag = "3/1";
+ this.zoom300MenuItem.Text = "300%";
+ this.zoom300MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
+ //
+ // zoom400MenuItem
+ //
+ this.zoom400MenuItem.Name = "zoom400MenuItem";
+ this.zoom400MenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoom400MenuItem.Tag = "4/1";
+ this.zoom400MenuItem.Text = "400%";
+ this.zoom400MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
+ //
+ // zoom600MenuItem
+ //
+ this.zoom600MenuItem.Name = "zoom600MenuItem";
+ this.zoom600MenuItem.Size = new System.Drawing.Size(209, 22);
+ this.zoom600MenuItem.Tag = "6/1";
+ this.zoom600MenuItem.Text = "600%";
+ this.zoom600MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
+ //
+ // statusStripSpacer
+ //
+ this.statusStripSpacer.Name = "statusStripSpacer";
+ this.statusStripSpacer.Size = new System.Drawing.Size(599, 19);
+ this.statusStripSpacer.Spring = true;
+ //
+ // zoomStatusDropDownBtn
+ //
+ this.zoomStatusDropDownBtn.DropDown = this.zoomMenuStrip;
+ this.zoomStatusDropDownBtn.Image = ((System.Drawing.Image)(resources.GetObject("zoomStatusDropDownBtn.Image")));
+ this.zoomStatusDropDownBtn.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.zoomStatusDropDownBtn.Name = "zoomStatusDropDownBtn";
+ this.zoomStatusDropDownBtn.Size = new System.Drawing.Size(64, 22);
+ this.zoomStatusDropDownBtn.Text = "100%";
+ //
// ImageEditorForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@@ -1645,6 +1834,7 @@ namespace Greenshot {
this.statusStrip1.ResumeLayout(true);
this.tableLayoutPanel1.ResumeLayout(true);
this.toolsToolStrip.ResumeLayout(true);
+ this.zoomMenuStrip.ResumeLayout(false);
this.menuStrip1.ResumeLayout(true);
this.destinationsToolStrip.ResumeLayout(true);
this.propertiesToolStrip.ResumeLayout(true);
@@ -1794,5 +1984,25 @@ namespace Greenshot {
private Greenshot.Controls.ToolStripColorButton btnLineColor;
private GreenshotPlugin.Controls.GreenshotToolStripMenuItem autoCropToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator17;
+ private System.Windows.Forms.ContextMenuStrip zoomMenuStrip;
+ private System.Windows.Forms.ToolStripMenuItem zoomInMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem zoomOutMenuItem;
+ private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator1;
+ private System.Windows.Forms.ToolStripMenuItem zoomBestFitMenuItem;
+ private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator2;
+ private System.Windows.Forms.ToolStripMenuItem zoom25MenuItem;
+ private System.Windows.Forms.ToolStripMenuItem zoom50MenuItem;
+ private System.Windows.Forms.ToolStripMenuItem zoom66MenuItem;
+ private System.Windows.Forms.ToolStripMenuItem zoom75MenuItem;
+ private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator3;
+ private System.Windows.Forms.ToolStripMenuItem zoomActualSizeMenuItem;
+ private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator4;
+ private System.Windows.Forms.ToolStripMenuItem zoom200MenuItem;
+ private System.Windows.Forms.ToolStripMenuItem zoom300MenuItem;
+ private System.Windows.Forms.ToolStripMenuItem zoom400MenuItem;
+ private System.Windows.Forms.ToolStripMenuItem zoom600MenuItem;
+ private System.Windows.Forms.ToolStripDropDownButton zoomStatusDropDownBtn;
+ private System.Windows.Forms.ToolStripMenuItem zoomMainMenuItem;
+ private System.Windows.Forms.ToolStripStatusLabel statusStripSpacer;
}
}
diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs
index b6ca89679..ab7d037f7 100644
--- a/Greenshot/Forms/ImageEditorForm.cs
+++ b/Greenshot/Forms/ImageEditorForm.cs
@@ -66,6 +66,11 @@ namespace Greenshot {
// whether part of the editor controls are disabled depending on selected item(s)
private bool _controlsDisabledDueToConfirmable;
+ ///
+ /// All provided zoom values (in percents) in ascending order.
+ ///
+ private readonly Fraction[] ZOOM_VALUES = new Fraction[] { (1, 4), (1, 2), (2, 3), (3, 4), (1 ,1), (2, 1), (3, 1), (4, 1), (6, 1) };
+
///
/// An Implementation for the IImageEditor, this way Plugins have access to the HWND handles wich can be used with Win32 API calls.
///
@@ -422,20 +427,14 @@ namespace Greenshot {
///
///
///
- private void SurfaceSizeChanged(object sender, EventArgs e) {
- if (EditorConfiguration.MatchSizeToCapture) {
- // Set editor's initial size to the size of the surface plus the size of the chrome
- Size imageSize = Surface.Image.Size;
- Size currentFormSize = Size;
- Size currentImageClientSize = panel1.ClientSize;
- int minimumFormWidth = 650;
- int minimumFormHeight = 530;
- int newWidth = Math.Max(minimumFormWidth, currentFormSize.Width - currentImageClientSize.Width + imageSize.Width);
- int newHeight = Math.Max(minimumFormHeight, currentFormSize.Height - currentImageClientSize.Height + imageSize.Height);
- Size = new Size(newWidth, newHeight);
+ private void SurfaceSizeChanged(object sender, EventArgs e)
+ {
+ if (EditorConfiguration.MatchSizeToCapture)
+ {
+ Size = GetOptimalWindowSize();
}
dimensionsLabel.Text = Surface.Image.Width + "x" + Surface.Image.Height;
- ImageEditorFormResize(sender, new EventArgs());
+ AlignCanvasPositionAfterResize();
}
public ISurface Surface {
@@ -862,15 +861,34 @@ namespace Greenshot {
case Keys.Oemcomma: // Rotate CCW Ctrl + ,
RotateCcwToolstripButtonClick(sender, e);
break;
- case Keys.OemPeriod: // Rotate CW Ctrl + .
+ case Keys.OemPeriod: // Rotate CW Ctrl + .
RotateCwToolstripButtonClick(sender, e);
break;
- case Keys.Add: // Ctrl + +
- case Keys.Oemplus: // Ctrl + +
+ case Keys.Add: // Ctrl + Num+
+ case Keys.Oemplus: // Ctrl + +
+ ZoomInMenuItemClick(sender, e);
+ break;
+ case Keys.Subtract: // Ctrl + Num-
+ case Keys.OemMinus: // Ctrl + -
+ ZoomOutMenuItemClick(sender, e);
+ break;
+ case Keys.NumPad0: // Ctrl + Num0
+ case Keys.D0: // Ctrl + 0
+ ZoomSetValueMenuItemClick(zoomActualSizeMenuItem, e);
+ break;
+ case Keys.NumPad9: // Ctrl + Num9
+ case Keys.D9: // Ctrl + 9
+ ZoomBestFitMenuItemClick(sender, e);
+ break;
+ }
+ } else if (e.Modifiers.Equals(Keys.Control | Keys.Shift)) {
+ switch (e.KeyCode) {
+ case Keys.Add: // Ctrl + Shift + Num+
+ case Keys.Oemplus: // Ctrl + Shift + +
EnlargeCanvasToolStripMenuItemClick(sender, e);
break;
- case Keys.Subtract: // Ctrl + -
- case Keys.OemMinus: // Ctrl + -
+ case Keys.Subtract: // Ctrl + Shift + Num-
+ case Keys.OemMinus: // Ctrl + Shift + -
ShrinkCanvasToolStripMenuItemClick(sender, e);
break;
}
@@ -1446,28 +1464,178 @@ namespace Greenshot {
}
private void ImageEditorFormResize(object sender, EventArgs e) {
+ AlignCanvasPositionAfterResize();
+ }
+
+ private void AlignCanvasPositionAfterResize() {
if (Surface?.Image == null || panel1 == null) {
return;
}
- Size imageSize = Surface.Image.Size;
- Size currentClientSize = panel1.ClientSize;
var canvas = Surface as Control;
+ Size canvasSize = canvas.Size;
+ Size currentClientSize = panel1.ClientSize;
Panel panel = (Panel) canvas?.Parent;
if (panel == null) {
return;
}
int offsetX = -panel.HorizontalScroll.Value;
int offsetY = -panel.VerticalScroll.Value;
- if (currentClientSize.Width > imageSize.Width) {
- canvas.Left = offsetX + (currentClientSize.Width - imageSize.Width) / 2;
+ if (currentClientSize.Width > canvasSize.Width) {
+ canvas.Left = offsetX + (currentClientSize.Width - canvasSize.Width) / 2;
} else {
canvas.Left = offsetX + 0;
}
- if (currentClientSize.Height > imageSize.Height) {
- canvas.Top = offsetY + (currentClientSize.Height - imageSize.Height) / 2;
+ if (currentClientSize.Height > canvasSize.Height) {
+ canvas.Top = offsetY + (currentClientSize.Height - canvasSize.Height) / 2;
} else {
canvas.Top = offsetY + 0;
}
}
+
+ ///
+ /// Compute a size as a sum of surface size and chrome.
+ /// Upper bound is working area of the screen. Lower bound is fixed value.
+ ///
+ private Size GetOptimalWindowSize() {
+ var surfaceSize = (Surface as Control).Size;
+ var chromeSize = GetChromeSize();
+ var newWidth = chromeSize.Width + surfaceSize.Width;
+ var newHeight = chromeSize.Height + surfaceSize.Height;
+
+ // Upper bound. Don't make it bigger than the available working area.
+ var maxWindowSize = GetAvailableScreenSpace();
+ newWidth = Math.Min(newWidth, maxWindowSize.Width);
+ newHeight = Math.Min(newHeight, maxWindowSize.Height);
+
+ // Lower bound. Don't make it smaller than a fixed value.
+ int minimumFormWidth = 650;
+ int minimumFormHeight = 530;
+ newWidth = Math.Max(minimumFormWidth, newWidth);
+ newHeight = Math.Max(minimumFormHeight, newHeight);
+
+ return new Size(newWidth, newHeight);
+ }
+
+ private Size GetChromeSize()
+ => Size - panel1.ClientSize;
+
+ ///
+ /// Compute a size that the form can take without getting out of working area of the screen.
+ ///
+ private Size GetAvailableScreenSpace() {
+ var screen = Screen.FromControl(this);
+ var screenBounds = screen.Bounds;
+ var workingArea = screen.WorkingArea;
+ if (Left > screenBounds.Left && Top > screenBounds.Top) {
+ return new Size(workingArea.Right - Left, workingArea.Bottom - Top);
+ } else {
+ return workingArea.Size;
+ }
+ }
+
+ private void ZoomInMenuItemClick(object sender, EventArgs e) {
+ var zoomValue = Surface.ZoomFactor;
+ var nextIndex = Array.FindIndex(ZOOM_VALUES, v => v > zoomValue);
+ var nextValue = nextIndex < 0 ? ZOOM_VALUES[ZOOM_VALUES.Length - 1] : ZOOM_VALUES[nextIndex];
+
+ ZoomSetValue(nextValue);
+ }
+
+ private void ZoomOutMenuItemClick(object sender, EventArgs e) {
+ var zoomValue = Surface.ZoomFactor;
+ var nextIndex = Array.FindLastIndex(ZOOM_VALUES, v => v < zoomValue);
+ var nextValue = nextIndex < 0 ? ZOOM_VALUES[0] : ZOOM_VALUES[nextIndex];
+
+ ZoomSetValue(nextValue);
+ }
+
+ private void ZoomSetValueMenuItemClick(object sender, EventArgs e) {
+ var senderMenuItem = (ToolStripMenuItem)sender;
+ var nextValue = Fraction.Parse((string)senderMenuItem.Tag);
+
+ ZoomSetValue(nextValue);
+ }
+
+ private void ZoomBestFitMenuItemClick(object sender, EventArgs e) {
+ var maxWindowSize = GetAvailableScreenSpace();
+ var chromeSize = GetChromeSize();
+ var maxImageSize = maxWindowSize - chromeSize;
+ var imageSize = Surface.Image.Size;
+
+ static bool isFit(Fraction scale, int source, int boundary)
+ => (int)(source * scale) <= boundary;
+
+ var nextIndex = Array.FindLastIndex(
+ ZOOM_VALUES,
+ zoom => isFit(zoom, imageSize.Width, maxImageSize.Width)
+ && isFit(zoom, imageSize.Height, maxImageSize.Height)
+ );
+ var nextValue = nextIndex < 0 ? ZOOM_VALUES[0] : ZOOM_VALUES[nextIndex];
+
+ ZoomSetValue(nextValue);
+ }
+
+ private void ZoomSetValue(Fraction value) {
+ var surface = Surface as Surface;
+ var panel = surface?.Parent as Panel;
+ if (panel == null)
+ {
+ return;
+ }
+ if (value == Surface.ZoomFactor)
+ {
+ return;
+ }
+
+ // Store scroll position
+ var rc = surface.GetVisibleRectangle(); // use visible rc by default
+ var size = surface.Size;
+ if (value > Surface.ZoomFactor) // being smart on zoom-in
+ {
+ var selection = surface.GetSelectionRectangle();
+ selection.Intersect(rc);
+ if (selection != Rectangle.Empty)
+ {
+ rc = selection; // zoom to visible part of selection
+ }
+ else
+ {
+ // if image fits completely to currently visible rc and there are no things to focus on
+ // - prefer top left corner to zoom-in as less disorienting for screenshots
+ if (size.Width < rc.Width)
+ {
+ rc.Width = 0;
+ }
+ if (size.Height < rc.Height)
+ {
+ rc.Height = 0;
+ }
+ }
+ }
+ var horizontalCenter = 1.0 * (rc.Left + rc.Width / 2) / size.Width;
+ var verticalCenter = 1.0 * (rc.Top + rc.Height / 2) / size.Height;
+
+ // Set the new zoom value
+ Surface.ZoomFactor = value;
+ Size = GetOptimalWindowSize();
+ AlignCanvasPositionAfterResize();
+
+ // Update zoom controls
+ zoomStatusDropDownBtn.Text = ((int)(100 * (double)value)).ToString() + "%";
+ var valueString = value.ToString();
+ foreach (var item in zoomMenuStrip.Items) {
+ if (item is ToolStripMenuItem menuItem) {
+ menuItem.Checked = menuItem.Tag as string == valueString;
+ }
+ }
+
+ // Restore scroll position
+ rc = surface.GetVisibleRectangle();
+ size = surface.Size;
+ panel.AutoScrollPosition = new Point(
+ (int)(horizontalCenter * size.Width) - rc.Width / 2,
+ (int)(verticalCenter * size.Height) - rc.Height / 2
+ );
+ }
}
}
diff --git a/Greenshot/Forms/ImageEditorForm.resx b/Greenshot/Forms/ImageEditorForm.resx
index e4188604b..025543b10 100644
--- a/Greenshot/Forms/ImageEditorForm.resx
+++ b/Greenshot/Forms/ImageEditorForm.resx
@@ -937,6 +937,84 @@
BIhPAPEZIL7CAAQ6fptA+D+IJskFIM2cgtoMKm6rQfg/iEY3oB9oC8jWozBbgXquAvFykGYQkDJuZlBy
WQvC/0E0QRfANIJoLmF9BnXPHTD8H8QmyQD9wBMMSPg/iE20ATK6uQwWUTeR8X8Qn2gDHJOfM6Dh/yA+
igHkZijqZSZyXQAA4IG1TpHFZ2gAAAAASUVORK5CYII=
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m
+ dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJKSURBVDhPY/j//z+DX8FVDBxZ/ZAhqeWVRkrbm7lA
+ fB+If0HpuSBxkDxIHU4DIqruB0bXPrzftODpia0n3+668/zLiaNXPh3oXf7yFEgcJA9SBzbALeMsCvbI
+ Oq/hk3fx/rSND3ccufH60MuPP259+vb7+etPP28/evPt7PztT3b5AuVB6sAGWMUcQMdz83svnth96cWB
+ q48/ngBpBor9B9FP3n47d+3JpxMlEy6dAqkDG6Djtwkd35+77e72M/feXbj78suDd19+fQCK/QfRID5I
+ fOme+3tA6sAGqLitRse/dp5/fgCkGMj+j44/fvv97PC118eA7F9gA5Rc1qLj+wu239sNsgmk+Ofvv5+B
+ Yv9BNDgsPv68tWrfw0MgdWAD1D13oOO52W3nz+6/+urw/ZdfT4M0AcXgYQAMyHPF3RcvgdSBDXBwcGCw
+ s7NjsLW1ZbCxsWEwd8q0Mgo+/GLe5gdnbz77fBoU+mCbgfSz998vbtj/6pRxyMn7egHHILGAbIC1tbU8
+ 0JDijsl7/ltFXnjVOOP5pZNXvpx+/u7H9VNXv5zpmPvymk3crfvmkdcDDYPPQNIBzACgRi03N/eaHTv2
+ /BcVFWtWs2qxc0x+PheI7wPxLyg91z7xiYZF1E0GFAOAtlsEBga3HTly5r+iolIPCwuLqpJxCYNTyisM
+ DDSAAcUAoO3eCQkpEy5evPtfT89gGlCzMRAzEG2Aubl5ya1br/7b2zvPY2VldQFpJskAPT09LRERkRag
+ 5hiYZhAWlrEhzgDy8X8GAJItIDq7n94UAAAAAElFTkSuQmCC
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m
+ dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIySURBVDhPY/j//z+DtrY2g559IYNfwVU4jqx+yJDU
+ 8kojpe3NXCC+D8S/oPRckDhIHqQObACyRhiOqLofGF378H7Tgqcntp58u+vO8y8njl75dKB3+ctTIHGQ
+ PEgd2AC3jLMo2CPrvIZP3sX70zY+3HHkxutDj958O/vk7bdzIAxiz9/+ZJcvUB6kDmyAVcwBdDw3v/fi
+ id2XXhy4+vjjCZhmGL725NOJkgmXToHUgQ3Q8duEju/P3XZ3+5l77y7cffnlAToGiS/dc38PSB3YABW3
+ 1ej4187zzw+AFAPZ/9Hxx2+/nx2+9voYkP0LbICSy1p0fH/B9nu7QTaBFH/69vs5Mn798eetVfseHgKp
+ Axug7rkDHc/Nbjt/dv/VV4fvv/x6Gj0MgAF5rrj74iWQOrABDg4ODHZ2dgy2trYMNjY2DOZOmVZGwYdf
+ zNv84OzNZ59RDHj2/vvFDftfnTIOOXlfL+AYJBaQDbC2tpYHGlLcMXnPf6vIC68aZzy/dPLKl9PP3/24
+ furqlzMdc19es4m7dd888nqgYfAZSDqAGQDUqOXm5l6zY8ee/6KiYs1qVi12jsnP5wLxfSD+BaXn2ic+
+ 0bCIusmAYgDQdovAwOC2I0fO/FdUVOphYWFRVTIuYXBKeYWBgQYwoBgAtN07ISFlwsWLd//r6RlMA2o2
+ BmIGog0wNzcvuXXr1X97e+d5rKysLiDNJBmgp6enJSIi0gLUHAPTDMLCMjbEGUA+/s8AAJUZIgOF4ptY
+ AAAAAElFTkSuQmCC
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m
+ dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJISURBVDhPnZLLaxNRFIfvIvkLTF0J0uAjNDKoWaTk
+ bS1RUYshLowWqZqFD/BBs/KxUEMoaKEgiJuRbqRQ6UaojTqUYGpJYmpMSFuMxklK2mmmmba2kzSZINd7
+ pk1p4qa6+Djn3vs73x24gzDGSKvVIsp6B3XcntzEdS+LLnt5jdtXoAksQdqoNOzDOeRkwdbBGufuso4L
+ D7Lso/7Z0HBYeP+DE0OfkiuB3oF8BPbhHHKywH51oo7j12OaUzfj7ADDhTJ8MbNclOZWSlUOgH5wdD50
+ mpxDThYYOgON0Ld646F0XsyQHgOFpYpcgZywNuPpS0QgJwsOdLxphKXfpkdAQHq8KErL0EOFNfSvGJaB
+ nCzYY3/diPQuxgUgmBfWMHx6Tih9gQrrX6XqXHBqYRxyskDdPtQI2z/y8wMISI8r1d+rMAwV1iAYHM1+
+ hJws2H/C3wh9wxebyC4UZ0iPAV4oyxVYKkpc95N4AnKywGazIYvFgsxmMzKZTEjfds1w2BmcH2JmvxdW
+ K5svAIjlKj8cLCR1Z8MsdWZ8/RW2CoxG424i6e55xmCD6yv/8AWXCCfFz9xieToyKUZ76PyU6WKK1bum
+ HYec0fX/oCYggy12+7H7fj+Dm5p2Pt5n8FqOXOFoAkuQNiptvZTTtJ7/huoE5PZWh8PpGxuL4uZm9VOF
+ QrFXrfOgNjf/F0SA6gTk9pNdXe6+eDyNKergczKsI6BtC/R6vSeV4rHVevSlUqlsh+F/ElAU1aJSqbxk
+ uLM2DOzYZdqe4P/B6A86Ah9NBTgWLgAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m
+ dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJXSURBVDhPnZLda1JhHMefC/0Lcl0FMelFZhwqLxy+
+ t4YV1UjsImvFKi+qQS9MuujlohIZ1GAQjG7O2k0ERdALpW3SZNpQ0zllall6NKwzj1OWczId8fT8zuaY
+ drO6+PBwvs/393kezjkIY4ykUimitNdQ19XoGqabGXTOyknMtjmawBBqqysNOexDjxesH6xz4gZjOHU7
+ w9wd+eF96yuMfmPL3o8zJdfA05wfctiHHi/QXwg2cPBSSHLkcpgZepVxeD7nJ+YXaz9LlWU2X6p+/T5X
+ CT62Z0ePkn3o8QJFt6sZ+spA2DsWmXVlC5VMrzWESYZBQp6nYtmS1zIY8UOPF+zqet0MQ79L2kEQSBWn
+ i+XaPMlwMldOQwY8cTJO6PGCbfrnzdTeh1i+CMDJJFu7AeCO5SehxwvEnS+aYUbsqTEY5n4tJarLvxdI
+ hmGF9wCCZx8yE9DjBTsPOZqhe22h4HiUc8+VqtnT1/2YZBhWuAV5kVN998MR6PECnU6HNBoNUqvVSKVS
+ IXnHRcVeo3t2+E06mOYW4zBUp7BQTb0c5/yy4z6GOja58hXWC5RK5VYi6et/6MQK0zR35xEb8c2UP7HF
+ pbg/Wg7007mY6kyCkZvihj3GwMp/UBeQwTa9/sAth8OJW1o239uhsGr2nWdpAkOora609mxW0n7yC2oQ
+ kNPbDQajzeMJ4NZW8QOBQLBdLLOgDjP3F0SAGgTk9MM9PebBcDiJKWr3EBmWEdCGBXK53JJIcFir3T8s
+ FAo7YfifBBRFtYlEIisZ7q4PA5u2qDYm+H8w+gNv9h/ta4LougAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHYSURBVDhPY8AH4ltfa6S0vZ6b3Pr6PhD/AtEgPkgcqgQ3
+ iKi6Hxhd8/B+0/ynJ7acfLvrzrPPJ45c+Xigd9nLUyBxkDxUKSZwyzmj4Z176f7UjQ92HL7++tCjN9/O
+ Pn7z7RwIg9jztz3e5QOUB6mDakEFVjH75xb0Xjyx++KLA1cefToO0wzD1558OlE84eJpkDqoFlSg7bvp
+ /pytd3aADMCFl+6+vwekDqoFFSi7rf614/xzuGJ0Fzx+++3soauvjoHUQbWgAiXnNffn77i3G6wZqBib
+ ASv3PTgEUgfVggrUPLfPzWo/d3bv5VeH77/4fBrdgEevv54r7rpwCaQOqgUVWDpmWhkGHXoxf/P9szef
+ fkIx4Nn7b5fW73t5yjj45H2doKOYsWBpaSlvbW1d3DF5z3/LyAuvGqY/vXTiyqfTz999v37qyucz7fNe
+ XrOOvXXfNOIaZjqwsbHRcnV1r9mxY89/UVHRZlXLZjuH5GdzHZOf3XdMevYLRIP49vFPMW0G2moRGBjc
+ duTImf8KCko9bGxsqlApwgBos098fPKEixfv/tfT05/KyspqDJUiDpiZmZXcuvXqv52d8zxmZmYXqDDx
+ wMDAQEtYWLgFaHMMVIhegIEBADK7VwLsrsplAAAAAElFTkSuQmCC
@@ -1026,4 +1104,7 @@
17, 17
+
+ 782, 17
+
\ No newline at end of file
diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj
index 1b25c59a2..080651ceb 100644
--- a/Greenshot/Greenshot.csproj
+++ b/Greenshot/Greenshot.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/Greenshot/icons/fugue/magnifier-zoom-actual.png b/Greenshot/icons/fugue/magnifier-zoom-actual.png
new file mode 100644
index 000000000..21cf71d63
Binary files /dev/null and b/Greenshot/icons/fugue/magnifier-zoom-actual.png differ
diff --git a/Greenshot/icons/fugue/magnifier-zoom-fit.png b/Greenshot/icons/fugue/magnifier-zoom-fit.png
new file mode 100644
index 000000000..8364359fd
Binary files /dev/null and b/Greenshot/icons/fugue/magnifier-zoom-fit.png differ
diff --git a/Greenshot/icons/fugue/magnifier-zoom-in.png b/Greenshot/icons/fugue/magnifier-zoom-in.png
new file mode 100644
index 000000000..800ec1205
Binary files /dev/null and b/Greenshot/icons/fugue/magnifier-zoom-in.png differ
diff --git a/Greenshot/icons/fugue/magnifier-zoom-out.png b/Greenshot/icons/fugue/magnifier-zoom-out.png
new file mode 100644
index 000000000..3ec2b7a5d
Binary files /dev/null and b/Greenshot/icons/fugue/magnifier-zoom-out.png differ
diff --git a/Greenshot/icons/fugue/magnifier-zoom.png b/Greenshot/icons/fugue/magnifier-zoom.png
new file mode 100644
index 000000000..941b10356
Binary files /dev/null and b/Greenshot/icons/fugue/magnifier-zoom.png differ
diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss
index b2fd8e371..f15a578aa 100644
--- a/Greenshot/releases/innosetup/setup.iss
+++ b/Greenshot/releases/innosetup/setup.iss
@@ -1,642 +1,656 @@
-#define ExeName "Greenshot"
-#define Version GetEnv('BuildVersionSimple')
-#define FileVersion GetEnv('AssemblyInformationalVersion')
-#define BaseDir "..\..\.."
-#define ReleaseDir "..\..\bin\Release\net472"
-#define BinDir "bin\Release\net472"
-
-; Include the scripts to install .NET Framework
-; See http://www.codeproject.com/KB/install/dotnetfx_innosetup_instal.aspx
-#include "scripts\products.iss"
-#include "scripts\products\stringversion.iss"
-#include "scripts\products\winversion.iss"
-#include "scripts\products\fileversion.iss"
-#include "scripts\products\msi20.iss"
-#include "scripts\products\msi31.iss"
-#include "scripts\products\dotnetfxversion.iss"
-#include "scripts\products\dotnetfx47.iss"
-
-[Files]
-Source: {#ReleaseDir}\Greenshot.exe; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
-Source: {#ReleaseDir}\GreenshotPlugin.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
-Source: {#ReleaseDir}\Greenshot.exe.config; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
-Source: {#ReleaseDir}\log4net.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
-Source: {#ReleaseDir}\Dapplo.Http*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
-Source: {#ReleaseDir}\Dapplo.Log.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
-Source: {#ReleaseDir}\Svg.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
-Source: {#ReleaseDir}\Fizzler.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
-Source: {#ReleaseDir}\Newtonsoft.Json.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
-Source: ..\..\log4net.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion
-Source: {#ReleaseDir}\checksum.SHA256; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
-;Source: ..\greenshot-defaults.ini; DestDir: {app}; Flags: overwritereadonly ignoreversion replacesameversion
-Source: ..\additional_files\installer.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion
-Source: ..\additional_files\license.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion
-Source: ..\additional_files\readme.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion
-
-; Core language files
-Source: ..\..\Languages\*nl-NL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*en-US*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*de-DE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion;
-
-; Additional language files
-Source: ..\..\Languages\*ar-SY*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\arSY; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*ca-CA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\caCA; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*cs-CZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\csCZ; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*da-DK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\daDK; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*de-x-franconia*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\dexfranconia; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*el-GR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\elGR; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*es-ES*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\esES; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*et-EE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\etEE; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*fa-IR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\faIR; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*fi-FI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\fiFI; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*fr-FR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frFR; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*fr-QC*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frQC; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*he-IL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\heIL; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*hu-HU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\huHU; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*id-ID*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\idID; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*it-IT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\itIT; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*ja-JP*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\jaJP; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*ko-KR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\koKR; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*kab-DZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\kabDZ; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*lt-LT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ltLT; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*lv-LV*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\lvLV; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*nn-NO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\nnNO; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*pl-PL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\plPL; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*pt-BR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptBR; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*pt-PT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptPT; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*ro-RO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\roRO; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*ru-RU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ruRU; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*sk-SK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\skSK; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*sl-SI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\slSI; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*sr-RS*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\srRS; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*sv-SE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\svSE; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*tr-TR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\trTR; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*uk-UA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ukUA; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*vi-VN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\viVN; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*zh-CN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhCN; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: ..\..\Languages\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion;
-
-;Office Plugin
-Source: {#BaseDir}\GreenshotOfficePlugin\{#BinDir}\GreenshotOfficePlugin.dll; DestDir: {app}\Plugins\GreenshotOfficePlugin; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-;OCR Plugin
-Source: {#BaseDir}\GreenshotOCRPlugin\{#BinDir}\GreenshotOCRPlugin.dll; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotOCRPlugin\Languages\language_ocr*.xml; DestDir: {app}\Languages\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe.config; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-;JIRA Plugin
-Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\GreenshotJiraPlugin.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\Dapplo.Jira.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotJiraPlugin\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion;
-;Imgur Plugin
-Source: {#BaseDir}\GreenshotImgurPlugin\{#BinDir}\GreenshotImgurPlugin.dll; DestDir: {app}\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotImgurPlugin\Languages\language_imgur*.xml; DestDir: {app}\Languages\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion;
-;Box Plugin
-Source: {#BaseDir}\GreenshotBoxPlugin\{#BinDir}\GreenshotBoxPlugin.dll; DestDir: {app}\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotBoxPlugin\Languages\language_box*.xml; DestDir: {app}\Languages\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion;
-;DropBox Plugin
-Source: {#BaseDir}\GreenshotDropBoxPlugin\{#BinDir}\GreenshotDropboxPlugin.dll; DestDir: {app}\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotDropBoxPlugin\Languages\language_dropbox*.xml; DestDir: {app}\Languages\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion;
-;Flickr Plugin
-Source: {#BaseDir}\GreenshotFlickrPlugin\{#BinDir}\GreenshotFlickrPlugin.dll; DestDir: {app}\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotFlickrPlugin\Languages\language_flickr*.xml; DestDir: {app}\Languages\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion;
-;Photobucket Plugin
-Source: {#BaseDir}\GreenshotPhotobucketPlugin\{#BinDir}\GreenshotPhotobucketPlugin.dll; DestDir: {app}\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotPhotobucketPlugin\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion;
-;Picasa Plugin
-Source: {#BaseDir}\GreenshotPicasaPlugin\{#BinDir}\GreenshotPicasaPlugin.dll; DestDir: {app}\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotPicasaPlugin\Languages\language_picasa*.xml; DestDir: {app}\Languages\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly ignoreversion replacesameversion;
-;Confluence Plugin
-Source: {#BaseDir}\GreenshotConfluencePlugin\{#BinDir}\GreenshotConfluencePlugin.dll; DestDir: {app}\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotConfluencePlugin\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion;
-;ExternalCommand Plugin
-Source: {#BaseDir}\GreenshotExternalCommandPlugin\{#BinDir}\GreenshotExternalCommandPlugin.dll; DestDir: {app}\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-Source: {#BaseDir}\GreenshotExternalCommandPlugin\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion;
-;Win 10 Plugin
-Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\GreenshotWin10Plugin.dll; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
-[Setup]
-; changes associations is used when the installer installs new extensions, it clears the explorer icon cache
-ChangesAssociations=yes
-AppId={#ExeName}
-AppName={#ExeName}
-AppMutex=F48E86D3-E34C-4DB7-8F8F-9A0EA55F0D08
-AppPublisher={#ExeName}
-AppPublisherURL=http://getgreenshot.org
-AppSupportURL=http://getgreenshot.org
-AppUpdatesURL=http://getgreenshot.org
-AppVerName={#ExeName} {#Version}
-AppVersion={#Version}
-ArchitecturesInstallIn64BitMode=x64
-Compression=lzma2/ultra64
-SolidCompression=yes
-DefaultDirName={code:DefDirRoot}\{#ExeName}
-DefaultGroupName={#ExeName}
-InfoBeforeFile=..\additional_files\readme.txt
-LicenseFile=..\additional_files\license.txt
-LanguageDetectionMethod=uilanguage
-MinVersion=6.1.7600
-OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE
-OutputDir=..\
-PrivilegesRequired=lowest
-SetupIconFile=..\..\icons\applicationIcon\icon.ico
-; Create a SHA1 signature
-; SignTool=SignTool sign /debug /fd sha1 /tr http://time.certum.pl /td sha1 $f
-; Append a SHA256 to the previous SHA1 signature (this is what as does)
-; SignTool=SignTool sign /debug /as /fd sha256 /tr http://time.certum.pl /td sha256 $f
-; SignedUninstaller=yes
-UninstallDisplayIcon={app}\{#ExeName}.exe
-Uninstallable=true
-VersionInfoCompany={#ExeName}
-VersionInfoProductName={#ExeName}
-VersionInfoProductTextVersion={#FileVersion}
-VersionInfoTextVersion={#FileVersion}
-VersionInfoVersion={#Version}
-; Reference a bitmap, max size 164x314
-WizardImageFile=installer-large.bmp
-; Reference a bitmap, max size 55x58
-WizardSmallImageFile=installer-small.bmp
-[Registry]
-; Delete all startup entries, so we don't have leftover values
-Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
-Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
-Root: HKCU32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64()
-Root: HKLM32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64()
-
-; delete filetype mappings
-; HKEY_LOCAL_USER - for current user only
-Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
-Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
-; HKEY_LOCAL_MACHINE - for all users when admin (with the noerror this doesn't matter)
-Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
-Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
-
-; Create the startup entries if requested to do so
-; HKEY_LOCAL_USER - for current user only
-Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: {app}\{#ExeName}.exe; Permissions: users-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: IsRegularUser
-; HKEY_LOCAL_MACHINE - for all users when admin
-Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: {app}\{#ExeName}.exe; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: not IsRegularUser
-
-; Register our own filetype for all users
-; HKEY_LOCAL_USER - for current user only
-Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
-Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
-Root: HKCU; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: "{app}\Greenshot.EXE,0"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
-Root: HKCU; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
-; HKEY_LOCAL_MACHINE - for all users when admin
-Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
-Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
-Root: HKLM; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: "{app}\Greenshot.EXE,0"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
-Root: HKLM; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
-
-[Icons]
-Name: {group}\{#ExeName}; Filename: {app}\{#ExeName}.exe; WorkingDir: {app}; AppUserModelID: "{#ExeName}"
-Name: {group}\Uninstall {#ExeName}; Filename: {uninstallexe}; WorkingDir: {app};
-Name: {group}\Readme.txt; Filename: {app}\readme.txt; WorkingDir: {app}
-Name: {group}\License.txt; Filename: {app}\license.txt; WorkingDir: {app}
-
-[Languages]
-Name: en; MessagesFile: compiler:Default.isl
-Name: cn; MessagesFile: Languages\ChineseSimplified.isl
-Name: de; MessagesFile: compiler:Languages\German.isl
-Name: es; MessagesFile: compiler:Languages\Spanish.isl
-Name: fi; MessagesFile: compiler:Languages\Finnish.isl
-Name: fr; MessagesFile: compiler:Languages\French.isl
-Name: nl; MessagesFile: compiler:Languages\Dutch.isl
-Name: lt; MessagesFile: Languages\Latvian.isl
-Name: nn; MessagesFile: Languages\NorwegianNynorsk.isl
-Name: sr; MessagesFile: Languages\SerbianCyrillic.isl
-Name: sv; MessagesFile: Languages\Swedish.isl
-Name: uk; MessagesFile: compiler:Languages\Ukrainian.isl
-
-[Tasks]
-Name: startup; Description: {cm:startup}
-
-[CustomMessages]
-
-de.confluence=Confluence Plug-in
-de.default=Standard installation
-en.office=Microsoft Office Plug-in
-de.externalcommand=Externes Kommando Plug-in
-de.imgur=Imgur Plug-in (Siehe: http://imgur.com)
-de.jira=Jira Plug-in
-de.language=Zusätzliche Sprachen
-de.ocr=OCR Plug-in (benötigt Microsoft Office Document Imaging (MODI))
-de.optimize=Optimierung der Leistung, kann etwas dauern.
-de.startgreenshot={#ExeName} starten
-de.startup={#ExeName} starten wenn Windows hochfährt
-de.win10=Windows 10 Plug-in
-
-en.confluence=Confluence plug-in
-en.default=Default installation
-en.office=Microsoft Office plug-in
-en.externalcommand=Open with external command plug-in
-en.imgur=Imgur plug-in (See: http://imgur.com)
-en.jira=Jira plug-in
-en.language=Additional languages
-en.ocr=OCR plug-in (needs Microsoft Office Document Imaging (MODI))
-en.optimize=Optimizing performance, this may take a while.
-en.startgreenshot=Start {#ExeName}
-en.startup=Start {#ExeName} with Windows start
-en.win10=Windows 10 plug-in
-
-es.confluence=Extensión para Confluence
-es.default=${default}
-es.externalcommand=Extensión para abrir con programas externos
-es.imgur=Extensión para Imgur (Ver http://imgur.com)
-es.jira=Extensión para Jira
-es.language=Idiomas adicionales
-es.ocr=Extensión para OCR (necesita Microsoft Office Document Imaging (MODI))
-es.optimize=Optimizando rendimiento; por favor, espera.
-es.startgreenshot=Lanzar {#ExeName}
-es.startup=Lanzar {#ExeName} al iniciarse Windows
-es.win10=Extensión para Windows 10
-
-fi.confluence=Confluence-liitännäinen
-fi.default=${default}
-fi.office=Microsoft-Office-liitännäinen
-fi.externalcommand=Avaa Ulkoinen komento-liitännäisellä
-fi.imgur=Imgur-liitännäinen (Katso: http://imgur.com)
-fi.jira=Jira-liitännäinen
-fi.language=Lisäkielet
-fi.ocr=OCR-liitännäinen (Tarvitaan: Microsoft Office Document Imaging (MODI))
-fi.optimize=Optimoidaan suorituskykyä, tämä voi kestää hetken.
-fi.startgreenshot=Käynnistä {#ExeName}
-fi.startup=Käynnistä {#ExeName} Windowsin käynnistyessä
-fi.win10=Windows 10-liitännäinen
-
-fr.confluence=Greffon Confluence
-fr.default=${default}
-fr.office=Greffon Microsoft Office
-fr.externalcommand=Ouvrir avec le greffon de commande externe
-fr.imgur=Greffon Imgur (Voir: http://imgur.com)
-fr.jira=Greffon Jira
-fr.language=Langues additionnelles
-fr.ocr=Greffon OCR (nécessite Document Imaging de Microsoft Office [MODI])
-fr.optimize=Optimisation des performances, Ceci peut prendre un certain temps.
-fr.startgreenshot=Démarrer {#ExeName}
-fr.startup=Lancer {#ExeName} au démarrage de Windows
-fr.win10=Greffon Windows 10
-
-lt.confluence=Confluence spraudnis
-lt.default=${default}
-lt.office=Microsoft Office spraudnis
-lt.externalcommand=Pielāgotu darbību spraudnis
-lt.imgur=Imgur spraudnis (Vairāk šeit: http://imgur.com)
-lt.jira=Jira spraudnis
-lt.language=Papildus valodas
-lt.ocr=OCR spraudnis (nepieciešams Microsoft Office Document Imaging (MODI))
-lt.optimize=Uzlaboju veikstpēju, tas prasīs kādu laiciņu.
-lt.startgreenshot=Palaist {#ExeName}
-lt.startup=Palaist {#ExeName} uzsākot darbus
-lt.win10=Windows 10 spraudnis
-
-nl.confluence=Confluence plug-in
-nl.default=Standaardinstallatie
-nl.office=Microsoft Office plug-in
-nl.externalcommand=Openen met extern commando plug-in
-nl.imgur=Imgur plug-in (zie: http://imgur.com)
-nl.jira=Jira plug-in
-nl.language=Extra talen
-nl.ocr=OCR plug-in (vereist Microsoft Office Document Imaging (MODI))
-nl.optimize=Prestaties verbeteren, even geduld.
-nl.startgreenshot={#ExeName} starten
-nl.startup={#ExeName} automatisch starten met Windows
-nl.win10=Windows 10 plug-in
-
-nn.confluence=Confluence-tillegg
-nn.default=Default installation
-nn.office=Microsoft Office Tillegg
-nn.externalcommand=Tillegg for å opne med ekstern kommando
-nn.imgur=Imgur-tillegg (sjå http://imgur.com)
-nn.jira=Jira-tillegg
-nn.language=Andre språk
-nn.ocr=OCR-tillegg (krev Microsoft Office Document Imaging (MODI))
-nn.optimize=Optimaliserar ytelse, dette kan ta litt tid...
-nn.startgreenshot=Start {#ExeName}
-nn.startup=Start {#ExeName} når Windows startar
-nn.win10=Windows 10 Tillegg
-
-sr.confluence=Прикључак за Конфлуенс
-sr.default=${default}
-sr.externalcommand=Отвори са прикључком за спољне наредбе
-sr.imgur=Прикључак за Имиџер (http://imgur.com)
-sr.jira=Прикључак за Џиру
-sr.language=Додатни језици
-sr.ocr=OCR прикључак (захтева Microsoft Office Document Imaging (MODI))
-sr.optimize=Оптимизујем перформансе…
-sr.startgreenshot=Покрени Гриншот
-sr.startup=Покрени програм са системом
-sr.win10=Прикључак за Windows 10
-
-sv.startup=Starta {#ExeName} med Windows
-sv.startgreenshot=Starta {#ExeName}
-sv.jira=Jira-insticksprogram
-sv.confluence=Confluence-insticksprogram
-sv.externalcommand=Öppna med externt kommando-insticksprogram
-sv.ocr=OCR-insticksprogram (kräver Microsoft Office Document Imaging (MODI))
-sv.imgur=Imgur-insticksprogram (Se: http://imgur.com)
-sv.language=Ytterligare språk
-sv.optimize=Optimerar prestanda, detta kan ta en stund.
-sv.win10=Windows 10-insticksprogram
-
-uk.confluence=Плагін Confluence
-uk.default=${default}
-uk.externalcommand=Плагін запуску зовнішньої команди
-uk.imgur=Плагін Imgur (див.: http://imgur.com)
-uk.jira=Плагін Jira
-uk.language=Додаткові мови
-uk.ocr=Плагін OCR (потребує Microsoft Office Document Imaging (MODI))
-uk.optimize=Оптимізація продуктивності, це може забрати час.
-uk.startgreenshot=Запустити {#ExeName}
-uk.startup=Запускати {#ExeName} під час запуску Windows
-uk.win10=Плагін Windows 10
-
-cn.confluence=Confluence插件
-cn.default=${default}
-cn.externalcommand=使用外部命令打开插件
-cn.imgur=Imgur插件( (请访问: http://imgur.com))
-cn.jira=Jira插件
-cn.language=其它语言
-cn.ocr=OCR插件(需要Microsoft Office Document Imaging (MODI)的支持)
-cn.optimize=正在优化性能,这可能需要一点时间。
-cn.startgreenshot=启动{#ExeName}
-cn.startup=让{#ExeName}随Windows一起启动
-cn.win10=Windows 10插件
-
-[Types]
-Name: "default"; Description: "{cm:default}"
-Name: "full"; Description: "{code:FullInstall}"
-Name: "compact"; Description: "{code:CompactInstall}"
-Name: "custom"; Description: "{code:CustomInstall}"; Flags: iscustom
-
-[Components]
-Name: "greenshot"; Description: "Greenshot"; Types: default full compact custom; Flags: fixed
-Name: "plugins\office"; Description: {cm:office}; Types: default full custom; Flags: disablenouninstallwarning
-Name: "plugins\ocr"; Description: {cm:ocr}; Types: default full custom; Flags: disablenouninstallwarning
-Name: "plugins\jira"; Description: {cm:jira}; Types: full custom; Flags: disablenouninstallwarning
-Name: "plugins\imgur"; Description: {cm:imgur}; Types: default full custom; Flags: disablenouninstallwarning
-Name: "plugins\confluence"; Description: {cm:confluence}; Types: full custom; Flags: disablenouninstallwarning
-Name: "plugins\externalcommand"; Description: {cm:externalcommand}; Types: default full custom; Flags: disablenouninstallwarning
-;Name: "plugins\networkimport"; Description: "Network Import Plugin"; Types: full
-Name: "plugins\box"; Description: "Box Plugin"; Types: full custom; Flags: disablenouninstallwarning
-Name: "plugins\dropbox"; Description: "Dropbox Plugin"; Types: full custom; Flags: disablenouninstallwarning
-Name: "plugins\flickr"; Description: "Flickr Plugin"; Types: full custom; Flags: disablenouninstallwarning
-Name: "plugins\picasa"; Description: "Picasa Plugin"; Types: full custom; Flags: disablenouninstallwarning
-Name: "plugins\photobucket"; Description: "Photobucket Plugin"; Types: full custom; Flags: disablenouninstallwarning
-Name: "plugins\win10"; Description: "Windows 10 Plugin"; Types: default full custom; Flags: disablenouninstallwarning; Check: IsWindows10OrNewer()
-Name: "languages"; Description: {cm:language}; Types: full custom; Flags: disablenouninstallwarning
-Name: "languages\arSY"; Description: "العربية"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d')
-Name: "languages\caCA"; Description: "Català"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\csCZ"; Description: "Ceština"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\daDK"; Description: "Dansk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\dexfranconia"; Description: "Frängisch (Deutsch)"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\elGR"; Description: "ελληνικά"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('4')
-Name: "languages\esES"; Description: "Español"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\etEE"; Description: "Eesti"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
-Name: "languages\faIR"; Description: "پارسی"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d')
-Name: "languages\fiFI"; Description: "Suomi"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\frFR"; Description: "Français"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\frQC"; Description: "Français - Québec"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\heIL"; Description: "עִבְרִית"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('c')
-Name: "languages\huHU"; Description: "Magyar"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
-Name: "languages\idID"; Description: "Bahasa Indonesia"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\itIT"; Description: "Italiano"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\jaJP"; Description: "日本語"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('7')
-Name: "languages\koKR"; Description: "한국어"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8')
-Name: "languages\kabDZ"; Description: "Taqbaylit"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8')
-Name: "languages\ltLT"; Description: "Lietuvių"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3')
-Name: "languages\lvLV"; Description: "Latviski"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3')
-Name: "languages\nnNO"; Description: "Nynorsk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\plPL"; Description: "Polski"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
-Name: "languages\ptBR"; Description: "Português do Brasil"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\ptPT"; Description: "Português de Portugal"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\ruRU"; Description: "Pусский"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5')
-Name: "languages\roRO"; Description: "Română"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
-Name: "languages\skSK"; Description: "Slovenčina"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
-Name: "languages\slSI"; Description: "Slovenščina"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
-Name: "languages\srRS"; Description: "Српски"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5')
-Name: "languages\svSE"; Description: "Svenska"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
-Name: "languages\trTR"; Description: "Türk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('6')
-Name: "languages\ukUA"; Description: "Українська"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5')
-Name: "languages\viVN"; Description: "Việt"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('e')
-Name: "languages\zhCN"; Description: "简体中文"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('a')
-Name: "languages\zhTW"; Description: "繁體中文"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('9')
-[Code]
-// Do we have a regular user trying to install this?
-function IsRegularUser(): Boolean;
-begin
- Result := not (IsAdmin or IsAdminInstallMode);
-end;
-
-// The following code is used to select the installation path, this is localappdata if non poweruser
-function DefDirRoot(Param: String): String;
-begin
- if IsRegularUser then
- Result := ExpandConstant('{localappdata}')
- else
- Result := ExpandConstant('{pf}')
-end;
-
-
-function FullInstall(Param : String) : String;
-begin
- result := SetupMessage(msgFullInstallation);
-end;
-
-function CustomInstall(Param : String) : String;
-begin
- result := SetupMessage(msgCustomInstallation);
-end;
-
-function CompactInstall(Param : String) : String;
-begin
- result := SetupMessage(msgCompactInstallation);
-end;
-/////////////////////////////////////////////////////////////////////
-// The following uninstall code was found at:
-// http://stackoverflow.com/questions/2000296/innosetup-how-to-automatically-uninstall-previous-installed-version
-// and than modified to work in a 32/64 bit environment
-/////////////////////////////////////////////////////////////////////
-function GetUninstallStrings(): array of String;
-var
- sUnInstPath: String;
- sUnInstallString: String;
- asUninstallStrings : array of String;
- index : Integer;
-begin
- sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
- sUnInstallString := '';
- index := 0;
-
- // Retrieve uninstall string from HKLM32 or HKCU32
- if RegQueryStringValue(HKLM32, sUnInstPath, 'UninstallString', sUnInstallString) then
- begin
- SetArrayLength(asUninstallStrings, index + 1);
- asUninstallStrings[index] := sUnInstallString;
- index := index +1;
- end;
-
- if RegQueryStringValue(HKCU32, sUnInstPath, 'UninstallString', sUnInstallString) then
- begin
- SetArrayLength(asUninstallStrings, index + 1);
- asUninstallStrings[index] := sUnInstallString;
- index := index +1;
- end;
-
- // Only for Windows with 64 bit support: Retrieve uninstall string from HKLM64 or HKCU64
- if IsWin64 then
- begin
- if RegQueryStringValue(HKLM64, sUnInstPath, 'UninstallString', sUnInstallString) then
- begin
- SetArrayLength(asUninstallStrings, index + 1);
- asUninstallStrings[index] := sUnInstallString;
- index := index +1;
- end;
-
- if RegQueryStringValue(HKCU64, sUnInstPath, 'UninstallString', sUnInstallString) then
- begin
- SetArrayLength(asUninstallStrings, index + 1);
- asUninstallStrings[index] := sUnInstallString;
- index := index +1;
- end;
- end;
- Result := asUninstallStrings;
-end;
-
-/////////////////////////////////////////////////////////////////////
-procedure UnInstallOldVersions();
-var
- sUnInstallString: String;
- index: Integer;
- isUninstallMade: Boolean;
- iResultCode : Integer;
- asUninstallStrings : array of String;
-begin
- isUninstallMade := false;
- asUninstallStrings := GetUninstallStrings();
- for index := 0 to (GetArrayLength(asUninstallStrings) -1) do
- begin
- sUnInstallString := RemoveQuotes(asUninstallStrings[index]);
- if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
- isUninstallMade := true;
- end;
-
- // Wait a few seconds to prevent installation issues, otherwise files are removed in one process while the other tries to link to them
- if (isUninstallMade) then
- Sleep(2000);
-end;
-
-/////////////////////////////////////////////////////////////////////
-procedure CurStepChanged(CurStep: TSetupStep);
-begin
- if (CurStep=ssInstall) then
- begin
- UnInstallOldVersions();
- end;
-end;
-/////////////////////////////////////////////////////////////////////
-// End of unstall code
-/////////////////////////////////////////////////////////////////////
-
-// Build a list of greenshot parameters from the supplied installer parameters
-function GetParamsForGS(argument: String): String;
-var
- i: Integer;
- parametersString: String;
- currentParameter: String;
- foundStart: Boolean;
- foundNoRun: Boolean;
- foundLanguage: Boolean;
-begin
- foundNoRun := false;
- foundLanguage := false;
- foundStart := false;
- for i:= 0 to ParamCount() do begin
- currentParameter := ParamStr(i);
-
- // check if norun is supplied
- if Lowercase(currentParameter) = '/norun' then begin
- foundNoRun := true;
- continue;
- end;
-
- if foundStart then begin
- parametersString := parametersString + ' ' + currentParameter;
- foundStart := false;
- end
- else begin
- if Lowercase(currentParameter) = '/language' then begin
- foundStart := true;
- foundLanguage := true;
- parametersString := parametersString + ' ' + currentParameter;
- end;
- end;
- end;
- if not foundLanguage then begin
- parametersString := parametersString + ' /language ' + ExpandConstant('{language}');
- end;
- if foundNoRun then begin
- parametersString := parametersString + ' /norun';
- end;
- // For debugging comment out the following
- //MsgBox(parametersString, mbInformation, MB_OK);
-
- Result := parametersString;
-end;
-
-// Check if language group is installed
-function hasLanguageGroup(argument: String): Boolean;
-var
- keyValue: String;
- returnValue: Boolean;
-begin
- returnValue := true;
- if (RegQueryStringValue( HKLM, 'SYSTEM\CurrentControlSet\Control\Nls\Language Groups', argument, keyValue)) then begin
- if Length(keyValue) = 0 then begin
- returnValue := false;
- end;
- end;
- Result := returnValue;
-end;
-
-function hasDotNet() : boolean;
-begin
- Result := netfxspversion(NetFx4x, '') >= 71;
-end;
-
-// Initialize the setup
-function InitializeSetup(): Boolean;
-begin
- // Check for .NET and install 4.7.1 if we don't have it
- if not hasDotNet() then
- begin
- // Enhance installer, if needed, otherwise .NET installations won't work
- msi20('2.0');
- msi31('3.0');
-
- //install .net 4.7.1
- dotnetfx47(71);
- end;
- Result := true;
-end;
-
-function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean;
-var
- Version: TWindowsVersion;
-begin
- GetWindowsVersionEx(Version);
- Result :=
- (Version.Major > Major) or
- ((Version.Major = Major) and (Version.Minor >= Minor));
-end;
-
-function IsWindows10OrNewer: Boolean;
-begin
- Result := IsWindowsVersionOrNewer(10, 0);
-end;
-
-[Run]
-Filename: "{app}\{#ExeName}.exe"; Description: "{cm:startgreenshot}"; Parameters: "{code:GetParamsForGS}"; WorkingDir: "{app}"; Flags: nowait postinstall runasoriginaluser
-Filename: "http://getgreenshot.org/thank-you/?language={language}&version={#Version}"; Flags: shellexec runasoriginaluser
-
-[InstallDelete]
-Name: {app}; Type: dirifempty;
+#define ExeName "Greenshot"
+#define Version GetEnv('BuildVersionSimple')
+#define FileVersion GetEnv('AssemblyInformationalVersion')
+#define BaseDir "..\..\.."
+#define ReleaseDir "..\..\bin\Release\net472"
+#define BinDir "bin\Release\net472"
+
+; Include the scripts to install .NET Framework
+; See http://www.codeproject.com/KB/install/dotnetfx_innosetup_instal.aspx
+#include "scripts\products.iss"
+#include "scripts\products\stringversion.iss"
+#include "scripts\products\winversion.iss"
+#include "scripts\products\fileversion.iss"
+#include "scripts\products\msi20.iss"
+#include "scripts\products\msi31.iss"
+#include "scripts\products\dotnetfxversion.iss"
+#include "scripts\products\dotnetfx47.iss"
+
+[Files]
+Source: {#ReleaseDir}\Greenshot.exe; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
+Source: {#ReleaseDir}\GreenshotPlugin.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
+Source: {#ReleaseDir}\Greenshot.exe.config; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
+Source: {#ReleaseDir}\log4net.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
+Source: {#ReleaseDir}\Dapplo.Http*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
+Source: {#ReleaseDir}\Dapplo.Log.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
+Source: {#ReleaseDir}\Svg.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
+Source: {#ReleaseDir}\Fizzler.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
+Source: {#ReleaseDir}\Newtonsoft.Json.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
+Source: ..\..\log4net.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion
+Source: {#ReleaseDir}\checksum.SHA256; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
+;Source: ..\greenshot-defaults.ini; DestDir: {app}; Flags: overwritereadonly ignoreversion replacesameversion
+Source: ..\additional_files\installer.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion
+Source: ..\additional_files\license.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion
+Source: ..\additional_files\readme.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion
+
+; Core language files
+Source: ..\..\Languages\*nl-NL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*en-US*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*de-DE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion;
+
+; Additional language files
+Source: ..\..\Languages\*ar-SY*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\arSY; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*ca-CA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\caCA; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*cs-CZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\csCZ; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*da-DK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\daDK; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*de-x-franconia*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\dexfranconia; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*el-GR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\elGR; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*es-ES*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\esES; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*et-EE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\etEE; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*fa-IR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\faIR; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*fi-FI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\fiFI; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*fr-FR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frFR; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*fr-QC*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frQC; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*he-IL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\heIL; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*hu-HU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\huHU; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*id-ID*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\idID; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*it-IT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\itIT; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*ja-JP*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\jaJP; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*ko-KR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\koKR; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*kab-DZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\kabDZ; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*lt-LT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ltLT; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*lv-LV*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\lvLV; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*nn-NO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\nnNO; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*pl-PL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\plPL; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*pt-BR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptBR; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*pt-PT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptPT; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*ro-RO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\roRO; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*ru-RU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ruRU; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*sk-SK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\skSK; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*sl-SI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\slSI; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*sr-RS*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\srRS; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*sv-SE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\svSE; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*tr-TR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\trTR; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*uk-UA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ukUA; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*vi-VN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\viVN; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*zh-CN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhCN; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: ..\..\Languages\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion;
+
+;Office Plugin
+Source: {#BaseDir}\GreenshotOfficePlugin\{#BinDir}\GreenshotOfficePlugin.dll; DestDir: {app}\Plugins\GreenshotOfficePlugin; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+;OCR Plugin
+Source: {#BaseDir}\GreenshotOCRPlugin\{#BinDir}\GreenshotOCRPlugin.dll; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotOCRPlugin\Languages\language_ocr*.xml; DestDir: {app}\Languages\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe.config; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+;JIRA Plugin
+Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\GreenshotJiraPlugin.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\Dapplo.Jira.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotJiraPlugin\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion;
+;Imgur Plugin
+Source: {#BaseDir}\GreenshotImgurPlugin\{#BinDir}\GreenshotImgurPlugin.dll; DestDir: {app}\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotImgurPlugin\Languages\language_imgur*.xml; DestDir: {app}\Languages\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion;
+;Box Plugin
+Source: {#BaseDir}\GreenshotBoxPlugin\{#BinDir}\GreenshotBoxPlugin.dll; DestDir: {app}\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotBoxPlugin\Languages\language_box*.xml; DestDir: {app}\Languages\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion;
+;DropBox Plugin
+Source: {#BaseDir}\GreenshotDropBoxPlugin\{#BinDir}\GreenshotDropboxPlugin.dll; DestDir: {app}\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotDropBoxPlugin\Languages\language_dropbox*.xml; DestDir: {app}\Languages\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion;
+;Flickr Plugin
+Source: {#BaseDir}\GreenshotFlickrPlugin\{#BinDir}\GreenshotFlickrPlugin.dll; DestDir: {app}\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotFlickrPlugin\Languages\language_flickr*.xml; DestDir: {app}\Languages\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion;
+;Photobucket Plugin
+Source: {#BaseDir}\GreenshotPhotobucketPlugin\{#BinDir}\GreenshotPhotobucketPlugin.dll; DestDir: {app}\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotPhotobucketPlugin\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion;
+;Picasa Plugin
+Source: {#BaseDir}\GreenshotPicasaPlugin\{#BinDir}\GreenshotPicasaPlugin.dll; DestDir: {app}\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotPicasaPlugin\Languages\language_picasa*.xml; DestDir: {app}\Languages\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly ignoreversion replacesameversion;
+;Confluence Plugin
+Source: {#BaseDir}\GreenshotConfluencePlugin\{#BinDir}\GreenshotConfluencePlugin.dll; DestDir: {app}\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotConfluencePlugin\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion;
+;ExternalCommand Plugin
+Source: {#BaseDir}\GreenshotExternalCommandPlugin\{#BinDir}\GreenshotExternalCommandPlugin.dll; DestDir: {app}\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+Source: {#BaseDir}\GreenshotExternalCommandPlugin\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion;
+;Win 10 Plugin
+Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\GreenshotWin10Plugin.dll; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
+[Setup]
+; changes associations is used when the installer installs new extensions, it clears the explorer icon cache
+ChangesAssociations=yes
+AppId={#ExeName}
+AppName={#ExeName}
+AppMutex=F48E86D3-E34C-4DB7-8F8F-9A0EA55F0D08
+AppPublisher={#ExeName}
+AppPublisherURL=http://getgreenshot.org
+AppSupportURL=http://getgreenshot.org
+AppUpdatesURL=http://getgreenshot.org
+AppVerName={#ExeName} {#Version}
+AppVersion={#Version}
+ArchitecturesInstallIn64BitMode=x64
+Compression=lzma2/ultra64
+SolidCompression=yes
+DefaultDirName={code:DefDirRoot}\{#ExeName}
+DefaultGroupName={#ExeName}
+InfoBeforeFile=..\additional_files\readme.txt
+LicenseFile=..\additional_files\license.txt
+LanguageDetectionMethod=uilanguage
+MinVersion=6.1.7600
+OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE
+OutputDir=..\
+PrivilegesRequired=lowest
+SetupIconFile=..\..\icons\applicationIcon\icon.ico
+; Create a SHA1 signature
+; SignTool=SignTool sign /debug /fd sha1 /tr http://time.certum.pl /td sha1 $f
+; Append a SHA256 to the previous SHA1 signature (this is what as does)
+; SignTool=SignTool sign /debug /as /fd sha256 /tr http://time.certum.pl /td sha256 $f
+; SignedUninstaller=yes
+UninstallDisplayIcon={app}\{#ExeName}.exe
+Uninstallable=true
+VersionInfoCompany={#ExeName}
+VersionInfoProductName={#ExeName}
+VersionInfoProductTextVersion={#FileVersion}
+VersionInfoTextVersion={#FileVersion}
+VersionInfoVersion={#Version}
+; Reference a bitmap, max size 164x314
+WizardImageFile=installer-large.bmp
+; Reference a bitmap, max size 55x58
+WizardSmallImageFile=installer-small.bmp
+[Registry]
+; Delete all startup entries, so we don't have leftover values
+Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
+Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
+Root: HKCU32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64()
+Root: HKLM32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64()
+
+; delete filetype mappings
+; HKEY_LOCAL_USER - for current user only
+Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
+Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
+; HKEY_LOCAL_MACHINE - for all users when admin (with the noerror this doesn't matter)
+Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
+Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
+
+; Create the startup entries if requested to do so
+; HKEY_LOCAL_USER - for current user only
+Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: {app}\{#ExeName}.exe; Permissions: users-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: IsRegularUser
+; HKEY_LOCAL_MACHINE - for all users when admin
+Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: {app}\{#ExeName}.exe; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: not IsRegularUser
+
+; Register our own filetype for all users
+; HKEY_LOCAL_USER - for current user only
+Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
+Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
+Root: HKCU; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: "{app}\Greenshot.EXE,0"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
+Root: HKCU; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
+; HKEY_LOCAL_MACHINE - for all users when admin
+Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
+Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
+Root: HKLM; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: "{app}\Greenshot.EXE,0"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
+Root: HKLM; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
+
+[Icons]
+Name: {group}\{#ExeName}; Filename: {app}\{#ExeName}.exe; WorkingDir: {app}; AppUserModelID: "{#ExeName}"
+Name: {group}\Uninstall {#ExeName}; Filename: {uninstallexe}; WorkingDir: {app};
+Name: {group}\Readme.txt; Filename: {app}\readme.txt; WorkingDir: {app}
+Name: {group}\License.txt; Filename: {app}\license.txt; WorkingDir: {app}
+
+[Languages]
+Name: en; MessagesFile: compiler:Default.isl
+Name: cn; MessagesFile: Languages\ChineseSimplified.isl
+Name: de; MessagesFile: compiler:Languages\German.isl
+Name: es; MessagesFile: compiler:Languages\Spanish.isl
+Name: fi; MessagesFile: compiler:Languages\Finnish.isl
+Name: fr; MessagesFile: compiler:Languages\French.isl
+Name: nl; MessagesFile: compiler:Languages\Dutch.isl
+Name: lt; MessagesFile: Languages\Latvian.isl
+Name: nn; MessagesFile: Languages\NorwegianNynorsk.isl
+Name: ru; MessagesFile: compiler:Languages\Russian.isl
+Name: sr; MessagesFile: Languages\SerbianCyrillic.isl
+Name: sv; MessagesFile: Languages\Swedish.isl
+Name: uk; MessagesFile: compiler:Languages\Ukrainian.isl
+
+[Tasks]
+Name: startup; Description: {cm:startup}
+
+[CustomMessages]
+
+de.confluence=Confluence Plug-in
+de.default=Standard installation
+de.office=Microsoft Office Plug-in
+de.externalcommand=Externes Kommando Plug-in
+de.imgur=Imgur Plug-in (Siehe: http://imgur.com)
+de.jira=Jira Plug-in
+de.language=Zusätzliche Sprachen
+de.ocr=OCR Plug-in (benötigt Microsoft Office Document Imaging (MODI))
+de.optimize=Optimierung der Leistung, kann etwas dauern.
+de.startgreenshot={#ExeName} starten
+de.startup={#ExeName} starten wenn Windows hochfährt
+de.win10=Windows 10 Plug-in
+
+en.confluence=Confluence plug-in
+en.default=Default installation
+en.office=Microsoft Office plug-in
+en.externalcommand=Open with external command plug-in
+en.imgur=Imgur plug-in (See: http://imgur.com)
+en.jira=Jira plug-in
+en.language=Additional languages
+en.ocr=OCR plug-in (needs Microsoft Office Document Imaging (MODI))
+en.optimize=Optimizing performance, this may take a while.
+en.startgreenshot=Start {#ExeName}
+en.startup=Start {#ExeName} with Windows start
+en.win10=Windows 10 plug-in
+
+es.confluence=Extensión para Confluence
+es.default=${default}
+es.externalcommand=Extensión para abrir con programas externos
+es.imgur=Extensión para Imgur (Ver http://imgur.com)
+es.jira=Extensión para Jira
+es.language=Idiomas adicionales
+es.ocr=Extensión para OCR (necesita Microsoft Office Document Imaging (MODI))
+es.optimize=Optimizando rendimiento; por favor, espera.
+es.startgreenshot=Lanzar {#ExeName}
+es.startup=Lanzar {#ExeName} al iniciarse Windows
+es.win10=Extensión para Windows 10
+
+fi.confluence=Confluence-liitännäinen
+fi.default=${default}
+fi.office=Microsoft-Office-liitännäinen
+fi.externalcommand=Avaa Ulkoinen komento-liitännäisellä
+fi.imgur=Imgur-liitännäinen (Katso: http://imgur.com)
+fi.jira=Jira-liitännäinen
+fi.language=Lisäkielet
+fi.ocr=OCR-liitännäinen (Tarvitaan: Microsoft Office Document Imaging (MODI))
+fi.optimize=Optimoidaan suorituskykyä, tämä voi kestää hetken.
+fi.startgreenshot=Käynnistä {#ExeName}
+fi.startup=Käynnistä {#ExeName} Windowsin käynnistyessä
+fi.win10=Windows 10-liitännäinen
+
+fr.confluence=Greffon Confluence
+fr.default=${default}
+fr.office=Greffon Microsoft Office
+fr.externalcommand=Ouvrir avec le greffon de commande externe
+fr.imgur=Greffon Imgur (Voir: http://imgur.com)
+fr.jira=Greffon Jira
+fr.language=Langues additionnelles
+fr.ocr=Greffon OCR (nécessite Document Imaging de Microsoft Office [MODI])
+fr.optimize=Optimisation des performances, Ceci peut prendre un certain temps.
+fr.startgreenshot=Démarrer {#ExeName}
+fr.startup=Lancer {#ExeName} au démarrage de Windows
+fr.win10=Greffon Windows 10
+
+lt.confluence=Confluence spraudnis
+lt.default=${default}
+lt.office=Microsoft Office spraudnis
+lt.externalcommand=Pielāgotu darbību spraudnis
+lt.imgur=Imgur spraudnis (Vairāk šeit: http://imgur.com)
+lt.jira=Jira spraudnis
+lt.language=Papildus valodas
+lt.ocr=OCR spraudnis (nepieciešams Microsoft Office Document Imaging (MODI))
+lt.optimize=Uzlaboju veikstpēju, tas prasīs kādu laiciņu.
+lt.startgreenshot=Palaist {#ExeName}
+lt.startup=Palaist {#ExeName} uzsākot darbus
+lt.win10=Windows 10 spraudnis
+
+nl.confluence=Confluence plug-in
+nl.default=Standaardinstallatie
+nl.office=Microsoft Office plug-in
+nl.externalcommand=Openen met extern commando plug-in
+nl.imgur=Imgur plug-in (zie: http://imgur.com)
+nl.jira=Jira plug-in
+nl.language=Extra talen
+nl.ocr=OCR plug-in (vereist Microsoft Office Document Imaging (MODI))
+nl.optimize=Prestaties verbeteren, even geduld.
+nl.startgreenshot={#ExeName} starten
+nl.startup={#ExeName} automatisch starten met Windows
+nl.win10=Windows 10 plug-in
+
+nn.confluence=Confluence-tillegg
+nn.default=Default installation
+nn.office=Microsoft Office Tillegg
+nn.externalcommand=Tillegg for å opne med ekstern kommando
+nn.imgur=Imgur-tillegg (sjå http://imgur.com)
+nn.jira=Jira-tillegg
+nn.language=Andre språk
+nn.ocr=OCR-tillegg (krev Microsoft Office Document Imaging (MODI))
+nn.optimize=Optimaliserar ytelse, dette kan ta litt tid...
+nn.startgreenshot=Start {#ExeName}
+nn.startup=Start {#ExeName} når Windows startar
+nn.win10=Windows 10 Tillegg
+
+ru.confluence=Плагин Confluence
+ru.default=${default}
+ru.office=Плагин Microsoft Office
+ru.externalcommand=Открыть с плагином с помощью внешней команды
+ru.imgur=Плагин Imgur (смотрите https://imgur.com/)
+ru.jira=Плагин Jira
+ru.language=Дополнительные языки
+ru.ocr=Плагин OCR (требуется Microsoft Office Document Imaging (MODI))
+ru.optimize=Идет оптимизация производительности, это может занять некоторое время.
+ru.startgreenshot=Запустить {#ExeName}
+ru.startup=Запускать {#ExeName} при старте Windows
+ru.win10=Плагин Windows 10
+
+sr.confluence=Прикључак за Конфлуенс
+sr.default=${default}
+sr.externalcommand=Отвори са прикључком за спољне наредбе
+sr.imgur=Прикључак за Имиџер (http://imgur.com)
+sr.jira=Прикључак за Џиру
+sr.language=Додатни језици
+sr.ocr=OCR прикључак (захтева Microsoft Office Document Imaging (MODI))
+sr.optimize=Оптимизујем перформансе…
+sr.startgreenshot=Покрени Гриншот
+sr.startup=Покрени програм са системом
+sr.win10=Прикључак за Windows 10
+
+sv.startup=Starta {#ExeName} med Windows
+sv.startgreenshot=Starta {#ExeName}
+sv.jira=Jira-insticksprogram
+sv.confluence=Confluence-insticksprogram
+sv.externalcommand=Öppna med externt kommando-insticksprogram
+sv.ocr=OCR-insticksprogram (kräver Microsoft Office Document Imaging (MODI))
+sv.imgur=Imgur-insticksprogram (Se: http://imgur.com)
+sv.language=Ytterligare språk
+sv.optimize=Optimerar prestanda, detta kan ta en stund.
+sv.win10=Windows 10-insticksprogram
+
+uk.confluence=Плагін Confluence
+uk.default=${default}
+uk.externalcommand=Плагін запуску зовнішньої команди
+uk.imgur=Плагін Imgur (див.: http://imgur.com)
+uk.jira=Плагін Jira
+uk.language=Додаткові мови
+uk.ocr=Плагін OCR (потребує Microsoft Office Document Imaging (MODI))
+uk.optimize=Оптимізація продуктивності, це може забрати час.
+uk.startgreenshot=Запустити {#ExeName}
+uk.startup=Запускати {#ExeName} під час запуску Windows
+uk.win10=Плагін Windows 10
+
+cn.confluence=Confluence插件
+cn.default=${default}
+cn.externalcommand=使用外部命令打开插件
+cn.imgur=Imgur插件( (请访问: http://imgur.com))
+cn.jira=Jira插件
+cn.language=其它语言
+cn.ocr=OCR插件(需要Microsoft Office Document Imaging (MODI)的支持)
+cn.optimize=正在优化性能,这可能需要一点时间。
+cn.startgreenshot=启动{#ExeName}
+cn.startup=让{#ExeName}随Windows一起启动
+cn.win10=Windows 10插件
+
+[Types]
+Name: "default"; Description: "{cm:default}"
+Name: "full"; Description: "{code:FullInstall}"
+Name: "compact"; Description: "{code:CompactInstall}"
+Name: "custom"; Description: "{code:CustomInstall}"; Flags: iscustom
+
+[Components]
+Name: "greenshot"; Description: "Greenshot"; Types: default full compact custom; Flags: fixed
+Name: "plugins\office"; Description: {cm:office}; Types: default full custom; Flags: disablenouninstallwarning
+Name: "plugins\ocr"; Description: {cm:ocr}; Types: default full custom; Flags: disablenouninstallwarning
+Name: "plugins\jira"; Description: {cm:jira}; Types: full custom; Flags: disablenouninstallwarning
+Name: "plugins\imgur"; Description: {cm:imgur}; Types: default full custom; Flags: disablenouninstallwarning
+Name: "plugins\confluence"; Description: {cm:confluence}; Types: full custom; Flags: disablenouninstallwarning
+Name: "plugins\externalcommand"; Description: {cm:externalcommand}; Types: default full custom; Flags: disablenouninstallwarning
+;Name: "plugins\networkimport"; Description: "Network Import Plugin"; Types: full
+Name: "plugins\box"; Description: "Box Plugin"; Types: full custom; Flags: disablenouninstallwarning
+Name: "plugins\dropbox"; Description: "Dropbox Plugin"; Types: full custom; Flags: disablenouninstallwarning
+Name: "plugins\flickr"; Description: "Flickr Plugin"; Types: full custom; Flags: disablenouninstallwarning
+Name: "plugins\picasa"; Description: "Picasa Plugin"; Types: full custom; Flags: disablenouninstallwarning
+Name: "plugins\photobucket"; Description: "Photobucket Plugin"; Types: full custom; Flags: disablenouninstallwarning
+Name: "plugins\win10"; Description: "Windows 10 Plugin"; Types: default full custom; Flags: disablenouninstallwarning; Check: IsWindows10OrNewer()
+Name: "languages"; Description: {cm:language}; Types: full custom; Flags: disablenouninstallwarning
+Name: "languages\arSY"; Description: "العربية"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d')
+Name: "languages\caCA"; Description: "Català"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\csCZ"; Description: "Ceština"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\daDK"; Description: "Dansk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\dexfranconia"; Description: "Frängisch (Deutsch)"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\elGR"; Description: "ελληνικά"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('4')
+Name: "languages\esES"; Description: "Español"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\etEE"; Description: "Eesti"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
+Name: "languages\faIR"; Description: "پارسی"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d')
+Name: "languages\fiFI"; Description: "Suomi"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\frFR"; Description: "Français"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\frQC"; Description: "Français - Québec"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\heIL"; Description: "עִבְרִית"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('c')
+Name: "languages\huHU"; Description: "Magyar"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
+Name: "languages\idID"; Description: "Bahasa Indonesia"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\itIT"; Description: "Italiano"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\jaJP"; Description: "日本語"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('7')
+Name: "languages\koKR"; Description: "한국어"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8')
+Name: "languages\kabDZ"; Description: "Taqbaylit"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8')
+Name: "languages\ltLT"; Description: "Lietuvių"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3')
+Name: "languages\lvLV"; Description: "Latviski"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3')
+Name: "languages\nnNO"; Description: "Nynorsk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\plPL"; Description: "Polski"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
+Name: "languages\ptBR"; Description: "Português do Brasil"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\ptPT"; Description: "Português de Portugal"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\ruRU"; Description: "Pусский"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5')
+Name: "languages\roRO"; Description: "Română"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
+Name: "languages\skSK"; Description: "Slovenčina"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
+Name: "languages\slSI"; Description: "Slovenščina"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2')
+Name: "languages\srRS"; Description: "Српски"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5')
+Name: "languages\svSE"; Description: "Svenska"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1')
+Name: "languages\trTR"; Description: "Türk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('6')
+Name: "languages\ukUA"; Description: "Українська"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5')
+Name: "languages\viVN"; Description: "Việt"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('e')
+Name: "languages\zhCN"; Description: "简体中文"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('a')
+Name: "languages\zhTW"; Description: "繁體中文"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('9')
+[Code]
+// Do we have a regular user trying to install this?
+function IsRegularUser(): Boolean;
+begin
+ Result := not (IsAdmin or IsAdminInstallMode);
+end;
+
+// The following code is used to select the installation path, this is localappdata if non poweruser
+function DefDirRoot(Param: String): String;
+begin
+ if IsRegularUser then
+ Result := ExpandConstant('{localappdata}')
+ else
+ Result := ExpandConstant('{pf}')
+end;
+
+
+function FullInstall(Param : String) : String;
+begin
+ result := SetupMessage(msgFullInstallation);
+end;
+
+function CustomInstall(Param : String) : String;
+begin
+ result := SetupMessage(msgCustomInstallation);
+end;
+
+function CompactInstall(Param : String) : String;
+begin
+ result := SetupMessage(msgCompactInstallation);
+end;
+/////////////////////////////////////////////////////////////////////
+// The following uninstall code was found at:
+// http://stackoverflow.com/questions/2000296/innosetup-how-to-automatically-uninstall-previous-installed-version
+// and than modified to work in a 32/64 bit environment
+/////////////////////////////////////////////////////////////////////
+function GetUninstallStrings(): array of String;
+var
+ sUnInstPath: String;
+ sUnInstallString: String;
+ asUninstallStrings : array of String;
+ index : Integer;
+begin
+ sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
+ sUnInstallString := '';
+ index := 0;
+
+ // Retrieve uninstall string from HKLM32 or HKCU32
+ if RegQueryStringValue(HKLM32, sUnInstPath, 'UninstallString', sUnInstallString) then
+ begin
+ SetArrayLength(asUninstallStrings, index + 1);
+ asUninstallStrings[index] := sUnInstallString;
+ index := index +1;
+ end;
+
+ if RegQueryStringValue(HKCU32, sUnInstPath, 'UninstallString', sUnInstallString) then
+ begin
+ SetArrayLength(asUninstallStrings, index + 1);
+ asUninstallStrings[index] := sUnInstallString;
+ index := index +1;
+ end;
+
+ // Only for Windows with 64 bit support: Retrieve uninstall string from HKLM64 or HKCU64
+ if IsWin64 then
+ begin
+ if RegQueryStringValue(HKLM64, sUnInstPath, 'UninstallString', sUnInstallString) then
+ begin
+ SetArrayLength(asUninstallStrings, index + 1);
+ asUninstallStrings[index] := sUnInstallString;
+ index := index +1;
+ end;
+
+ if RegQueryStringValue(HKCU64, sUnInstPath, 'UninstallString', sUnInstallString) then
+ begin
+ SetArrayLength(asUninstallStrings, index + 1);
+ asUninstallStrings[index] := sUnInstallString;
+ index := index +1;
+ end;
+ end;
+ Result := asUninstallStrings;
+end;
+
+/////////////////////////////////////////////////////////////////////
+procedure UnInstallOldVersions();
+var
+ sUnInstallString: String;
+ index: Integer;
+ isUninstallMade: Boolean;
+ iResultCode : Integer;
+ asUninstallStrings : array of String;
+begin
+ isUninstallMade := false;
+ asUninstallStrings := GetUninstallStrings();
+ for index := 0 to (GetArrayLength(asUninstallStrings) -1) do
+ begin
+ sUnInstallString := RemoveQuotes(asUninstallStrings[index]);
+ if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
+ isUninstallMade := true;
+ end;
+
+ // Wait a few seconds to prevent installation issues, otherwise files are removed in one process while the other tries to link to them
+ if (isUninstallMade) then
+ Sleep(2000);
+end;
+
+/////////////////////////////////////////////////////////////////////
+procedure CurStepChanged(CurStep: TSetupStep);
+begin
+ if (CurStep=ssInstall) then
+ begin
+ UnInstallOldVersions();
+ end;
+end;
+/////////////////////////////////////////////////////////////////////
+// End of unstall code
+/////////////////////////////////////////////////////////////////////
+
+// Build a list of greenshot parameters from the supplied installer parameters
+function GetParamsForGS(argument: String): String;
+var
+ i: Integer;
+ parametersString: String;
+ currentParameter: String;
+ foundStart: Boolean;
+ foundNoRun: Boolean;
+ foundLanguage: Boolean;
+begin
+ foundNoRun := false;
+ foundLanguage := false;
+ foundStart := false;
+ for i:= 0 to ParamCount() do begin
+ currentParameter := ParamStr(i);
+
+ // check if norun is supplied
+ if Lowercase(currentParameter) = '/norun' then begin
+ foundNoRun := true;
+ continue;
+ end;
+
+ if foundStart then begin
+ parametersString := parametersString + ' ' + currentParameter;
+ foundStart := false;
+ end
+ else begin
+ if Lowercase(currentParameter) = '/language' then begin
+ foundStart := true;
+ foundLanguage := true;
+ parametersString := parametersString + ' ' + currentParameter;
+ end;
+ end;
+ end;
+ if not foundLanguage then begin
+ parametersString := parametersString + ' /language ' + ExpandConstant('{language}');
+ end;
+ if foundNoRun then begin
+ parametersString := parametersString + ' /norun';
+ end;
+ // For debugging comment out the following
+ //MsgBox(parametersString, mbInformation, MB_OK);
+
+ Result := parametersString;
+end;
+
+// Check if language group is installed
+function hasLanguageGroup(argument: String): Boolean;
+var
+ keyValue: String;
+ returnValue: Boolean;
+begin
+ returnValue := true;
+ if (RegQueryStringValue( HKLM, 'SYSTEM\CurrentControlSet\Control\Nls\Language Groups', argument, keyValue)) then begin
+ if Length(keyValue) = 0 then begin
+ returnValue := false;
+ end;
+ end;
+ Result := returnValue;
+end;
+
+function hasDotNet() : boolean;
+begin
+ Result := netfxspversion(NetFx4x, '') >= 71;
+end;
+
+// Initialize the setup
+function InitializeSetup(): Boolean;
+begin
+ // Check for .NET and install 4.7.1 if we don't have it
+ if not hasDotNet() then
+ begin
+ // Enhance installer, if needed, otherwise .NET installations won't work
+ msi20('2.0');
+ msi31('3.0');
+
+ //install .net 4.7.1
+ dotnetfx47(71);
+ end;
+ Result := true;
+end;
+
+function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean;
+var
+ Version: TWindowsVersion;
+begin
+ GetWindowsVersionEx(Version);
+ Result :=
+ (Version.Major > Major) or
+ ((Version.Major = Major) and (Version.Minor >= Minor));
+end;
+
+function IsWindows10OrNewer: Boolean;
+begin
+ Result := IsWindowsVersionOrNewer(10, 0);
+end;
+
+[Run]
+Filename: "{app}\{#ExeName}.exe"; Description: "{cm:startgreenshot}"; Parameters: "{code:GetParamsForGS}"; WorkingDir: "{app}"; Flags: nowait postinstall runasoriginaluser
+Filename: "http://getgreenshot.org/thank-you/?language={language}&version={#Version}"; Flags: shellexec runasoriginaluser
+
+[InstallDelete]
+Name: {app}; Type: dirifempty;
diff --git a/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs b/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs
index 23525b608..611594334 100644
--- a/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs
+++ b/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs
@@ -95,7 +95,7 @@ namespace GreenshotOfficePlugin.OfficeExport
var pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
ImageOutput.SaveToStream(surfaceToUpload, pngStream, pngOutputSettings);
var base64String = Convert.ToBase64String(pngStream.GetBuffer());
- var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Width, surfaceToUpload.Height);
+ var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Image.Width, surfaceToUpload.Image.Height);
var pageChangesXml = string.Format(XmlOutline, imageXmlStr, page.Id, OnenoteNamespace2010, page.Name);
LOG.InfoFormat("Sending XML: {0}", pageChangesXml);
oneNoteApplication.ComObject.UpdatePageContent(pageChangesXml, DateTime.MinValue, XMLSchema.xs2010, false);
diff --git a/GreenshotPlugin/Core/Fraction.cs b/GreenshotPlugin/Core/Fraction.cs
new file mode 100644
index 000000000..312b91bb8
--- /dev/null
+++ b/GreenshotPlugin/Core/Fraction.cs
@@ -0,0 +1,152 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace GreenshotPlugin.Core
+{
+ ///
+ /// Basic Fraction (Rational) numbers with features only needed to represent scale factors.
+ ///
+ public readonly struct Fraction : IEquatable, IComparable
+ {
+ public static Fraction Identity { get; } = new Fraction(1, 1);
+
+ public uint Numerator { get; }
+ public uint Denominator { get; }
+
+ public Fraction(uint numerator, uint denominator)
+ {
+ if (denominator == 0)
+ {
+ throw new ArgumentException("Can't divide by zero.", nameof(denominator));
+ }
+ if (numerator == 0)
+ {
+ throw new ArgumentException("Zero is not supported by this implementation.", nameof(numerator));
+ }
+ var gcd = GreatestCommonDivisor(numerator, denominator);
+ Numerator = numerator / gcd;
+ Denominator = denominator / gcd;
+ }
+
+ public Fraction Inverse()
+ => new Fraction(Denominator, Numerator);
+
+ #region Parse
+
+ private static readonly Regex PARSE_REGEX = new Regex(@"^([1-9][0-9]*)\/([1-9][0-9]*)$", RegexOptions.Compiled);
+ public static bool TryParse(string str, out Fraction result)
+ {
+ var match = PARSE_REGEX.Match(str);
+ if (!match.Success)
+ {
+ result = Identity;
+ return false;
+ }
+ var numerator = uint.Parse(match.Groups[1].Value);
+ var denominator = uint.Parse(match.Groups[2].Value);
+ result = new Fraction(numerator, denominator);
+ return true;
+ }
+
+ public static Fraction Parse(string str)
+ => TryParse(str, out var result)
+ ? result
+ : throw new ArgumentException($"Could not parse the input \"{str}\".", nameof(str));
+
+ #endregion
+
+ #region Overrides, interface implementations
+
+ public override string ToString()
+ => $"{Numerator}/{Denominator}";
+
+ public override bool Equals(object obj)
+ => obj is Fraction fraction && Equals(fraction);
+
+ public bool Equals(Fraction other)
+ => Numerator == other.Numerator && Denominator == other.Denominator;
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hashCode = -1534900553;
+ hashCode = hashCode * -1521134295 + Numerator.GetHashCode();
+ hashCode = hashCode * -1521134295 + Denominator.GetHashCode();
+ return hashCode;
+ }
+ }
+
+ public int CompareTo(Fraction other)
+ => (int)(Numerator * other.Denominator) - (int)(other.Numerator * Denominator);
+
+ #endregion
+
+ #region Equality operators
+
+ public static bool operator ==(Fraction left, Fraction right)
+ => left.Equals(right);
+
+ public static bool operator !=(Fraction left, Fraction right)
+ => !(left == right);
+
+ #endregion
+
+ #region Comparison operators
+
+ public static bool operator <(Fraction left, Fraction right)
+ => left.CompareTo(right) < 0;
+
+ public static bool operator <=(Fraction left, Fraction right)
+ => left.CompareTo(right) <= 0;
+
+ public static bool operator >(Fraction left, Fraction right)
+ => left.CompareTo(right) > 0;
+
+ public static bool operator >=(Fraction left, Fraction right)
+ => left.CompareTo(right) >= 0;
+
+ #endregion
+
+ #region Scale operators
+
+ public static Fraction operator *(Fraction left, Fraction right)
+ => new Fraction(left.Numerator * right.Numerator, left.Denominator * right.Denominator);
+
+ public static Fraction operator *(Fraction left, uint right)
+ => new Fraction(left.Numerator * right, left.Denominator);
+
+ public static Fraction operator *(uint left, Fraction right)
+ => new Fraction(left * right.Numerator, right.Denominator);
+
+ public static Fraction operator /(Fraction left, Fraction right)
+ => new Fraction(left.Numerator * right.Denominator, left.Denominator * right.Numerator);
+
+ public static Fraction operator /(Fraction left, uint right)
+ => new Fraction(left.Numerator, left.Denominator * right);
+
+ public static Fraction operator /(uint left, Fraction right)
+ => new Fraction(left * right.Denominator, right.Numerator);
+
+ #endregion
+
+ #region Type conversion operators
+
+ public static implicit operator double(Fraction fraction)
+ => 1.0 * fraction.Numerator / fraction.Denominator;
+
+ public static implicit operator float(Fraction fraction)
+ => 1.0f * fraction.Numerator / fraction.Denominator;
+
+ public static implicit operator Fraction(uint number)
+ => new Fraction(number, 1u);
+
+ public static implicit operator Fraction((uint numerator, uint demoninator) tuple)
+ => new Fraction(tuple.numerator, tuple.demoninator);
+
+ #endregion
+
+ private static uint GreatestCommonDivisor(uint a, uint b)
+ => (b != 0) ? GreatestCommonDivisor(b, a % b) : a;
+ }
+}
diff --git a/GreenshotPlugin/Core/WindowsVersion.cs b/GreenshotPlugin/Core/WindowsVersion.cs
index 6dd4faa08..cd263d518 100644
--- a/GreenshotPlugin/Core/WindowsVersion.cs
+++ b/GreenshotPlugin/Core/WindowsVersion.cs
@@ -41,7 +41,7 @@ namespace GreenshotPlugin.Core
public static bool IsWindows7OrLater { get; } = WinVersion.Major == 6 && WinVersion.Minor >= 1 || WinVersion.Major > 6;
public static bool IsWindows7OrLower { get; } = WinVersionTotal <= 6.1;
-
+
///
/// Test if the current OS is Windows 8.0
///
@@ -102,6 +102,11 @@ namespace GreenshotPlugin.Core
/// true if we are running on Windows XP or later
public static bool IsWindowsXpOrLater { get; } = WinVersion.Major >= 5 || WinVersion.Major == 5 && WinVersion.Minor >= 1;
+ ///
+ /// Returns the windows build number
+ ///
+ public static int BuildVersion => WinVersion.Build;
+
///
/// Test if the current Windows version is 10 and the build number or later
/// See the build numbers here
diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj
index 1a9598bc0..574e0fafc 100644
--- a/GreenshotPlugin/GreenshotPlugin.csproj
+++ b/GreenshotPlugin/GreenshotPlugin.csproj
@@ -15,7 +15,7 @@
-
+
diff --git a/GreenshotPlugin/Interfaces/Drawing/Container.cs b/GreenshotPlugin/Interfaces/Drawing/Container.cs
index 6fd0df7fa..c8d85bdd7 100644
--- a/GreenshotPlugin/Interfaces/Drawing/Container.cs
+++ b/GreenshotPlugin/Interfaces/Drawing/Container.cs
@@ -102,7 +102,6 @@ namespace GreenshotPlugin.Interfaces.Drawing
get;
set;
}
- void AlignToParent(HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment);
void Invalidate();
bool ClickableAt(int x, int y);
void MoveBy(int x, int y);
@@ -152,6 +151,10 @@ namespace GreenshotPlugin.Interfaces.Drawing
get;
set;
}
+ Rectangle DrawingBounds
+ {
+ get;
+ }
void MakeBoundsChangeUndoable(bool allowMerge);
void Transform(Matrix matrix);
void MoveBy(int dx, int dy);
diff --git a/GreenshotPlugin/Interfaces/ISurface.cs b/GreenshotPlugin/Interfaces/ISurface.cs
index 44a150364..068ab0f29 100644
--- a/GreenshotPlugin/Interfaces/ISurface.cs
+++ b/GreenshotPlugin/Interfaces/ISurface.cs
@@ -23,6 +23,7 @@ using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
+using GreenshotPlugin.Core;
using GreenshotPlugin.Effects;
using GreenshotPlugin.Interfaces.Drawing;
@@ -84,8 +85,8 @@ namespace GreenshotPlugin.Interfaces
/// The TextContainer will be "re"sized to the text size.
///
/// String to show
- /// Left, Center, Right
- /// TOP, CENTER, BOTTOM
+ /// Where to put the container, X coordinate in the Image coordinate space
+ /// Where to put the container, Y coordinate in the Image coordinate space
/// FontFamily
/// Font Size in float
/// bool true if italic
@@ -94,7 +95,7 @@ namespace GreenshotPlugin.Interfaces
/// size of border (0 for none)
/// Color of string
/// Color of background (e.g. Color.Transparent)
- ITextContainer AddTextContainer(string text, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor);
+ ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor);
IImageContainer AddImageContainer(Image image, int x, int y);
ICursorContainer AddCursorContainer(Cursor cursor, int x, int y);
@@ -147,8 +148,13 @@ namespace GreenshotPlugin.Interfaces
///
/// This returns false if the container is deleted but still in the undo stack
bool IsOnSurface(IDrawableContainer container);
- void Invalidate(Rectangle rectangleToInvalidate);
void Invalidate();
+ ///
+ /// Invalidates the specified region of the Surface.
+ /// Takes care of the Surface zoom level, accepts rectangle in the coordinate space of the Image.
+ ///
+ /// Bounding rectangle for updated elements, in the coordinate space of the Image.
+ void InvalidateElements(Rectangle rectangleToInvalidate);
bool Modified
{
get;
@@ -186,9 +192,32 @@ namespace GreenshotPlugin.Interfaces
get;
set;
}
- int Width { get; }
- int Height { get; }
+
+ ///
+ /// Zoom value applied to the surface.
+ ///
+ Fraction ZoomFactor { get; set; }
+ ///
+ /// Translate a point from image coorditate space to surface coordinate space.
+ ///
+ /// A point in the coordinate space of the image.
+ Point ToSurfaceCoordinates(Point point);
+ ///
+ /// Translate a rectangle from image coorditate space to surface coordinate space.
+ ///
+ /// A rectangle in the coordinate space of the image.
+ Rectangle ToSurfaceCoordinates(Rectangle rc);
+ ///
+ /// Translate a point from surface coorditate space to image coordinate space.
+ ///
+ /// A point in the coordinate space of the surface.
+ Point ToImageCoordinates(Point point);
+ ///
+ /// Translate a rectangle from surface coorditate space to image coordinate space.
+ ///
+ /// A rectangle in the coordinate space of the surface.
+ Rectangle ToImageCoordinates(Rectangle rc);
void MakeUndoable(IMemento memento, bool allowMerge);
}
-}
\ No newline at end of file
+}
diff --git a/GreenshotWin10Plugin/Win10Plugin.cs b/GreenshotWin10Plugin/Win10Plugin.cs
index 1e0519071..53344f391 100644
--- a/GreenshotWin10Plugin/Win10Plugin.cs
+++ b/GreenshotWin10Plugin/Win10Plugin.cs
@@ -35,7 +35,9 @@ namespace GreenshotWin10Plugin
[Plugin("Win10", false)]
public sealed class Win10Plugin : IGreenshotPlugin
{
- public void Dispose()
+ private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10Plugin));
+
+ public void Dispose()
{
Dispose(true);
}
@@ -58,8 +60,10 @@ namespace GreenshotWin10Plugin
/// true if plugin is initialized, false if not (doesn't show)
public bool Initialize()
{
- if (!WindowsVersion.IsWindows10OrLater)
+ // Here we check if the build version of Windows is actually what we support
+ if (!WindowsVersion.IsWindows10BuildOrLater(17763))
{
+ Log.WarnFormat("No support for Windows build {0}", WindowsVersion.BuildVersion);
return false;
}