using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Globalization;
using System.Web.UI.HtmlControls;
using System.Web.Caching;
using Anders.Web.Controls.Model;
using Anders.Web.Controls.Application;
namespace Anders.Web.Controls
{
public class ImageCropper : CompositeControl
{
private Image image = new Image();
private HiddenField cropCords = new HiddenField();
private CropAreaCordinates cropArea = new CropAreaCordinates();
protected override void CreateChildControls()
{
EnsureChildControls();
image.ID = "cropImage";
cropCords.ID = "cords";
string v = Page.Request.Form[this.UniqueID + "$cords"];
if (!string.IsNullOrEmpty(v))
{
string[] values = v.Split(';');
cropArea.X = int.Parse(values[0]);
cropArea.Y = int.Parse(values[1]);
cropArea.Width = int.Parse(values[2]);
cropArea.Height = int.Parse(values[3]);
//This values are not saved in client hiddenfield, we retrive them from viewstate instead
cropArea.MinWidth = MinWidth;
cropArea.MinHeight = MinHeight;
}
Controls.Add(cropCords);
Controls.Add(image);
base.CreateChildControls();
}
protected override void OnPreRender(EventArgs e)
{
if (CropEnabled)
{
InitClientCrop();
InitImages();
float h = (float)CroppedImageHeight / (float)CroppedImageWidth;
IFormatProvider culture = new CultureInfo("en-US", true);
string height = h.ToString(culture);
image.Attributes["onload"] = string.Format("InitCrop(this.id, {0},{1},{2},{3},{4},{5}, '{6}', {7}, {8}, {9});",
AllowQualityLoss ? 0 : cropArea.MinWidth,
AllowQualityLoss ? 0 : cropArea.MinHeight,
cropArea.X,
cropArea.Y,
cropArea.Width,
cropArea.Height,
cropCords.ClientID,
CaptureKeys.ToString().ToLower(),
MaintainAspectRatio ? 1 : 0,
MaintainAspectRatio ? height : "0"
);
image.ImageUrl = string.Format("~/CropImage.axd?cropCacheId={0}", CacheKey);
cropCords.Value = string.Format("{0};{1};{2};{3}", cropArea.X, cropArea.Y, cropArea.Width, cropArea.Height);
}
else
image.Attributes.Remove("onload");
base.OnPreRender(e);
}
protected override void Render(HtmlTextWriter writer)
{
if (CropEnabled)
{
PostBackOptions options = new PostBackOptions(cropCords);
options.PerformValidation = false;
Page.ClientScript.RegisterForEventValidation(options);
}
base.Render(writer);
}
/// <summary>
/// Crops the current image with the selected crop area
/// </summary>
public void Crop()
{
if (SourceImage != null && CropEnabled)
{
ImageManager imageManager = new ImageManager();
CropData cropData = new CropData();
cropData.Buffer = SourceImage;
cropData.CropAreaCordinates = cropArea;
imageManager.CropImageCropperImage(cropData, CroppedImageWidth, CroppedImageHeight, MaintainAspectRatio, JpegQuality);
SetBuffer(string.Empty, cropData.Buffer);
CropEnabled = false;
}
}
/// <summary>
/// Undo the crop and reset image.
/// </summary>
public void Undo()
{
CreateImage();
CropEnabled = true;
}
/// <summary>
/// Quality of the resulting jpeg
/// </summary>
public long JpegQuality
{
get { return (long)ViewState["jpegQuality"]; }
set { ViewState["jpegQuality"] = value; }
}
/// <summary>
/// Gets or sets if its ok for the user to crop the image resulting in a zoom
/// </summary>
public bool AllowQualityLoss
{
get { return ViewState["allowQualityLoss"] != null ? (bool)ViewState["allowQualityLoss"] : false; }
set { ViewState["allowQualityLoss"] = value; }
}
/// <summary>
/// Gets or sets if the control should force the user to crop with a ceratin aspect ratio (CroppedImageWidth and CroppedImageHeight)
/// </summary>
public bool MaintainAspectRatio
{
get { return ViewState["maintainAspectRatio"] != null ? (bool)ViewState["maintainAspectRatio"] : false; }
set { ViewState["maintainAspectRatio"] = value; }
}
/// <summary>
/// Getes or Sets the width of the desired result
/// </summary>
public int CroppedImageWidth
{
get { return ViewState["croppedImageWidth"] != null ? (int)ViewState["croppedImageWidth"] : 0; }
set { ViewState["croppedImageWidth"] = value; }
}
/// <summary>
/// Gets or Sets the height of the desired result
/// </summary>
public int CroppedImageHeight
{
get { return ViewState["croppedImageHeight"] != null ? (int)ViewState["croppedImageHeight"] : 0; }
set
{
ViewState["croppedImageHeight"] = value;
}
}
/// <summary>
/// Gets or sets if the crop function should be enabled, if disabled the control will act as a normal image
/// </summary>
public bool CropEnabled
{
get { return ViewState["cropEnabled"] != null ? (bool)ViewState["cropEnabled"] : false; }
set { ViewState["cropEnabled"] = value; }
}
/// <summary>
/// Gets ors sets if the control should capture keys, if set to true arrow keys can be used to move the crop area.
/// If you use multiple crop controls on a page disable this feature
/// </summary>
public bool CaptureKeys
{
get { return ViewState["captureKeys"] != null ? (bool)ViewState["captureKeys"] : false; }
set { ViewState["captureKeys"] = value; }
}
/// <summary>
/// Gets or sets the AlternateText of the displaying image
/// </summary>
public string AlternateText
{
get { return image.AlternateText; }
set { image.AlternateText = value; }
}
/// <summary>
/// Gets or sets the source image
/// </summary>
public byte[] SourceImage
{
get { return Page.Cache["source" + CacheKey.ToString()] as byte[]; }
set { SetBuffer("source", value); }
}
/// <summary>
/// Gets the image buffer if no crop has been made this will be the display image that is resized to the ImageWidth / ImageHeight
/// If the image has been cropped this will be the cropped image
/// </summary>
public byte[] Image
{
get { return Page.Cache[CacheKey.ToString()] as byte[]; }
private set { SetBuffer(string.Empty, value); }
}
private int MinWidth
{
get { return ViewState["minWidth"] != null ? (int)ViewState["minWidth"] : 0; }
set { ViewState["minWidth"] = value; }
}
private int MinHeight
{
get { return ViewState["minHeight"] != null ? (int)ViewState["minHeight"] : 0; }
set { ViewState["minHeight"] = value; }
}
private void InitImages()
{
if (SourceImage != null && Image == null)
{
CreateImage();
}
}
/// <summary>
/// Creates the image that is displayed for the client during cropping
/// </summary>
private void CreateImage()
{
ImageManager imageManager = new ImageManager();
CropData cropData = imageManager.GetImageCropperDisplayImage(CroppedImageWidth, CroppedImageHeight, SourceImage, JpegQuality);
cropArea = cropData.CropAreaCordinates;
//Min width and min height is not sent to client's hiddenfield so we need to save this in viewstate.
MinWidth = cropArea.MinWidth;
MinHeight = cropArea.MinHeight;
//Saves buffer to cache
SetBuffer(string.Empty, cropData.Buffer);
}
/// <summary>
/// Register all client side elements
/// </summary>
private void InitClientCrop()
{
string protoTypePath = this.Page.ClientScript.GetWebResourceUrl(typeof(ImageCropper),
"Anders.Web.Controls.js.lib.prototype.js");
string builderPath = this.Page.ClientScript.GetWebResourceUrl(typeof(ImageCropper),
"Anders.Web.Controls.js.lib.builder.js");
string dragdropPath = this.Page.ClientScript.GetWebResourceUrl(typeof(ImageCropper),
"Anders.Web.Controls.js.lib.dragdrop.js");
string cropperPath = this.Page.ClientScript.GetWebResourceUrl(typeof(ImageCropper),
"Anders.Web.Controls.js.cropper.js");
//Register client scripts
this.Page.ClientScript.RegisterClientScriptInclude("prototype.js", protoTypePath);
this.Page.ClientScript.RegisterClientScriptInclude("builder.js", builderPath);
this.Page.ClientScript.RegisterClientScriptInclude("dragdrop.js", dragdropPath);
this.Page.ClientScript.RegisterClientScriptInclude("cropper.js", cropperPath);
//Adds css include to html head
if (Page.Header.FindControl("cropCss") == null)
{
HtmlGenericControl cssMetaData = new HtmlGenericControl("link");
cssMetaData.ID = "cropCss";
cssMetaData.Attributes.Add("rel", "stylesheet");
cssMetaData.Attributes.Add("href",
Page.ClientScript.GetWebResourceUrl(typeof(ImageCropper),
"Anders.Web.Controls.css.cropper.css"));
cssMetaData.Attributes.Add("type", "text/css");
cssMetaData.Attributes.Add("media", "screen");
Page.Header.Controls.Add(cssMetaData);
}
}
private void SetBuffer(string prefix, byte[] buffer)
{
if (CacheKey != Guid.Empty)
Page.Cache.Remove(prefix + CacheKey.ToString());
else
SetCacheKey();
AddBufferToCache(prefix + CacheKey.ToString(), buffer);
}
private void AddBufferToCache(string cacheId, byte[] buffer)
{
Page.Cache.Add(cacheId, buffer, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, Page.Session.Timeout, 0), CacheItemPriority.Normal, null);
}
private Guid CacheKey
{
get { return ViewState["cacheId"] != null ? (Guid)ViewState["cacheId"] : Guid.Empty; }
set { ViewState["cacheId"] = value; }
}
private void SetCacheKey()
{
CacheKey = Guid.NewGuid();
}
}
}