/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Drawing.Drawing2D;
using GreenshotPlugin.UnmanagedHelpers;
using GreenshotPlugin.Core;
using IniFile;
namespace GreenshotPlugin.Core {
///
/// Description of ImageHelper.
///
public static class ImageHelper {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ImageHelper));
private static CoreConfiguration conf = IniConfig.GetIniSection();
public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight) {
return CreateThumbnail(image, thumbWidth, thumbHeight, -1, -1);
}
public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight, int maxWidth, int maxHeight) {
int srcWidth=image.Width;
int srcHeight=image.Height;
if (thumbHeight < 0) {
thumbHeight = (int)(thumbWidth * ((float)srcHeight / (float)srcWidth));
}
if (thumbWidth < 0) {
thumbWidth = (int)(thumbHeight * ((float)srcWidth / (float)srcHeight));
}
if (maxWidth > 0 && thumbWidth > maxWidth) {
thumbWidth = Math.Min(thumbWidth, maxWidth);
thumbHeight = (int)(thumbWidth * ((float)srcHeight / (float)srcWidth));
}
if (maxHeight > 0 && thumbHeight > maxHeight) {
thumbHeight = Math.Min(thumbHeight, maxHeight);
thumbWidth = (int)(thumbHeight * ((float)srcWidth / (float)srcHeight));
}
Bitmap bmp = new Bitmap(thumbWidth, thumbHeight);
using (Graphics gr = System.Drawing.Graphics.FromImage(bmp)) {
gr.SmoothingMode = SmoothingMode.HighQuality ;
gr.CompositingQuality = CompositingQuality.HighQuality;
gr.InterpolationMode = InterpolationMode.High;
System.Drawing.Rectangle rectDestination = new System.Drawing.Rectangle(0, 0, thumbWidth, thumbHeight);
gr.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel);
}
return bmp;
}
///
/// Crops the image to the specified rectangle
///
/// Image to crop
/// Rectangle with bitmap coordinates, will be "intersected" to the bitmap
public static bool Crop(ref Image image, ref Rectangle cropRectangle) {
Image returnImage = null;
if (image != null && image is Bitmap && ((image.Width * image.Height) > 0)) {
cropRectangle.Intersect(new Rectangle(0,0, image.Width, image.Height));
if (cropRectangle.Width != 0 || cropRectangle.Height != 0) {
returnImage = (image as Bitmap).Clone(cropRectangle, image.PixelFormat);
image.Dispose();
image = returnImage;
return true;
}
}
LOG.Warn("Can't crop a null/zero size image!");
return false;
}
private static Rectangle FindAutoCropRectangle(BitmapBuffer buffer, Point colorPoint) {
Rectangle cropRectangle = Rectangle.Empty;
Color referenceColor = buffer.GetColorAtWithoutAlpha(colorPoint.X,colorPoint.Y);
Point min = new Point(int.MaxValue, int.MaxValue);
Point max = new Point(int.MinValue, int.MinValue);
if (conf.AutoCropDifference > 0) {
for(int y = 0; y < buffer.Height; y++) {
for(int x = 0; x < buffer.Width; x++) {
Color currentColor = buffer.GetColorAt(x, y);
int diffR = Math.Abs(currentColor.R - referenceColor.R);
int diffG = Math.Abs(currentColor.G - referenceColor.G);
int diffB = Math.Abs(currentColor.B - referenceColor.B);
if (((diffR+diffG+diffB)/3) > conf.AutoCropDifference) {
if (x < min.X) min.X = x;
if (y < min.Y) min.Y = y;
if (x > max.X) max.X = x;
if (y > max.Y) max.Y = y;
}
}
}
} else {
for(int y = 0; y < buffer.Height; y++) {
for(int x = 0; x < buffer.Width; x++) {
Color currentColor = buffer.GetColorAtWithoutAlpha(x, y);
if (referenceColor.Equals(currentColor)) {
if (x < min.X) min.X = x;
if (y < min.Y) min.Y = y;
if (x > max.X) max.X = x;
if (y > max.Y) max.Y = y;
}
}
}
}
if (!(Point.Empty.Equals(min) && max.Equals(new Point(buffer.Width-1, buffer.Height-1)))) {
if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) {
cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1);
}
}
return cropRectangle;
}
///
/// Get a rectangle for the image which crops the image of all colors equal to that on 0,0
///
///
/// Rectangle
public static Rectangle FindAutoCropRectangle(Image image) {
Rectangle cropRectangle = Rectangle.Empty;
using (BitmapBuffer buffer = new BitmapBuffer((Bitmap)image, false)) {
buffer.Lock();
Rectangle currentRectangle = Rectangle.Empty;
List checkPoints = new List();
// Top Left
checkPoints.Add(new Point(0, 0));
// Bottom Left
checkPoints.Add(new Point(0, image.Height-1));
// Top Right
checkPoints.Add(new Point(image.Width-1, 0));
// Bottom Right
checkPoints.Add( new Point(image.Width-1, image.Height-1));
// find biggest area
foreach(Point checkPoint in checkPoints) {
currentRectangle = FindAutoCropRectangle(buffer, checkPoint);
if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) {
cropRectangle = currentRectangle;
}
}
}
return cropRectangle;
}
public static Bitmap LoadBitmap(string filename) {
if (string.IsNullOrEmpty(filename)) {
return null;
}
Bitmap fileBitmap = null;
LOG.InfoFormat("Loading image from file {0}", filename);
// Fixed lock problem Bug #3431881
using (Stream imageFileStream = File.OpenRead(filename)) {
// And fixed problem that the bitmap stream is disposed... by Cloning the image
// This also ensures the bitmap is correctly created
if (filename.EndsWith(".ico")) {
// Icon logic, try to get the Vista icon, else the biggest possible
try {
using (Image tmpImage = ExtractVistaIcon(imageFileStream)) {
if (tmpImage != null) {
fileBitmap = CloneImageToBitmap(tmpImage);
}
}
} catch (Exception vistaIconException) {
LOG.Warn("Can't read icon from " + filename, vistaIconException);
}
if (fileBitmap == null) {
try {
// No vista icon, try normal icon
imageFileStream.Position = 0;
// We create a copy of the bitmap, so everything else can be disposed
using (Icon tmpIcon = new Icon(imageFileStream, new Size(1024,1024))) {
using (Image tmpImage = tmpIcon.ToBitmap()) {
fileBitmap = ImageHelper.CloneImageToBitmap(tmpImage);
}
}
} catch (Exception iconException) {
LOG.Warn("Can't read icon from " + filename, iconException);
}
}
}
if (fileBitmap == null) {
// We create a copy of the bitmap, so everything else can be disposed
imageFileStream.Position = 0;
using (Image tmpImage = Image.FromStream(imageFileStream, true, true)) {
fileBitmap = ImageHelper.CloneImageToBitmap(tmpImage);
}
}
}
return fileBitmap;
}
///
/// Clone the image to a bitmap
///
/// Image to clone
/// Bitmap
public static Bitmap CloneImageToBitmap(Image srcImage) {
Bitmap returnImage;
int width = srcImage.Width;
int height = srcImage.Height;
float horizontalResolution = srcImage.HorizontalResolution;
float verticalResolution = srcImage.VerticalResolution;
PixelFormat pixelFormat = srcImage.PixelFormat;
if (srcImage is Metafile) {
pixelFormat = PixelFormat.Format32bppArgb;
}
// Make sure Greenshot supports the pixelformat, if not convert to one we support
if (!isSupported(pixelFormat)) {
pixelFormat = PixelFormat.Format24bppRgb;
}
returnImage = new Bitmap(width, height, pixelFormat);
returnImage.SetResolution(horizontalResolution, verticalResolution);
using (Graphics graphics = Graphics.FromImage(returnImage)) {
if (Image.IsAlphaPixelFormat(pixelFormat)) {
graphics.Clear(Color.Transparent);
} else {
graphics.Clear(Color.White);
}
graphics.DrawImageUnscaled(srcImage, 0, 0);
}
return returnImage;
}
/**
* Checks if we support the supplied PixelFormat
*/
private static bool isSupported(PixelFormat pixelformat) {
return (PixelFormat.Format32bppArgb.Equals(pixelformat)||
PixelFormat.Format32bppRgb.Equals(pixelformat) ||
PixelFormat.Format24bppRgb.Equals(pixelformat));
}
// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx
// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx
public static Bitmap ExtractVistaIcon(Stream iconStream) {
const int SizeICONDIR = 6;
const int SizeICONDIRENTRY = 16;
Bitmap bmpPngExtracted = null;
try {
byte[] srcBuf = new byte[iconStream.Length];
iconStream.Read(srcBuf, 0, (int)iconStream.Length);
int iCount = BitConverter.ToInt16(srcBuf, 4);
for (int iIndex=0; iIndex