protected override RequestedAction LayoutImage(ImageState s) { if (s.sourceBitmap == null) return RequestedAction.None; //Parse carve data bitmap if (!string.IsNullOrEmpty(s.settings["carve.data"])) { string[] parts = s.settings["carve.data"].Split('|'); //Parse block count and string var block_count = int.Parse(parts[0]); var carveString = new LzwDecoder("012").Decode(PathUtils.FromBase64UToBytes(parts[1])); float block_size = (int)Math.Floor(Math.Sqrt(s.originalSize.Width * s.originalSize.Height / (double)block_count)); var carveData = new CarveDataPlotter() { BlockCount=block_count, Stride = (int)Math.Ceiling((float)s.originalSize.Width / block_size), Rows = (int)Math.Ceiling((float)s.originalSize.Height / block_size) }; carveData.Init(carveString); Size remove = carveData.GetRemovalSpace(s.originalSize.Width,s.originalSize.Height,(int)block_size); if (remove.Width / s.originalSize.Width > remove.Height / s.originalSize.Height) { s.originalSize = new Size(s.originalSize.Width - remove.Width, s.originalSize.Height); } else { s.originalSize = new Size(s.originalSize.Width, s.originalSize.Height - remove.Height); } //Save later s.Data[CarveData] = carveData; } return RequestedAction.None; }
protected override RequestedAction PrepareDestinationBitmap(ImageState s) { if (!this.IsDiagnosticRequest(s.settings)) return RequestedAction.None; // Rather than allow the normal process, we will throw an // AlternateResponseException that contains the data we *really* // want to return. var info = new LayoutInformation(s); var serializer = new JsonSerializer(); // Check to see if indented JSON has been requested. This is useful // for human-readable output. if (s.settings.Get("j.indented", false)) { serializer.Formatting = Formatting.Indented; } serializer.Converters.Add(new InstructionsConverter()); StringWriter sw = new StringWriter(); serializer.Serialize(sw, info); var bytes = System.Text.Encoding.UTF8.GetBytes(sw.ToString()); throw new AlternateResponseException( "Resizing pipeline was canceled as JSON data was requested instead.", "application/json; charset=utf-8", bytes); }
protected override RequestedAction LayoutImage(ImageState s) { if (s.sourceBitmap == null) return RequestedAction.None; //percentpadding. Percentage is 0-100, multiplied by the average of the width and height. double percentpadding = s.settings.Get<double>("trim.percentpadding", 0) / 100; int? threshold = s.settings.Get<int>("trim.threshold"); if (threshold != null) { if (threshold < 0) threshold = 0; if (threshold > 255) threshold = 255; Rectangle box = new BoundingBoxFinder().FindBoxSobel(s.sourceBitmap, new Rectangle(0, 0, s.sourceBitmap.Width, s.sourceBitmap.Height), (byte)threshold); //Add padding int paddingPixels = (int)Math.Ceiling(percentpadding * (box.Width + box.Height) / 2); box.X = Math.Max(0, box.X - paddingPixels); box.Y= Math.Max(0, box.Y - paddingPixels); box.Width = Math.Min(s.sourceBitmap.Width, box.Width + paddingPixels * 2); box.Height = Math.Min(s.sourceBitmap.Height, box.Height + paddingPixels * 2); //Adjust s.originalSize so the layout occurs properly. s.originalSize = box.Size; s.Data[RectDataKey] = box; } return RequestedAction.None; }
protected override RequestedAction PostRenderImage(ImageState s) { var color = s.destBitmap.GetPixel(0,0); Console.WriteLine("PostLayoutEffects " + ++i + " color at (0,0): " + color); return base.PostRenderImage(s); }
protected override RequestedAction PostRenderImage(ImageState s) { _delays = _delays ?? GetDelays(s.sourceBitmap); _visitor((Bitmap)s.destBitmap.Clone(), s.destGraphics, _delays[_visitIndex++]); return base.PostRenderImage(s); }
public PointF[] GetOverlayParalellogram(Overlay o, Size nativeSize, ImageState translateToFinalCoordinateSpace) { //What's the polygon w/h? double cw = PolygonMath.Dist(o.Poly[0], o.Poly[1]); double ch = PolygonMath.Dist(o.Poly[1], o.Poly[2]); //Take a copy to shrink to content size double w = cw; double h = ch; double aspect = (double)nativeSize.Height / (double)nativeSize.Width; //If specified, what percentage of the space do we use? if (o.PolyWidthInLogoPixels > 0) { w = cw * (double)nativeSize.Width / o.PolyWidthInLogoPixels; if (o.RespectOnlyMatchingBound) h = w * aspect; } if (o.PolyHeightInLogoPixels > 0) { h = ch * (double)nativeSize.Height / o.PolyHeightInLogoPixels; if (o.RespectOnlyMatchingBound && o.PolyWidthInLogoPixels <= 0) w = h / aspect; } //Shrink to keep aspect ratio if (w / h > 1 / aspect) { w = h / aspect; } else { h = w * aspect; } //Let's define our width/height offsets double ox = 0; double oy = 0; ; //Apply alignment to ox, oy if (o.Align == ContentAlignment.BottomLeft || o.Align == ContentAlignment.MiddleLeft || o.Align == ContentAlignment.TopLeft) ox = 0; if (o.Align == ContentAlignment.BottomCenter || o.Align == ContentAlignment.MiddleCenter || o.Align == ContentAlignment.TopCenter) ox = (cw - w) / 2; if (o.Align == ContentAlignment.BottomRight || o.Align == ContentAlignment.MiddleRight || o.Align == ContentAlignment.TopRight) ox = cw - w; if (o.Align == ContentAlignment.TopLeft || o.Align == ContentAlignment.TopCenter || o.Align == ContentAlignment.TopRight) oy = 0; if (o.Align == ContentAlignment.MiddleLeft || o.Align == ContentAlignment.MiddleCenter || o.Align == ContentAlignment.MiddleRight) oy = (ch - h) / 2; if (o.Align == ContentAlignment.BottomLeft || o.Align == ContentAlignment.BottomCenter || o.Align == ContentAlignment.BottomRight) oy = ch - h; //Now, we need to rotate everything to match the rotation of the original parallelogram double angle = Math.Atan2(o.Poly[1].Y - o.Poly[0].Y, o.Poly[1].X - o.Poly[0].X); PointF[] t = new PointF[4]; t[0] = CreateVector(CreateVector(o.Poly[0], angle, ox), angle + Math.PI / 2, oy); t[1] = CreateVector(t[0], angle, w); t[2] = CreateVector(t[1], angle + Math.PI / 2, h); t[3] = CreateVector(t[0], angle + Math.PI / 2, h); //Translate the points if a ImageState instance was specified if (translateToFinalCoordinateSpace != null) return this.TranslatePoints(t, translateToFinalCoordinateSpace); return t; }
protected override RequestedAction PostCreateImageAttributes(ImageState s) { if (s.copyAttibutes == null) return RequestedAction.None; if (!s.settings.WasOneSpecified(GetSupportedQuerystringKeys().ToArray())) return RequestedAction.None; s.copyAttibutes.SetColorMatrix(new ColorMatrix(Grayscale())); return RequestedAction.None; }
protected override RequestedAction PostLayoutImage(ImageState s) { //Now we offset copyRect so it works properly. if (s.Data.ContainsKey(RectDataKey)){ Rectangle box = (Rectangle)s.Data[RectDataKey]; s.copyRect = new RectangleF(s.copyRect.X + box.X, s.copyRect.Y + box.Y,s.copyRect.Width,s.copyRect.Height); } return RequestedAction.None; }
/// <summary> /// Builds an FIBitmap from the stream and job.Settings /// </summary> /// <param name="s"></param> /// <param name="job"></param> /// <returns></returns> protected FIBITMAP buildFiBitmap(ref FIBITMAP original, ImageJob job, bool supportsTransparency, bool mayUnloadOriginal) { ResizeSettings settings = job.Settings; if (original.IsNull) return FIBITMAP.Zero; FIBITMAP final = FIBITMAP.Zero; //Find the image size Size orig = new Size((int)FreeImage.GetWidth(original), (int)FreeImage.GetHeight(original)); //Calculate the new size of the image and the canvas. ImageState state = new ImageState(settings, orig, true); c.CurrentImageBuilder.Process(state); RectangleF imageDest = PolygonMath.GetBoundingBox(state.layout["image"]); if (imageDest.Width != orig.Width || imageDest.Height != orig.Height) { //Rescale bool temp; final = FreeImage.Rescale(original, (int)imageDest.Width, (int)imageDest.Height, FreeImageScalingPlugin.ParseResizeAlgorithm(settings["fi.scale"], FREE_IMAGE_FILTER.FILTER_BOX, out temp)); if (mayUnloadOriginal) FreeImage.UnloadEx(ref original); if (final.IsNull) return FIBITMAP.Zero; } else { final = original; } RGBQUAD bgcolor = default(RGBQUAD); bgcolor.Color = settings.BackgroundColor; if (settings.BackgroundColor == Color.Transparent && !supportsTransparency) bgcolor.Color = Color.White; //If we need to leave padding, do so. BoxPadding outsideImage = new BoxPadding(imageDest.Left, imageDest.Top, state.destSize.Width - imageDest.Right, state.destSize.Height - imageDest.Bottom); if (outsideImage.All != 0) { var old = final; //Extend canvas final = FreeImage.EnlargeCanvas<RGBQUAD>(old, (int)outsideImage.Left, (int)outsideImage.Top, (int)outsideImage.Right, (int)outsideImage.Bottom, bgcolor.Color != Color.Transparent ? new Nullable<RGBQUAD>(bgcolor) : null, FREE_IMAGE_COLOR_OPTIONS.FICO_RGBA); if (old == original) { if (mayUnloadOriginal) { FreeImage.UnloadEx(ref original); old = original; } } else { FreeImage.UnloadEx(ref old); //'old' has the original value of 'final', which we allocated. } if (final.IsNull) return FIBITMAP.Zero; } return final; }
protected override RequestedAction RenderImage(ImageState s) { //Skip this when we are doing simulations if (s.destGraphics == null) return RequestedAction.None; //If there's pre-rendering involved this optimization is utterly pointless. if (s.preRenderBitmap != null) return RequestedAction.None; //Find out what the speed setting is. int speed = 0; if (string.IsNullOrEmpty(s.settings["speed"]) || !int.TryParse(s.settings["speed"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out speed)) speed = 0; if (speed < 1) return RequestedAction.None; s.destGraphics.CompositingMode = CompositingMode.SourceCopy; s.destGraphics.CompositingQuality = CompositingQuality.HighSpeed; if (speed == 1) s.destGraphics.InterpolationMode = InterpolationMode.HighQualityBilinear; else s.destGraphics.InterpolationMode = InterpolationMode.Bilinear; s.destGraphics.PixelOffsetMode = PixelOffsetMode.HighSpeed; s.destGraphics.SmoothingMode = SmoothingMode.HighSpeed; s.copyAttibutes.SetWrapMode(WrapMode.TileFlipXY); if (speed < 3) { s.destGraphics.DrawImage(s.sourceBitmap, PolygonMath.getParallelogram(s.layout["image"]), s.copyRect, GraphicsUnit.Pixel, s.copyAttibutes); } else if (speed < 4) { Rectangle midsize = PolygonMath.ToRectangle(PolygonMath.GetBoundingBox(s.layout["image"])); using (Image thumb = s.sourceBitmap.GetThumbnailImage(midsize.Width, midsize.Height, delegate() { return false; }, IntPtr.Zero)) { double xfactor = (double)thumb.Width / (double)s.sourceBitmap.Width; double yfactor = (double)thumb.Height / (double)s.sourceBitmap.Height; RectangleF copyPart = new RectangleF((float)(s.copyRect.Left * xfactor), (float)(s.copyRect.Top * yfactor), (float)(s.copyRect.Width * xfactor), (float)(s.copyRect.Height * yfactor)); if (Math.Floor(copyPart.Height) == thumb.Height || Math.Ceiling(copyPart.Height) == thumb.Height) copyPart.Height = thumb.Height; if (Math.Floor(copyPart.Width) == thumb.Width || Math.Ceiling(copyPart.Width) == thumb.Width) copyPart.Width = thumb.Width; s.destGraphics.DrawImage(thumb, PolygonMath.getParallelogram(s.layout["image"]), copyPart, GraphicsUnit.Pixel, s.copyAttibutes); } } else { RectangleF box = PolygonMath.GetBoundingBox(PolygonMath.getParallelogram(s.layout["image"])); s.destGraphics.CompositingMode = CompositingMode.SourceCopy; s.destGraphics.DrawImage(s.sourceBitmap, box.Left, box.Top, box.Width, box.Height); } return RequestedAction.Cancel; }
protected override RequestedAction LayoutImage(ImageState s) { //Only activated if both width and height are specified, and mode=crop. if (s.settings.Mode != FitMode.Crop || s.settings.Width < 0 || s.settings.Height < 0) return RequestedAction.None; //Calculate bounding box for all coordinates specified. double[] focus = NameValueCollectionExtensions.GetList<double>(s.settings, "c.focus", null, 2, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72); if (focus == null) return RequestedAction.None; RectangleF box = PolygonMath.GetBoundingBox(focus); var bounds = new RectangleF(new PointF(0,0),s.originalSize); //Clip box to original image bounds box = PolygonMath.ClipRectangle(box, bounds); var targetSize = new SizeF(s.settings.Width,s.settings.Height); SizeF copySize; //Now, we can either crop as closely as possible or as loosely as possible. if (NameValueCollectionExtensions.Get<bool>(s.settings, "c.zoom", false) && box.Width > 0 && box.Height > 0) { //Crop close copySize = PolygonMath.ScaleOutside(box.Size, targetSize); } else { //Crop minimally copySize = PolygonMath.ScaleInside(targetSize, bounds.Size); //Ensure it's outside the box if (!PolygonMath.FitsInside(box.Size,copySize)) copySize = PolygonMath.ScaleOutside(box.Size, copySize); } //Clip to bounds. box = PolygonMath.ClipRectangle(PolygonMath.ExpandTo(box, copySize), bounds); s.copyRect = box; ///What is the vertical and horizontal aspect ratio different in result pixels? var padding = PolygonMath.ScaleInside(box.Size, targetSize); padding = new SizeF(targetSize.Width - padding.Width, targetSize.Height - padding.Height); //So, if we haven't met the aspect ratio yet, what mode will we pass on? var finalmode = NameValueCollectionExtensions.Get<FitMode>(s.settings, "c.finalmode", FitMode.Pad); //Crop off 1 or 2 pixels instead of padding without worrying too much if (finalmode == FitMode.Pad && padding.Width + padding.Height < 3) finalmode = FitMode.Crop; s.settings.Mode = finalmode; return RequestedAction.None; }
protected override RequestedAction PostRenderImage(ImageState s) { if (s.destBitmap == null) return RequestedAction.None; if (!s.settings.WasOneSpecified(GetSupportedQuerystringKeys().ToArray())) return RequestedAction.None;; int blurSize; if (!int.TryParse(s.settings["ipt.blur"], out blurSize)) { return RequestedAction.None; } new GaussianBlur(1.4, blurSize).ApplyInPlace(s.destBitmap); return RequestedAction.None; }
protected override RequestedAction RenderOverlays(ImageState s) { // Get 'sample' from the querystring string sample = s.settings["sample"]; //Don't try to draw the string if it is empty, or if this is a 'simulation' render if (string.IsNullOrEmpty(sample) || s.destGraphics == null) return RequestedAction.None; //Let's use Arial, and make sure the text fits inside the bitmap width. System.Drawing.Font font = new System.Drawing.Font("Arial", (float)(s.destBitmap.Width / (sample.Length * 1.5f)), System.Drawing.GraphicsUnit.Pixel); //Draw the text at the top left corner of the resulting image. s.destGraphics.DrawString(sample, font, System.Drawing.Brushes.Black, 0, 0); return RequestedAction.None; }
protected override RequestedAction PostLayoutImage(ImageState s) { base.PostLayoutImage(s); if (!limits.HasImageSize) return RequestedAction.None;//Skip this unless we have image size limits SizeF box = s.layout.GetBoundingBox().Size; double wFactor = box.Width / limits.ImageSize.Width; double hFactor = box.Height / limits.ImageSize.Height; double scaleFactor = wFactor > hFactor ? wFactor : hFactor; if (scaleFactor > 1) { //The bounding box exceeds the ImageSize. Scale down until it fits. s.layout.Scale(1 / scaleFactor, new PointF(0, 0)); } return RequestedAction.None; }
protected override RequestedAction LayoutEffects(ImageState s) { float shadowWidth = s.settings.Get<float>("shadowWidth", 0); if (shadowWidth != 0) { var offset = NameValueCollectionExtensions.GetList<float>(s.settings, "shadowOffset", 0, 2); PointF shadowOffset = offset == null ? new PointF(0,0) : new PointF(offset[0], offset[1]); //Clone last ring, then offset it - provides the inner bounds of the shadow later s.layout.AddInvisiblePolygon("shadowInner", PolygonMath.MovePoly(s.layout.LastRing.points, shadowOffset)); //Determine the outer bound of the shadow s.layout.AddRing("shadow", PolygonMath.InflatePoly(s.layout.LastRing.points, new float[]{ Math.Max(0, shadowWidth - shadowOffset.Y), Math.Max(0, shadowWidth + shadowOffset.X), Math.Max(0, shadowWidth + shadowOffset.Y), Math.Max(0, shadowWidth - shadowOffset.X) })); } return RequestedAction.None; }
protected override RequestedAction PostRenderImage(ImageState s) { if (s.destBitmap == null) return RequestedAction.None; string str = null; int i = 0; if ("true".Equals(s.settings["r.autoeyes"], StringComparison.OrdinalIgnoreCase)) { List<ObjRect> eyes; using (var ed = new EyeDetection()) eyes = ed.DetectFeatures(s.sourceBitmap); List<PointF> points = new List<PointF>(); foreach(ObjRect r in eyes) { points.Add(new PointF(r.X,r.Y)); points.Add(new PointF(r.X2,r.Y2));} PointF[] newPoints = c.CurrentImageBuilder.TranslatePoints(points.ToArray(),s.originalSize,new ResizeSettings(s.settings)); using (Graphics g = Graphics.FromImage(s.destBitmap)){ for(i =0; i < newPoints.Length -1; i+=2){ float x1 = newPoints[i].X; float y1 = newPoints[i].Y; float x2 = newPoints[i + 1].X; float y2 = newPoints[i + 1].Y; float t; if (x1 > x2){ t = x2; x2 =x1; x1 = t;} if (y1 > y2){ t = y1; y1 = y2; y2 = t;} g.DrawRectangle(eyes[i /2].Feature == FeatureType.Eye ? Pens.Green : Pens.Gray,new Rectangle((int)x1,(int)y1,(int)(x2-x1),(int)(y2-y1))); } } } str = s.settings["r.filter"]; //radius if (!string.IsNullOrEmpty(str) && int.TryParse(str, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out i)) { using (s.destBitmap) { s.destBitmap = new RedEyeFilter((short)i).Apply(s.destBitmap); } //Note to future self: sobel/canny/eye kernel convolutions were not helpful; they were dead ends. } return RequestedAction.None; }
/// <summary> /// Supporting rounded corners. /// </summary> /// <param name="s"></param> /// <returns></returns> protected override RequestedAction PreRenderImage(ImageState s) { if (s.sourceBitmap == null) return RequestedAction.None; double[] vals = NameValueCollectionExtensions.GetList<double>(s.settings, "s.roundcorners",0,1,4); if (vals == null) return RequestedAction.None; if (vals.Length == 1) vals = new double[]{vals[0],vals[0],vals[0],vals[0]}; bool hasValue = false; foreach (double d in vals) if (d > 0) hasValue = true; if (!hasValue) return RequestedAction.None; Bitmap cropped = null; try{ //Make sure cropping is applied, and use existing prerendered bitmap if present. s.ApplyCropping(); cropped = s.preRenderBitmap ?? s.sourceBitmap; s.preRenderBitmap = new Bitmap(cropped.Width,cropped.Height, PixelFormat.Format32bppArgb); int[] radius = new int[4]; //Radius percentages are 0-100, a percentage of the smaller of the width and height. for (int i = 0; i < vals.Length; i++) radius[i] = (int)Math.Round(Math.Max(0,Math.Min(99.999,vals[i])) * ((double)Math.Min(s.preRenderBitmap.Width,s.preRenderBitmap.Height) / 100)); s.preRenderBitmap.MakeTransparent(); using (Graphics g = Graphics.FromImage(s.preRenderBitmap)) { g.SmoothingMode = SmoothingMode.AntiAlias; g.CompositingMode = CompositingMode.SourceOver; g.CompositingQuality = CompositingQuality.HighQuality; g.PixelOffsetMode = PixelOffsetMode.HighQuality; using (TextureBrush tb = new TextureBrush(cropped)) using (GraphicsPath gp = new GraphicsPath(FillMode.Winding)) { Rectangle bounds = new Rectangle(0, 0, s.preRenderBitmap.Width, s.preRenderBitmap.Height); int[] angles = new int[]{180,270,0,90}; int[] xs = new int[]{bounds.X,bounds.Right - radius[1], bounds.Right - radius[2], bounds.X}; int[] ys = new int[]{bounds.Y,bounds.Y,bounds.Bottom - radius[2], bounds.Bottom - radius[3]}; for (int i =0; i < 4; i++){ if (radius[i] > 0){ gp.AddArc(xs[i],ys[i],radius[i],radius[i],angles[i],90); }else{ gp.AddLine(xs[i],ys[i],xs[i],ys[i]); } } g.FillPath(tb, gp); } } }finally{ if (cropped != null & cropped != s.sourceBitmap) cropped.Dispose(); } return RequestedAction.None; }
/// <summary> /// Creates a bitmap of s.destSize dimensions, intializes a graphics object for it, and configures all the default settings. /// </summary> /// <param name="s"></param> protected override RequestedAction PrepareDestinationBitmap(ImageState s) { if (base.PrepareDestinationBitmap(s) == RequestedAction.Cancel) return RequestedAction.Cancel; if (s.sourceBitmap == null) return RequestedAction.None; //Create new bitmap using calculated size. s.destBitmap = new Bitmap(s.destSize.Width,s.destSize.Height, PixelFormat.Format32bppArgb); //Create graphics handle Graphics g = s.destGraphics = Graphics.FromImage(s.destBitmap); //High quality everthing g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; g.CompositingMode = CompositingMode.SourceOver; return RequestedAction.None; }
protected override RequestedAction LayoutRound(ImageState s) { if (base.LayoutRound(s) == RequestedAction.Cancel) return RequestedAction.Cancel; //Call extensions //Todo, round points here. //s.layout.Round(); return RequestedAction.None; }
protected override RequestedAction LayoutRotate(ImageState s) { if (base.LayoutRotate(s) == RequestedAction.Cancel) return RequestedAction.Cancel; //Call extensions //Now, rotate all rings. s.layout.Rotate(s.settings.Rotate, new PointF(0, 0)); return RequestedAction.None; }
protected override RequestedAction LayoutPadding(ImageState s) { if (base.LayoutPadding(s) == RequestedAction.Cancel) return RequestedAction.Cancel; //Call extensions //We need to add padding if (!s.settings.Padding.IsEmpty) { s.layout.AddRing("padding", s.settings.Padding); } return RequestedAction.None; }
protected RequestedAction RenderLayersForLevel(ImageState s, Layer.LayerPlacement only) { string watermark = s.settings["watermark"]; //from the querystring Graphics g = s.destGraphics; if (string.IsNullOrEmpty(watermark) || g == null) return RequestedAction.None; string[] parts = watermark.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries); bool foundPart = false; foreach (string w in parts) { if (NamedWatermarks.ContainsKey(w)) { IEnumerable<Layer> layers = NamedWatermarks[w]; foreach (Layer l in layers) { if (l.DrawAs == only) { l.RenderTo(s); } } foundPart = true; } } if ( !foundPart && only == Layer.LayerPlacement.Overlay) { //Parse named watermark files if (watermark.IndexOfAny(System.IO.Path.GetInvalidFileNameChars()) > -1 || watermark.IndexOfAny(new char[] { '\\', '/' }) > -1) throw new ArgumentException("Watermark value contained invalid file name characters: " + watermark); if (OtherImages != null && OtherImages.Path != null) { ImageLayer layer = OtherImages.Copy(); //Is the watermark dir a physical path? char slash = layer.Path.Contains("/") ? '/' : '\\'; layer.Path = layer.Path.TrimEnd(slash) + slash + watermark.TrimStart(slash); //If it's a forward-slash, and we're in asp.net, verify the file exists if (slash == '/' && HttpContext.Current != null && !c.Pipeline.FileExists(layer.Path, layer.ImageQuery)) return RequestedAction.None; layer.RenderTo(s); } else { this.LegacyDrawWatermark(s); } } return RequestedAction.None; }
protected override RequestedAction PostRenderImage(ImageState s) { Color? c = Util.ParseUtils.ParseColor(s.settings["s.overlay"]); if (c != null && s.destGraphics != null) { using (var b = new SolidBrush(c.Value)) { s.destGraphics.FillPolygon(b, s.layout["image"]); } } return RequestedAction.None; }
public LayoutInformation(ImageState state) { this.instructions = new NameValueCollection(state.settings); this.sourceRect = new SizeOnly(state.originalSize); this.finalRect = new SizeOnly(state.destSize); this.imageSourcePoly = new PolyRect(state.copyRect); if (state.layout.ContainsRing("image")) { this.imageDestPoly = new PolyRect(state.layout["image"]); } if (state.layout.ContainsRing("imageArea")) { this.imageDestAreaPoly = new PolyRect(state.layout["imageArea"]); } // Check to see if sFlip/sRotate has altered the original raw image // rectangle. The check must be the same as in // ImageBuilder.PrepareSourceBitmap(). Note that the adjustment // happens only when there's an actual bitmap, regardless of the // sFlip/sRotate settings. if (state.sourceBitmap != null && (state.settings.SourceFlip != RotateFlipType.RotateNoneFlipNone || !string.IsNullOrEmpty(state.settings["sRotate"]))) { // We need to calculate the original rect/poly by *reversing* the // requested sFlip/sRotate. We determine what the requested change // was, then calculate the reverse. var angle = state.settings.Get<double>("sRotate", 0); var flipRotate = (int)PolygonMath.CombineFlipAndRotate(state.settings.SourceFlip, angle); var copyPoly = PolygonMath.ToPoly(state.copyRect); var trueOriginalSize = state.originalSize; // The RotateFlipType values are ordered such that odd values // transpose the size of the rectangle, %4 gives the rotation // and /4 (=> 0 or 1) whether there's been an x-flip. We can // use this to streamline our calculations. if (flipRotate % 2 == 1) { trueOriginalSize = new Size(state.originalSize.Height, state.originalSize.Width); } this.preAdjustedSourceRect = new SizeOnly(trueOriginalSize); // Remember that the sFlip/sRotate change performed the rotation // first and then the flip, so we have to do the opposite to go // backwards. if (flipRotate / 4 == 1) { copyPoly = PolygonMath.ScalePoints(copyPoly, -1, 1, PointF.Empty); copyPoly = PolygonMath.MovePoly(copyPoly, new PointF(trueOriginalSize.Width, 0)); } // It's possible to calculate a rotation-origin that will place // the original pre-sRotate (0,0) point back at (0,0) again... // but since it involves sqrt(), there would be rounding errors // that we should be able to avoid. (We might, in fact, want to // avoid using PolygonMath entirely, and hand-map the points // backwards for accuracy.) switch (flipRotate % 4) { case 0: // no rotation // no-op! break; case 1: // 90 degrees, clockwise copyPoly = PolygonMath.RotatePoly(copyPoly, -90); copyPoly = PolygonMath.MovePoly(copyPoly, new PointF(0, trueOriginalSize.Height)); break; case 2: // 180 degrees, clockwise copyPoly = PolygonMath.RotatePoly(copyPoly, -180); copyPoly = PolygonMath.MovePoly(copyPoly, new PointF(trueOriginalSize.Width, trueOriginalSize.Height)); break; case 3: // 270 degrees, clockwise copyPoly = PolygonMath.RotatePoly(copyPoly, -270); copyPoly = PolygonMath.MovePoly(copyPoly, new PointF(trueOriginalSize.Width, 0)); break; } this.preAdjustedImageSourcePoly = new PolyRect(copyPoly); } }
protected override RequestedAction PostCreateImageAttributes(ImageState s) { if (s.copyAttibutes == null) return RequestedAction.None; if (!s.settings.WasOneSpecified((string[])GetSupportedQuerystringKeys())) return RequestedAction.None; List<float[][]> filters = new List<float[][]>(); string filter = s.settings["filter"]; if (!string.IsNullOrEmpty(filter)) { int valuesStart = filter.IndexOf('('); string valStr = null; double[] values = null; if (valuesStart > -1) { valStr = filter.Substring(valuesStart); filter = filter.Substring(0, valuesStart); values = ParseUtils.ParseList<double>(valStr, 0,0,1); } if ("grayscale".Equals(filter, StringComparison.OrdinalIgnoreCase)) filters.Add(GrayscaleFlat()); if ("sepia".Equals(filter, StringComparison.OrdinalIgnoreCase)) filters.Add(Sepia()); if (values != null && values.Length == 1) { if ("alpha".Equals(filter, StringComparison.OrdinalIgnoreCase)) filters.Add(Alpha((float)values[0])); if ("brightness".Equals(filter, StringComparison.OrdinalIgnoreCase)) filters.Add(Brightness((float)values[0])); } } if ("true".Equals(s.settings["s.grayscale"], StringComparison.OrdinalIgnoreCase)) filters.Add(GrayscaleNTSC()); if ("flat".Equals(s.settings["s.grayscale"], StringComparison.OrdinalIgnoreCase)) filters.Add(GrayscaleFlat()); if ("y".Equals(s.settings["s.grayscale"], StringComparison.OrdinalIgnoreCase)) filters.Add(GrayscaleY()); if ("ry".Equals(s.settings["s.grayscale"], StringComparison.OrdinalIgnoreCase)) filters.Add(GrayscaleRY()); if ("ntsc".Equals(s.settings["s.grayscale"], StringComparison.OrdinalIgnoreCase)) filters.Add(GrayscaleNTSC()); if ("bt709".Equals(s.settings["s.grayscale"], StringComparison.OrdinalIgnoreCase)) filters.Add(GrayscaleBT709()); if ("true".Equals(s.settings["s.sepia"], StringComparison.OrdinalIgnoreCase)) filters.Add(Sepia()); if ("true".Equals(s.settings["s.invert"], StringComparison.OrdinalIgnoreCase)) filters.Add(Invert()); Color? c = Util.ParseUtils.ParseColor(s.settings["s.shift"]); if (c != null) filters.Add(Shift(c.Value)); string alpha = s.settings["s.alpha"]; string brightness = s.settings["s.brightness"]; string contrast = s.settings["s.contrast"]; string saturation = s.settings["s.saturation"]; double temp = 0; if (!string.IsNullOrEmpty(alpha) && double.TryParse(alpha, ParseUtils.FloatingPointStyle, NumberFormatInfo.InvariantInfo, out temp)) filters.Add(Alpha((float)temp)); if (!string.IsNullOrEmpty(brightness) && double.TryParse(brightness, ParseUtils.FloatingPointStyle, NumberFormatInfo.InvariantInfo, out temp)) filters.Add(Brightness((float)temp)); if (!string.IsNullOrEmpty(contrast) && double.TryParse(contrast, ParseUtils.FloatingPointStyle, NumberFormatInfo.InvariantInfo, out temp)) filters.Add(Contrast((float)temp)); if (!string.IsNullOrEmpty(saturation) && double.TryParse(saturation, ParseUtils.FloatingPointStyle, NumberFormatInfo.InvariantInfo, out temp)) filters.Add(Saturation((float)temp)); if (filters.Count == 0) return RequestedAction.None; if (filters.Count == 1) s.copyAttibutes.SetColorMatrix(new ColorMatrix(filters[0])); else { //Multiple all the filters float[][] first = filters[0]; for (int i = 1; i < filters.Count; i++) { first = Multiply(first, filters[i]); } s.copyAttibutes.SetColorMatrix(new ColorMatrix(first)); } return RequestedAction.None; }
protected override RequestedAction LayoutBorder(ImageState s) { if (base.LayoutBorder(s) == RequestedAction.Cancel) return RequestedAction.Cancel; //Call extensions //And borders if (!s.settings.Border.IsEmpty) { s.layout.AddRing("border", s.settings.Border); } return RequestedAction.None; }
protected override RequestedAction PostRenderBackground(ImageState s) { return RenderLayersForLevel(s, Layer.LayerPlacement.Background); }
/// <summary> /// Populates copyRect, as well as Rings image and imageArea. Translates and scales any existing rings as if they existed on the original bitmap. /// </summary> /// <param name="s"></param> protected override RequestedAction LayoutImage(ImageState s) { if (base.LayoutImage(s) == RequestedAction.Cancel) return RequestedAction.Cancel; //Call extensions if (s.copyRect.IsEmpty) { //Use the crop size if present. s.copyRect = new RectangleF(new PointF(0, 0), s.originalSize); if (NameValueCollectionExtensions.GetList<double>(s.settings, "crop", 0, 4) != null) { s.copyRect = PolygonMath.ToRectangle(s.settings.getCustomCropSourceRect(s.originalSize)); //Round the custom crop rectangle coordinates if (s.copyRect.Size.IsEmpty) throw new Exception("You must specify a custom crop rectange if crop=custom"); } } //Save the manual crop size. SizeF manualCropSize = s.copySize; RectangleF manualCropRect = s.copyRect; FitMode fit = s.settings.Mode; //Determine fit mode to use if both vertical and horizontal limits are used. if (fit == FitMode.None){ if (s.settings.Width != -1 || s.settings.Height != -1){ if ("fill".Equals(s.settings["stretch"], StringComparison.OrdinalIgnoreCase)) fit = FitMode.Stretch; else if ("auto".Equals(s.settings["crop"], StringComparison.OrdinalIgnoreCase)) fit = FitMode.Crop; else if (!string.IsNullOrEmpty(s.settings["carve"]) && !"false".Equals(s.settings["carve"], StringComparison.OrdinalIgnoreCase) && !"none".Equals(s.settings["carve"], StringComparison.OrdinalIgnoreCase)) fit = FitMode.Carve; else fit = FitMode.Pad; }else{ fit = FitMode.Max; } } //Aspect ratio of the image double imageRatio = s.copySize.Width / s.copySize.Height; //Zoom factor double zoom = s.settings.Get<double>("zoom", 1); //The target size for the image SizeF targetSize = new SizeF(-1, -1); //Target area for the image SizeF areaSize = new SizeF(-1, -1); //If any dimensions are specified, calculate. Otherwise, use original image dimensions if (s.settings.Width != -1 || s.settings.Height != -1 || s.settings.MaxHeight != -1 || s.settings.MaxWidth != -1) { //A dimension was specified. //We first calculate the largest size the image can be under the width/height/maxwidth/maxheight restrictions. //- pretending stretch=fill and scale=both //Temp vars - results stored in targetSize and areaSize double width = s.settings.Width; double height = s.settings.Height; double maxwidth = s.settings.MaxWidth; double maxheight = s.settings.MaxHeight; //Eliminate cases where both a value and a max value are specified: use the smaller value for the width/height if (maxwidth > 0 && width > 0) { width = Math.Min(maxwidth, width); maxwidth = -1; } if (maxheight > 0 && height > 0) { height = Math.Min(maxheight, height); maxheight = -1; } //Handle cases of width/maxheight and height/maxwidth as in legacy versions. if (width != -1 && maxheight != -1) maxheight = Math.Min(maxheight, (width / imageRatio)); if (height != -1 && maxwidth != -1) maxwidth = Math.Min(maxwidth, (height * imageRatio)); //Move max values to width/height. FitMode should already reflect the mode we are using, and we've already resolved mixed modes above. width = Math.Max(width, maxwidth); height = Math.Max(height, maxheight); //Calculate missing value (a missing value is handled the same everywhere). if (width > 0 && height <= 0) height = width/ imageRatio; else if (height > 0 && width <= 0) width = height * imageRatio; //We now have width & height, our target size. It will only be a different aspect ratio from the image if both 'width' and 'height' are specified. //FitMode.Max if (fit == FitMode.Max) { areaSize = targetSize = PolygonMath.ScaleInside(manualCropSize, new SizeF((float)width, (float)height)); //FitMode.Pad } else if (fit == FitMode.Pad) { areaSize = new SizeF((float)width, (float)height); targetSize = PolygonMath.ScaleInside(manualCropSize, areaSize); //FitMode.crop } else if (fit == FitMode.Crop) { //We autocrop - so both target and area match the requested size areaSize = targetSize = new SizeF((float)width, (float)height); RectangleF copyRect; ScaleMode scale = s.settings.Scale; bool cropWidthSmaller = manualCropSize.Width <= (float)width; bool cropHeightSmaller = manualCropSize.Height <= (float)height; // With both DownscaleOnly (where only one dimension is smaller than // requested) and UpscaleCanvas, we will have a targetSize based on the // minWidth & minHeight. // TODO: what happens if mode=crop;scale=down but the target is larger than the source? if ((scale == ScaleMode.DownscaleOnly && (cropWidthSmaller != cropHeightSmaller)) || (scale == ScaleMode.UpscaleCanvas)) { var minWidth = Math.Min(manualCropSize.Width, (float)width); var minHeight = Math.Min(manualCropSize.Height, (float)height); targetSize = new SizeF(minWidth, minHeight); copyRect = manualCropRect = new RectangleF(0, 0, minWidth, minHeight); // For DownscaleOnly, the areaSize is adjusted to the new targetSize as well. if (scale == ScaleMode.DownscaleOnly) { areaSize = targetSize; } } else { //Determine the size of the area we are copying Size sourceSize = PolygonMath.RoundPoints(PolygonMath.ScaleInside(areaSize, manualCropSize)); //Center the portion we are copying within the manualCropSize copyRect = new RectangleF(0, 0, sourceSize.Width, sourceSize.Height); } // Align the actual source-copy rectangle inside the available // space based on the anchor. s.copyRect = PolygonMath.ToRectangle(PolygonMath.AlignWith(copyRect, s.copyRect, s.settings.Anchor)); } else { //Stretch and carve both act like stretching, so do that: areaSize = targetSize = new SizeF((float)width, (float)height); } }else{ //No dimensions specified, no fit mode needed. Use manual crop dimensions areaSize = targetSize = manualCropSize; } //Multiply both areaSize and targetSize by zoom. areaSize.Width *= (float)zoom; areaSize.Height *= (float)zoom; targetSize.Width *= (float)zoom; targetSize.Height *= (float)zoom; //Todo: automatic crop is permitted to break the scaling rules. Fix!! //Now do upscale/downscale checks. If they take effect, set targetSize to imageSize if (s.settings.Scale == ScaleMode.DownscaleOnly) { if (PolygonMath.FitsInside(manualCropSize, targetSize)) { //The image is smaller or equal to its target polygon. Use original image coordinates instead. areaSize = targetSize = manualCropSize; s.copyRect = manualCropRect; } } else if (s.settings.Scale == ScaleMode.UpscaleOnly) { if (!PolygonMath.FitsInside(manualCropSize, targetSize)) { //The image is larger than its target. Use original image coordintes instead areaSize = targetSize = manualCropSize; s.copyRect = manualCropRect; } } else if (s.settings.Scale == ScaleMode.UpscaleCanvas) { //Same as downscaleonly, except areaSize isn't changed. if (PolygonMath.FitsInside(manualCropSize, targetSize)) { //The image is smaller or equal to its target polygon. //Use manual copy rect/size instead. targetSize = manualCropSize; s.copyRect = manualCropRect; } } //May 12: require max dimension and round values to minimize rounding differences later. areaSize.Width = Math.Max(1, (float)Math.Round(areaSize.Width)); areaSize.Height = Math.Max(1, (float)Math.Round(areaSize.Height)); targetSize.Width = Math.Max(1, (float)Math.Round(targetSize.Width)); targetSize.Height = Math.Max(1, (float)Math.Round(targetSize.Height)); //Translate and scale all existing rings s.layout.Shift(s.copyRect, new RectangleF(new Point(0, 0), targetSize)); s.layout.AddRing("image", PolygonMath.ToPoly(new RectangleF(new PointF(0, 0), targetSize))); s.layout.AddRing("imageArea",PolygonMath.ToPoly(new RectangleF(new PointF(0, 0), areaSize))); //Center imageArea around 'image' s.layout["imageArea"] = PolygonMath.AlignWith(s.layout["imageArea"], s.layout["image"], s.settings.Anchor); return RequestedAction.None; }
protected override RequestedAction RenderOverlays(ImageState s) { return RenderLayersForLevel(s, Layer.LayerPlacement.Overlay); }
protected override RequestedAction LayoutNormalize(ImageState s) { if (base.LayoutNormalize(s) == RequestedAction.Cancel) return RequestedAction.Cancel; //Call extensions //Normalize all the rings s.layout.Normalize(new PointF(0, 0)); return RequestedAction.None; }