diff --git a/components/editorControls/imagecropper/Config.cs b/components/editorControls/imagecropper/Config.cs
new file mode 100644
index 0000000000..1ee4be2f51
--- /dev/null
+++ b/components/editorControls/imagecropper/Config.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+
+namespace umbraco.editorControls.imagecropper
+{
+ public class Config
+ {
+ public string UploadPropertyAlias { get; set; }
+ public bool GenerateImages { get; set; }
+ public int Quality { get; set; }
+ public bool ShowLabel { get; set; }
+ public ArrayList presets { get; set; }
+
+ public Config(string configuration)
+ {
+ presets = new ArrayList();
+
+ string[] configData = configuration.Split('|');
+
+ if (configData.Length != 2) return;
+
+ string[] generalSettings = configData[0].Split(',');
+
+ UploadPropertyAlias = generalSettings[0];
+ GenerateImages = generalSettings[1] == "1";
+ ShowLabel = generalSettings[2] == "1";
+
+ int _quality;
+ if(generalSettings.Length >= 4 && Int32.TryParse(generalSettings[3], out _quality))
+ {
+ Quality = _quality;
+ }
+ else
+ {
+ Quality = 90;
+ }
+
+ string[] presetData = configData[1].Split(';');
+
+ for (int i=0; i < presetData.Length; i++)
+ {
+ string[] p = presetData[i].Split(',');
+
+ int targetWidth, targetHeight;
+
+ if (p.Length >= 4 && Int32.TryParse(p[1], out targetWidth) && Int32.TryParse(p[2], out targetHeight))
+ {
+ char[] cropPosition = { 'C', 'M' };
+
+ if(p.Length >= 5)
+ {
+ cropPosition = p[4].ToCharArray();
+ }
+
+ presets.Add(new Preset(p[0], targetWidth, targetHeight, p[3] == "1" ? true : false, cropPosition[0].ToString(), cropPosition[1].ToString()));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/components/editorControls/imagecropper/Data.cs b/components/editorControls/imagecropper/Data.cs
new file mode 100644
index 0000000000..b8219279e7
--- /dev/null
+++ b/components/editorControls/imagecropper/Data.cs
@@ -0,0 +1,119 @@
+namespace umbraco.editorControls.imagecropper
+{
+ struct Crop
+ {
+ public int X;
+ public int Y;
+ public int X2;
+ public int Y2;
+
+ public Crop(int x, int y, int x2, int y2)
+ {
+ X = x;
+ Y = y;
+ X2 = x2;
+ Y2 = y2;
+ }
+ }
+
+ enum DefaultCropPosition
+ {
+ CenterCenter = 0,
+ CenterTop,
+ CenterBottom,
+ LeftCenter,
+ LeftTop,
+ LeftBottom,
+ RightCenter,
+ RightTop,
+ RightBottom
+ }
+
+ struct Preset
+ {
+ public string Name;
+ public int TargetWidth;
+ public int TargetHeight;
+ public bool KeepAspect;
+ public string PositionH;
+ public string PositionV;
+
+ public float Aspect
+ {
+ get { return (float)TargetWidth / TargetHeight; }
+ }
+
+ public Crop Fit(ImageInfo imageInfo)
+ {
+ Crop crop;
+
+ if (Aspect >= imageInfo.Aspect)
+ {
+ // crop widest hor ver
+ // relevant positioning: center top, center center, center bottom
+
+ float h = ((float)imageInfo.Width / TargetWidth) * TargetHeight;
+
+ crop.X = 0;
+ crop.X2 = imageInfo.Width;
+
+ switch(PositionV)
+ {
+ case "T":
+ crop.Y = 0;
+ crop.Y2 = (int)h;
+ break;
+ case "B":
+ crop.Y = imageInfo.Height - (int)h;
+ crop.Y2 = imageInfo.Height;
+ break;
+ default: // CC
+ crop.Y = (int)(imageInfo.Height - h) / 2;
+ crop.Y2 = (int)(crop.Y + h);
+ break;
+ }
+ }
+ else
+ {
+
+ // image widest
+ // relevant positioning: left/right center, left/right top, left/right bottom
+
+ float w = ((float)imageInfo.Height / TargetHeight) * TargetWidth;
+
+ crop.Y = 0;
+ crop.Y2 = imageInfo.Height;
+
+ switch (PositionH)
+ {
+ case "L":
+ crop.X = 0;
+ crop.X2 = (int)w;
+ break;
+ case "R":
+ crop.X = imageInfo.Width - (int)w;
+ crop.X2 = imageInfo.Width;
+ break;
+ default: // CC
+ crop.X = (int) (imageInfo.Width - w)/2;
+ crop.X2 = (int) (crop.X + w);
+ break;
+ }
+
+ }
+
+ return crop;
+ }
+
+ public Preset(string name, int targetWidth, int targetHeight, bool keepAspect, string positionH, string positionV)
+ {
+ Name = name;
+ TargetWidth = targetWidth;
+ TargetHeight = targetHeight;
+ KeepAspect = keepAspect;
+ PositionH = positionH;
+ PositionV = positionV;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/components/editorControls/imagecropper/DataEditor.cs b/components/editorControls/imagecropper/DataEditor.cs
new file mode 100644
index 0000000000..20abb3f990
--- /dev/null
+++ b/components/editorControls/imagecropper/DataEditor.cs
@@ -0,0 +1,192 @@
+using System;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using umbraco.cms.businesslogic.property;
+using umbraco.cms.businesslogic.web;
+using System.Xml;
+using System.Text;
+using umbraco.editorControls.imagecropper;
+
+namespace umbraco.editorControls.imagecropper
+{
+ public class DataEditor : PlaceHolder, umbraco.interfaces.IDataEditor
+ {
+ private umbraco.interfaces.IData data;
+ private Config config;
+ private XmlDocument _xml;
+
+ public Image imgImage = new Image();
+ public HiddenField hdnJson = new HiddenField();
+ public HiddenField hdnRaw = new HiddenField();
+ public HiddenField hdnSer = new HiddenField();
+
+ public DataEditor(umbraco.interfaces.IData Data, string Configuration)
+ {
+ data = Data;
+ config = new Config(Configuration);
+ }
+
+ public virtual bool TreatAsRichTextEditor { get { return false; } }
+
+ public bool ShowLabel { get { return config.ShowLabel; } }
+
+ public Control Editor { get { return this; } }
+
+ protected override void OnInit(EventArgs e)
+ //protected override void OnLoad(EventArgs e)
+ {
+ this.ID = "ImageCropper";
+ //base.OnInit(e);
+
+ int propertyId = ((umbraco.cms.businesslogic.datatype.DefaultData) data).PropertyId;
+
+ int currentDocumentId = ((umbraco.cms.businesslogic.datatype.DefaultData)data).NodeId;
+ Document currentDocument = new Document(currentDocumentId);
+
+ Property uploadProperty = currentDocument.getProperty(config.UploadPropertyAlias);
+
+ if(uploadProperty == null) return;
+
+ string relativeImagePath = uploadProperty.Value.ToString();
+
+ ImageInfo imageInfo = new ImageInfo(relativeImagePath);
+
+ imgImage.ImageUrl = relativeImagePath;
+ imgImage.ID = String.Format("cropBox_{0}", propertyId);
+
+ StringBuilder sbJson = new StringBuilder();
+ StringBuilder sbRaw = new StringBuilder();
+
+ try
+ {
+ _xml = new XmlDocument();
+ _xml.LoadXml(data.Value.ToString());
+ }
+ catch
+ {
+ _xml = createBaseXmlDocument();
+ }
+
+ sbJson.Append("{ \"current\": 0, \"crops\": [");
+
+ for (int i = 0; i < config.presets.Count; i++)
+ {
+ Preset preset = (Preset) config.presets[i];
+ Crop crop;
+
+ sbJson.Append("{\"name\":'" + preset.Name + "'");
+
+ sbJson.Append(",\"config\":{" +
+ String.Format("\"targetWidth\":{0},\"targetHeight\":{1},\"keepAspect\":{2}",
+ preset.TargetWidth, preset.TargetHeight,
+ (preset.KeepAspect ? "true" : "false") + "}"));
+
+ if (imageInfo.Exists)
+ {
+ crop = preset.Fit(imageInfo);
+ }
+ else
+ {
+ crop.X = 0;
+ crop.Y = 0;
+ crop.X2 = preset.TargetWidth;
+ crop.Y2 = preset.TargetHeight;
+ }
+
+ // stored
+ if (_xml.DocumentElement != null && _xml.DocumentElement.ChildNodes.Count == config.presets.Count)
+ {
+ XmlNode xmlNode = _xml.DocumentElement.ChildNodes[i];
+
+ int xml_x = Convert.ToInt32(xmlNode.Attributes["x"].Value);
+ int xml_y = Convert.ToInt32(xmlNode.Attributes["y"].Value);
+ int xml_x2 = Convert.ToInt32(xmlNode.Attributes["x2"].Value);
+ int xml_y2 = Convert.ToInt32(xmlNode.Attributes["y2"].Value);
+
+ DateTime fileDate = Convert.ToDateTime(_xml.DocumentElement.Attributes["date"].Value);
+
+ // only use xml values if image is the same and different from defaults (document is stored inbetween image upload and cropping)
+ //if (xml_x2 - xml_x != preset.TargetWidth || xml_y2 - xml_y != preset.TargetHeight)
+ //fileDate == imageInfo.DateStamp && (
+
+ if(crop.X != xml_x || crop.X2 != xml_x2 || crop.Y != xml_y || crop.Y2 != xml_y2)
+ {
+ crop.X = xml_x;
+ crop.Y = xml_y;
+ crop.X2 = xml_x2;
+ crop.Y2 = xml_y2;
+ }
+ }
+
+ sbJson.Append(",\"value\":{" + String.Format("\"x\":{0},\"y\":{1},\"x2\":{2},\"y2\":{3}", crop.X, crop.Y, crop.X2, crop.Y2) + "}}");
+ sbRaw.Append(String.Format("{0},{1},{2},{3}", crop.X, crop.Y, crop.X2, crop.Y2));
+
+ if (i < config.presets.Count - 1)
+ {
+ sbJson.Append(",");
+ sbRaw.Append(";");
+ }
+ }
+
+ sbJson.Append("]}");
+
+ hdnJson.Value = sbJson.ToString();
+ //hdnJson.ID = String.Format("json_{0}", propertyId);
+ hdnRaw.Value = sbRaw.ToString();
+ //hdnRaw.ID = String.Format("raw_{0}", propertyId);
+
+ Controls.Add(imgImage);
+
+ Controls.Add(hdnJson);
+ Controls.Add(hdnRaw);
+
+ string imageCropperInitScript =
+ "initImageCropper('" +
+ imgImage.ClientID + "', '" +
+ hdnJson.ClientID + "', '" +
+ hdnRaw.ClientID +
+ "');";
+
+ Page.ClientScript.RegisterStartupScript(GetType(), ClientID + "_imageCropper", imageCropperInitScript, true);
+ Page.ClientScript.RegisterClientScriptBlock(Resources.json2Script.GetType(), "json2Script", Resources.json2Script, true);
+ Page.ClientScript.RegisterClientScriptBlock(Resources.jCropCSS.GetType(), "jCropCSS", Resources.jCropCSS);
+ Page.ClientScript.RegisterClientScriptBlock(Resources.jCropScript.GetType(), "jCropScript", Resources.jCropScript, true);
+ Page.ClientScript.RegisterClientScriptBlock(Resources.imageCropperScript.GetType(), "imageCropperScript", Resources.imageCropperScript, true);
+
+
+ base.OnInit(e);
+ }
+
+
+ ///
+ /// Store data as string XML (overridden by ToXMl to store "real" XML
+ /// XML format:
+ ///
+ ///
+ ///
+ ///
+ public void Save()
+ {
+ ImageInfo imageInfo = new ImageInfo(imgImage.ImageUrl);
+ if (!imageInfo.Exists)
+ {
+ data.Value = "";
+ }
+ else
+ {
+ SaveData saveData = new SaveData(hdnRaw.Value);
+ data.Value = saveData.Xml(config, imageInfo);
+ imageInfo.GenerateThumbnails(saveData, config);
+ }
+ }
+
+ private static XmlDocument createBaseXmlDocument()
+ {
+ XmlDocument doc = new XmlDocument();
+ XmlNode root = doc.CreateElement("crops");
+ doc.AppendChild(root);
+ return doc;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/components/editorControls/imagecropper/DataType.cs b/components/editorControls/imagecropper/DataType.cs
new file mode 100644
index 0000000000..6dd266de12
--- /dev/null
+++ b/components/editorControls/imagecropper/DataType.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Reflection;
+
+namespace umbraco.editorControls.imagecropper
+{
+ public class DataType : umbraco.cms.businesslogic.datatype.BaseDataType, umbraco.interfaces.IDataType
+ {
+ private umbraco.interfaces.IDataEditor _editor;
+ private umbraco.interfaces.IData _baseData;
+ private PrevalueEditor _prevalueEditor;
+
+ public override umbraco.interfaces.IDataEditor DataEditor
+ {
+ get
+ {
+ if (_editor == null)
+ _editor = new DataEditor(Data, ((PrevalueEditor)PrevalueEditor).Configuration);
+ return _editor;
+ }
+ }
+
+ public override umbraco.interfaces.IData Data
+ {
+ get
+ {
+ if (_baseData == null)
+ _baseData = new DataTypeData(this);
+ return _baseData;
+ }
+ }
+ public override Guid Id
+ {
+ get { return new Guid("7A2D436C-34C2-410F-898F-4A23B3D79F54"); }
+ }
+
+ public override string DataTypeName
+ {
+ get { return "Image Cropper"; }
+ }
+
+ public override umbraco.interfaces.IDataPrevalue PrevalueEditor
+ {
+ get
+ {
+ if (_prevalueEditor == null)
+ _prevalueEditor = new PrevalueEditor(this);
+ return _prevalueEditor;
+ }
+ }
+
+ public static int Version
+ {
+ get
+ {
+ Version version = Assembly.GetExecutingAssembly().GetName().Version;
+ return version.Major*1000 + version.Minor*100;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/components/editorControls/imagecropper/DataTypeData.cs b/components/editorControls/imagecropper/DataTypeData.cs
new file mode 100644
index 0000000000..7c667aaa24
--- /dev/null
+++ b/components/editorControls/imagecropper/DataTypeData.cs
@@ -0,0 +1,21 @@
+using System.Xml;
+
+namespace umbraco.editorControls.imagecropper
+{
+ public class DataTypeData : umbraco.cms.businesslogic.datatype.DefaultData
+ {
+ public DataTypeData(umbraco.cms.businesslogic.datatype.BaseDataType DataType) : base(DataType) { }
+
+ public override XmlNode ToXMl(XmlDocument data)
+ {
+ if (Value.ToString() != "") {
+ XmlDocument xd = new XmlDocument();
+ xd.LoadXml(Value.ToString());
+ return data.ImportNode(xd.DocumentElement, true);
+ } else {
+ return base.ToXMl(data);
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/components/editorControls/imagecropper/Helper.cs b/components/editorControls/imagecropper/Helper.cs
new file mode 100644
index 0000000000..1294ae367e
--- /dev/null
+++ b/components/editorControls/imagecropper/Helper.cs
@@ -0,0 +1,22 @@
+using System.IO;
+using System.Xml.Serialization;
+
+namespace umbraco.editorControls.imagecropper
+{
+ class Helper
+ {
+
+
+ public static string SerializeToString(object obj)
+ {
+ XmlSerializer serializer = new XmlSerializer(obj.GetType());
+
+ using (StringWriter writer = new StringWriter())
+ {
+ serializer.Serialize(writer, obj);
+
+ return writer.ToString();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/components/editorControls/imagecropper/ImageInfo.cs b/components/editorControls/imagecropper/ImageInfo.cs
new file mode 100644
index 0000000000..da2849081e
--- /dev/null
+++ b/components/editorControls/imagecropper/ImageInfo.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Drawing;
+using System.IO;
+using System.Web;
+using umbraco.editorControls.imagecropper;
+
+namespace umbraco.editorControls.imagecropper
+{
+ public class ImageInfo
+ {
+ public Image image { get; set; }
+ public string Name { get; set; }
+ public int Width { get; set; }
+ public int Height { get; set; }
+ public float Aspect { get; set; }
+ public DateTime DateStamp { get; set; }
+ public string Path { get; set; }
+ public string RelativePath { get; set; }
+
+ public ImageInfo(string relativePath)
+ {
+ RelativePath = relativePath;
+ Path = HttpContext.Current.Server.MapPath(relativePath);
+ if (File.Exists(Path))
+ {
+ string fileName = Path.Substring(Path.LastIndexOf('\\') + 1);
+ Name = fileName.Substring(0, fileName.LastIndexOf('.'));
+
+ byte[] buffer = null;
+
+ using (FileStream fs = new FileStream(Path, FileMode.Open, FileAccess.Read))
+ {
+ buffer = new byte[fs.Length];
+ fs.Read(buffer, 0, (int) fs.Length);
+ fs.Close();
+ }
+
+ try
+ {
+ image = Image.FromStream(new MemoryStream(buffer));
+
+ Width = image.Width;
+ Height = image.Height;
+ Aspect = (float) Width/Height;
+ DateStamp = File.GetLastWriteTime(Path);
+ }
+ catch (Exception)
+ {
+ Width = 0;
+ Height = 0;
+ Aspect = 0;
+ }
+
+ }
+ else
+ {
+ Width = 0;
+ Height = 0;
+ Aspect = 0;
+ }
+ }
+
+ public bool Exists
+ {
+ get { return Width > 0 && Height > 0; }
+ }
+
+ public string Directory
+ {
+ get { return Path.Substring(0, Path.LastIndexOf('\\')); }
+ }
+
+ public void GenerateThumbnails(SaveData saveData, Config config)
+ {
+ if (config.GenerateImages)
+ {
+ for (int i = 0; i < config.presets.Count; i++)
+ {
+ Crop crop = (Crop) saveData.data[i];
+ Preset preset = (Preset) config.presets[i];
+
+ // Crop rectangle bigger than actual image
+ if(crop.X2 - crop.X > Width || crop.Y2 - crop.Y > Height)
+ {
+ crop = preset.Fit(this);
+ }
+
+ ImageTransform.Execute(
+ Path,
+ String.Format("{0}_{1}", Name, preset.Name),
+ crop.X,
+ crop.Y,
+ crop.X2 - crop.X,
+ crop.Y2 - crop.Y,
+ preset.TargetWidth,
+ preset.TargetHeight,
+ config.Quality
+ );
+ //BasePage bp = new BasePage();
+ //bp.speechBubble(BasePage.speechBubbleIcon.error, "Error",
+ // "One or more crops are out of bounds. Please correct and try again.");
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/components/editorControls/imagecropper/ImageManipulation.cs b/components/editorControls/imagecropper/ImageManipulation.cs
new file mode 100644
index 0000000000..3536b3a037
--- /dev/null
+++ b/components/editorControls/imagecropper/ImageManipulation.cs
@@ -0,0 +1,212 @@
+using System;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.Drawing;
+using System.IO;
+
+namespace umbraco.editorControls.imagecropper
+{
+ public class ImageTransform
+ {
+ public static void Execute(string sourceFile, string name, int cropX, int cropY, int cropWidth, int cropHeight, int sizeWidth, int sizeHeight, long quality)
+ {
+ if (!File.Exists(sourceFile)) return;
+
+ string path = sourceFile.Substring(0, sourceFile.LastIndexOf('\\'));
+
+ // TODO: Make configurable and move to imageInfo
+ //if(File.Exists(String.Format(@"{0}\{1}.jpg", path, name))) return;
+
+ byte[] buffer = null;
+
+ using(FileStream fs = new FileStream(sourceFile, FileMode.Open, FileAccess.Read))
+ {
+ buffer = new byte[fs.Length];
+ fs.Read(buffer, 0, (int)fs.Length);
+ fs.Close();
+ }
+
+ Image image = Image.FromStream(new MemoryStream(buffer));
+
+ DirectoryInfo di = new DirectoryInfo(path);
+ if (!di.Exists) di.Create();
+
+ using(Image croppedImage = cropImage(image, new Rectangle(cropX, cropY, cropWidth, cropHeight)))
+ {
+ using(Image resizedImage = resizeImage(croppedImage, new Size(sizeWidth, sizeHeight)))
+ {
+ using (Bitmap b = new Bitmap(resizedImage))
+ {
+ saveJpeg(String.Format("{0}/{1}.jpg", path, name), b, quality);
+ }
+ }
+ }
+
+
+ //saveJpeg(
+ // String.Format("{0}/{1}.jpg", path, name),
+ // new Bitmap(
+ // resizeImage(cropImage(image, new Rectangle(cropX, cropY, cropWidth, cropHeight)), new Size(sizeWidth, sizeHeight))),
+ // quality
+ // );
+
+ //using (FileStream stm = new FileStream(sourceFile, FileMode.Open, FileAccess.Read))
+ //{
+ //using (Image image = Image.FromStream(stm))
+ //{
+
+ //}
+ //stm.Close();
+ //}
+
+
+ //using (Image image = Image.FromFile(sourceFile))
+ //{
+ // //image = cropImage(image, new Rectangle(cropX, cropY, cropWidth, cropHeight));
+ // //cropImage(image, new Rectangle(cropX, cropY, cropWidth, cropHeight));
+ // //image = resizeImage(image, new Size(sizeWidth, sizeHeight));
+ // //resizeImage(image, new Size(sizeWidth, sizeHeight));
+ // string path = sourceFile.Substring(0, sourceFile.LastIndexOf('\\') + 1) + "Crops";
+ // DirectoryInfo di = new DirectoryInfo(path);
+ // if (!di.Exists) di.Create();
+ // saveJpeg(
+ // String.Format("{0}/{1}.jpg", path, name),
+ // new Bitmap(
+ // resizeImage(cropImage(image, new Rectangle(cropX, cropY, cropWidth, cropHeight)), new Size(sizeWidth, sizeHeight))),
+ // quality
+ // );
+
+ // image.Dispose();
+ //}
+ }
+
+ private static void saveJpeg(string path, Bitmap img, long quality)
+ {
+ // Encoder parameter for image quality
+ EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, quality);
+
+ // Jpeg image codec
+ ImageCodecInfo jpegCodec = getEncoderInfo("image/jpeg");
+
+ if (jpegCodec == null)
+ return;
+
+ EncoderParameters encoderParams = new EncoderParameters(1);
+ encoderParams.Param[0] = qualityParam;
+
+ img.Save(path, jpegCodec, encoderParams);
+ }
+
+ private static ImageCodecInfo getEncoderInfo(string mimeType)
+ {
+ // Get image codecs for all image formats
+ ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
+
+ // Find the correct image codec
+ for (int i = 0; i < codecs.Length; i++)
+ if (codecs[i].MimeType == mimeType)
+ return codecs[i];
+ return null;
+ }
+
+ private static Image cropImage(Image img, Rectangle cropArea)
+ {
+ Bitmap bmpImage = new Bitmap(img);
+ Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
+ return (Image)(bmpCrop);
+ }
+
+ private static Image resizeImage(Image imgToResize, Size size)
+ {
+ //int sourceWidth = imgToResize.Width;
+ //int sourceHeight = imgToResize.Height;
+
+ //float nPercent = 0;
+ //float nPercentW = 0;
+ //float nPercentH = 0;
+
+ //nPercentW = ((float)size.Width / (float)sourceWidth);
+ //nPercentH = ((float)size.Height / (float)sourceHeight);
+
+ //if (nPercentH < nPercentW)
+ // nPercent = nPercentH;
+ //else
+ // nPercent = nPercentW;
+
+ //int destWidth = (int)(sourceWidth * nPercent);
+ //int destHeight = (int)(sourceHeight * nPercent);
+
+
+
+
+
+
+
+ int destWidth = size.Width;
+ int destHeight = size.Height;
+
+ Bitmap b = new Bitmap(destWidth, destHeight);
+
+ ImageAttributes ia = new ImageAttributes();
+ ia.SetWrapMode(WrapMode.TileFlipXY);
+
+ Graphics g = Graphics.FromImage(b);
+ g.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ g.Clear(Color.White);
+ g.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ g.CompositingQuality = CompositingQuality.HighQuality;
+ g.SmoothingMode = SmoothingMode.HighQuality;
+ g.DrawImage(imgToResize, new Rectangle(0, 0, destWidth, destHeight), 0, 0, imgToResize.Width,
+ imgToResize.Height, GraphicsUnit.Pixel, ia);
+
+ ia.Dispose();
+ g.Dispose();
+
+ return b;
+
+
+
+
+
+#if false
+
+ int destWidth = size.Width;
+ int destHeight = size.Height;
+
+ using (Bitmap b = new Bitmap(destWidth, destHeight))
+ {
+ using (Graphics g = Graphics.FromImage(b))
+ {
+ g.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ using (ImageAttributes ia = new ImageAttributes())
+ {
+ ia.SetWrapMode(WrapMode.TileFlipXY);
+ g.Clear(Color.White);
+ g.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ g.CompositingQuality = CompositingQuality.HighQuality;
+ g.SmoothingMode = SmoothingMode.HighQuality;
+ g.DrawImage(imgToResize, new Rectangle(0, 0, destWidth, destHeight), 0, 0, imgToResize.Width,
+ imgToResize.Height, GraphicsUnit.Pixel, ia);
+ }
+ }
+ return b;
+ }
+
+#endif
+
+#if false
+ int destWidth = size.Width;
+ int destHeight = size.Height;
+
+ Bitmap b = new Bitmap(destWidth, destHeight);
+ Graphics g = Graphics.FromImage((Image)b);
+ g.InterpolationMode = InterpolationMode.HighQualityBicubic;
+
+ g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
+ g.Dispose();
+
+ return (Image)b;
+#endif
+ }
+ }
+}
\ No newline at end of file
diff --git a/components/editorControls/imagecropper/PrevalueEditor.cs b/components/editorControls/imagecropper/PrevalueEditor.cs
new file mode 100644
index 0000000000..1050c494b9
--- /dev/null
+++ b/components/editorControls/imagecropper/PrevalueEditor.cs
@@ -0,0 +1,413 @@
+using System;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using umbraco.BusinessLogic;
+using umbraco.editorControls;
+using umbraco.DataLayer;
+using umbraco.interfaces;
+
+namespace umbraco.editorControls.imagecropper
+{
+ public class PrevalueEditor : PlaceHolder, IDataPrevalue
+ {
+ private readonly umbraco.cms.businesslogic.datatype.BaseDataType _dataType;
+
+ private TextBox txtPropertyAlias;
+ private CheckBox chkGenerateCrops;
+ private CheckBox chkShowLabel;
+ private Literal litQuality;
+ private TextBox txtQuality;
+
+ private SmartListBox slbPresets;
+ private TextBox txtCropName;
+ private TextBox txtTargetWidth;
+ private TextBox txtTargetHeight;
+ private CheckBox chkKeepAspect;
+ private DropDownList ddlDefaultPosH;
+ private DropDownList ddlDefaultPosV;
+
+ private Button btnUp;
+ private Button btnDown;
+ private Button btnAdd;
+ private Button btnRemove;
+ private Button btnGenerate;
+
+ //private RegularExpressionValidator revName;
+ //private RequiredFieldValidator rqfName;
+ //private ValidationSummary vsErrors;
+
+ public PrevalueEditor(umbraco.cms.businesslogic.datatype.BaseDataType dataType)
+ {
+ _dataType = dataType;
+ SetupChildControls();
+ }
+
+ public void SetupChildControls()
+ {
+ txtPropertyAlias = new TextBox {ID = "upload", Width = Unit.Pixel(100)};
+ chkGenerateCrops = new CheckBox {ID = "generateimg", AutoPostBack = true};
+ litQuality = new Literal {ID = "qualityLiteral", Text = " Quality ", Visible = false};
+ txtQuality = new TextBox {ID = "quality", Width = Unit.Pixel(30), Visible = false};
+ chkShowLabel = new CheckBox {ID = "label"};
+ slbPresets = new SmartListBox
+ {
+ ID = "presets",
+ SelectionMode = ListSelectionMode.Multiple,
+ Height = Unit.Pixel(123),
+ Width = Unit.Pixel(350)
+ };
+
+ txtCropName = new TextBox {ID = "presetname", Width = Unit.Pixel(100)};
+ txtTargetWidth = new TextBox {ID = "presetw", Width = Unit.Pixel(50)};
+ txtTargetHeight = new TextBox {ID = "preseth", Width = Unit.Pixel(50)};
+ chkKeepAspect = new CheckBox {ID = "aspect", Checked = true};
+
+ ddlDefaultPosH = new DropDownList {ID = "posh"};
+ ddlDefaultPosH.Items.Add(new ListItem("Left", "L"));
+ ddlDefaultPosH.Items.Add(new ListItem("Center", "C"));
+ ddlDefaultPosH.Items.Add(new ListItem("Right", "R"));
+
+ ddlDefaultPosV = new DropDownList {ID = "posv"};
+ ddlDefaultPosV.Items.Add(new ListItem("Top", "T"));
+ ddlDefaultPosV.Items.Add(new ListItem("Middle", "M"));
+ ddlDefaultPosV.Items.Add(new ListItem("Bottom", "B"));
+
+ btnUp = new Button {ID = "up", Text = "Up", Width = Unit.Pixel(60)};
+ btnDown = new Button {ID = "down", Text = "Down", Width = Unit.Pixel(60)};
+ btnAdd = new Button {ID = "add", Text = "Add", Width = Unit.Pixel(60)};
+ btnRemove = new Button {ID = "remove", Text = "Remove", Width = Unit.Pixel(60)};
+ btnGenerate = new Button {ID = "generate", Text = "Generate", Width = Unit.Pixel(60)};
+
+ //vsErrors = new ValidationSummary {ID = "summary", ValidationGroup = "cropper"};
+ //rqfName = new RequiredFieldValidator {ID = "namevalidator", ValidationGroup = "cropper", ControlToValidate = txtCropName.ClientID, ErrorMessage = "Crop name missing", Text="*" };
+
+ //revName = new RegularExpressionValidator
+ // {
+ // ID = "namevalidator",
+ // ValidationExpression = ".*[a-zA-Z0-9-_ ].*",
+ // ValidationGroup = "cropper",
+ // ErrorMessage = "Invalid name. Alphanumerical only please as this will be the filename",
+ // AssociatedControlID = txtCropName.ID
+ // };
+
+ Controls.Add(txtPropertyAlias);
+ Controls.Add(chkGenerateCrops);
+ Controls.Add(litQuality);
+ Controls.Add(txtQuality);
+ Controls.Add(chkShowLabel);
+
+ Controls.Add(slbPresets);
+ Controls.Add(txtCropName);
+ Controls.Add(txtTargetWidth);
+ Controls.Add(txtTargetHeight);
+ Controls.Add(chkKeepAspect);
+ Controls.Add(ddlDefaultPosH);
+ Controls.Add(ddlDefaultPosV);
+
+ Controls.Add(btnUp);
+ Controls.Add(btnDown);
+ Controls.Add(btnAdd);
+ Controls.Add(btnRemove);
+ Controls.Add(btnGenerate);
+
+ //Controls.Add(vsErrors);
+ //Controls.Add(rqfName);
+ //Controls.Add(revName);
+
+ btnUp.Click += _upButton_Click;
+ btnDown.Click += _downButton_Click;
+ btnAdd.Click += _addButton_Click;
+ btnRemove.Click += _removeButton_Click;
+
+ //btnGenerate.Click += _generateButton_Click;
+
+ chkGenerateCrops.CheckedChanged += _generateImagesCheckBox_CheckedChanged;
+
+
+ }
+
+#if false
+ void _generateButton_Click(object sender, EventArgs e)
+ {
+ Config config = new Config(Configuration);
+
+ // get list of nodeids with this datatype
+ using (IRecordsReader rdr = SqlHelper.ExecuteReader(
+ "SELECT DISTINCT contentNodeId, " +
+ "(SELECT Alias FROM cmsPropertyType WHERE Id = pd.propertyTypeId) AS propertyAlias " +
+ "FROM cmsPropertyData pd " +
+ "WHERE PropertyTypeId IN (SELECT Id FROM cmsPropertyType WHERE DataTypeId = " + _dataType.DataTypeDefinitionId + ")"))
+ {
+ while (rdr.Read())
+ {
+ int documentId = rdr.GetInt("contentNodeId");
+ string propertyAlias = rdr.GetString("propertyAlias");
+
+ Document document = new Document(documentId);
+
+ Property cropProperty = document.getProperty(propertyAlias);
+ Property imageProperty = document.getProperty(config.UploadPropertyAlias);
+
+ if (cropProperty != null) // && cropProperty.Value.ToString() == ""
+ {
+ ImageInfo imageInfo = new ImageInfo(imageProperty.Value.ToString());
+
+ if (imageInfo.Exists)
+ {
+ SaveData saveData = new SaveData();
+
+ foreach (Preset preset in config.presets)
+ {
+ Crop crop = preset.Fit(imageInfo);
+ saveData.data.Add(crop);
+ }
+
+ //cropProperty.Value = saveData.Xml(config, imageInfo);
+
+ imageInfo.GenerateThumbnails(saveData, config);
+
+ if (document.Published)
+ {
+ //document.Publish(document.User);
+ //umbraco.library.UpdateDocumentCache(document.Id);
+ }
+ else
+ {
+ //document.Save();
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ void _generateImagesCheckBox_CheckedChanged(object sender, EventArgs e)
+ {
+ txtQuality.Visible = chkGenerateCrops.Checked;
+ litQuality.Visible = chkGenerateCrops.Checked;
+ }
+
+ void _upButton_Click(object sender, EventArgs e)
+ {
+ slbPresets.MoveUp();
+ }
+
+ void _downButton_Click(object sender, EventArgs e)
+ {
+ slbPresets.MoveDown();
+ }
+
+ void _removeButton_Click(object sender, EventArgs e)
+ {
+ for (int i = slbPresets.Items.Count - 1; i >= 0; i--)
+ {
+ if (slbPresets.Items[i].Selected)
+ slbPresets.Items.Remove(slbPresets.Items[i]);
+ }
+ }
+
+ void _addButton_Click(object sender, EventArgs e)
+ {
+ slbPresets.Items.Add(
+ new ListItem(
+ getListItemDisplayName(
+ txtCropName.Text,
+ txtTargetWidth.Text,
+ txtTargetHeight.Text,
+ chkKeepAspect.Checked ? "1" : "0",
+ String.Concat(ddlDefaultPosH.SelectedValue, ddlDefaultPosV.SelectedValue)),
+ String.Format("{0},{1},{2},{3},{4}",
+ txtCropName.Text,
+ txtTargetWidth.Text,
+ txtTargetHeight.Text,
+ chkKeepAspect.Checked ? "1" : "0",
+ String.Concat(ddlDefaultPosH.SelectedValue, ddlDefaultPosV.SelectedValue))
+ )
+ );
+ txtCropName.Text = "";
+ txtTargetWidth.Text = "";
+ txtTargetHeight.Text = "";
+ chkKeepAspect.Checked = true;
+
+ }
+
+ public Control Editor
+ {
+ get
+ {
+ return this;
+ }
+ }
+
+ protected override void OnLoad(EventArgs e)
+ {
+ base.OnLoad(e);
+
+ if (!Page.IsPostBack)
+ LoadData();
+ }
+
+ private void LoadData()
+ {
+ if (!string.IsNullOrEmpty(Configuration))
+ {
+ Config config = new Config(Configuration);
+
+ txtPropertyAlias.Text = config.UploadPropertyAlias;
+ chkGenerateCrops.Checked = config.GenerateImages;
+ chkShowLabel.Checked = config.ShowLabel;
+ txtQuality.Visible = chkShowLabel.Checked;
+ txtQuality.Text = config.Quality.ToString();
+ litQuality.Visible = chkShowLabel.Checked;
+
+ foreach (Preset preset in config.presets)
+ {
+ slbPresets.Items.Add(
+ new ListItem(
+ getListItemDisplayName(
+ preset.Name,
+ preset.TargetWidth.ToString(),
+ preset.TargetHeight.ToString(),
+ preset.KeepAspect ? "1" : "0",
+ String.Concat(preset.PositionH, preset.PositionV)),
+ String.Format("{0},{1},{2},{3},{4}{5}",
+ preset.Name,
+ preset.TargetWidth,
+ preset.TargetHeight,
+ preset.KeepAspect ? "1" : "0",
+ preset.PositionH, preset.PositionV)));
+ }
+ }
+ }
+
+ private static string getListItemDisplayName(string presetTemplateName, string width, string height, string keepAspect, string position)
+ {
+ return String.Format("{0}, width: {1}px, height: {2}px, keep aspect: {3}, {4}",
+ presetTemplateName,
+ width,
+ height,
+ keepAspect == "1" ? "yes" : "no",
+ position);
+ }
+
+ ///
+ /// Serialize configuration to:
+ /// uploadPropertyAlias,generateImages,showLabel|presetTemplateName,targetWidth,targetHeight,keepAspect;
+ ///
+ public void Save()
+ {
+ _dataType.DBType = (umbraco.cms.businesslogic.datatype.DBTypes)Enum.Parse(
+ typeof(umbraco.cms.businesslogic.datatype.DBTypes), DBTypes.Ntext.ToString(), true);
+ string generalData = String.Format("{0},{1},{2}",
+ txtPropertyAlias.Text,
+ chkGenerateCrops.Checked ? "1" : "0",
+ chkShowLabel.Checked ? "1" : "0"
+ );
+
+ string templateData = "";
+
+ for (int i = 0; i < slbPresets.Items.Count; i++)
+ {
+ templateData += slbPresets.Items[i].Value;
+ if (i < slbPresets.Items.Count - 1) templateData += ";";
+ }
+
+ string data = String.Format("{0}|{1}", generalData, templateData);
+
+ SqlHelper.ExecuteNonQuery("delete from cmsDataTypePreValues where datatypenodeid = @dtdefid",
+ SqlHelper.CreateParameter("@dtdefid", _dataType.DataTypeDefinitionId));
+
+ SqlHelper.ExecuteNonQuery("insert into cmsDataTypePreValues (datatypenodeid,[value],sortorder,alias) values (@dtdefid,@value,0,'')",
+ SqlHelper.CreateParameter("@dtdefid", _dataType.DataTypeDefinitionId), SqlHelper.CreateParameter("@value", data));
+ }
+
+ protected override void Render(HtmlTextWriter writer)
+ {
+ writer.Write("
General
");
+ writer.Write("");
+
+ writer.Write(" | Property alias: (eg. 'umbracoFile'): | ");
+ txtPropertyAlias.RenderControl(writer);
+ writer.Write(" |
");
+
+ writer.Write(" | Save crop images (/media/(imageid)/(filename)_(cropname).jpg): | ");
+ chkGenerateCrops.RenderControl(writer);
+ litQuality.RenderControl(writer);
+ txtQuality.RenderControl(writer);
+ writer.Write(" |
");
+
+ writer.Write(" | Show Label: | ");
+ chkShowLabel.RenderControl(writer);
+ writer.Write(" |
");
+
+ writer.Write("
");
+
+ writer.Write("Crops
");
+
+ writer.Write("");
+ writer.Write(" ");
+
+ writer.Write(" ");
+ writer.Write(" | Name | ");
+ txtCropName.RenderControl(writer);
+ writer.Write(" | ");
+ writer.Write(" | Target width | ");
+ txtTargetWidth.RenderControl(writer);
+ writer.Write(" px | ");
+ writer.Write(" | Target height | ");
+ txtTargetHeight.RenderControl(writer);
+ writer.Write(" px | ");
+ writer.Write(" | Default position | ");
+ ddlDefaultPosH.RenderControl(writer);
+ writer.Write(" ");
+ ddlDefaultPosV.RenderControl(writer);
+ writer.Write(" | ");
+ writer.Write(" | Keep aspect | ");
+ chkKeepAspect.RenderControl(writer);
+ writer.Write(" | ");
+ writer.Write(" ");
+ btnAdd.RenderControl(writer);
+
+ writer.Write(" | ");
+ slbPresets.RenderControl(writer);
+ writer.Write(" | ");
+ btnUp.RenderControl(writer);
+ writer.Write(" ");
+ btnDown.RenderControl(writer);
+ writer.Write("
");
+ btnRemove.RenderControl(writer);
+ writer.Write(" |
");
+ writer.Write("
");
+
+ //_generateButton.RenderControl(writer);
+ //_vsErrors.RenderControl(writer);
+ //_revName.RenderControl(writer);
+
+
+ }
+
+ public string Configuration
+ {
+ get
+ {
+ object conf =
+ SqlHelper.ExecuteScalar