private void DrawGradient(Graphics g) { g.PixelOffsetMode = PixelOffsetMode.Half; Rectangle gradientRect; float gradientAngle; switch (this.orientation) { case Orientation.Horizontal: gradientAngle = 180.0f; break; case Orientation.Vertical: gradientAngle = 90.0f; break; default: throw new InvalidEnumArgumentException(); } // draw gradient gradientRect = ClientRectangle; switch (this.orientation) { case Orientation.Horizontal: gradientRect.Inflate(-triangleHalfLength, -triangleSize + 3); break; case Orientation.Vertical: gradientRect.Inflate(-triangleSize + 3, -triangleHalfLength); break; default: throw new InvalidEnumArgumentException(); } if (this.customGradient != null && gradientRect.Width > 1 && gradientRect.Height > 1) { Surface gradientSurface = new Surface(gradientRect.Size); using (RenderArgs ra = new RenderArgs(gradientSurface)) { Utility.DrawColorRectangle(ra.Graphics, ra.Bounds, Color.Transparent, false); if (Orientation == Orientation.Horizontal) { for (int x = 0; x < gradientSurface.Width; ++x) { // TODO: refactor, double buffer, save this computation in a bitmap somewhere double index = (double)(x * (this.customGradient.Length - 1)) / (double)(gradientSurface.Width - 1); int indexL = (int)Math.Floor(index); double t = 1.0 - (index - indexL); int indexR = (int)Math.Min(this.customGradient.Length - 1, Math.Ceiling(index)); Color colorL = this.customGradient[indexL]; Color colorR = this.customGradient[indexR]; double a1 = colorL.A / 255.0; double r1 = colorL.R / 255.0; double g1 = colorL.G / 255.0; double b1 = colorL.B / 255.0; double a2 = colorR.A / 255.0; double r2 = colorR.R / 255.0; double g2 = colorR.G / 255.0; double b2 = colorR.B / 255.0; double at = (t * a1) + ((1.0 - t) * a2); double rt; double gt; double bt; if (at == 0) { rt = 0; gt = 0; bt = 0; } else { rt = ((t * a1 * r1) + ((1.0 - t) * a2 * r2)) / at; gt = ((t * a1 * g1) + ((1.0 - t) * a2 * g2)) / at; bt = ((t * a1 * b1) + ((1.0 - t) * a2 * b2)) / at; } int ap = Utility.Clamp((int)Math.Round(at * 255.0), 0, 255); int rp = Utility.Clamp((int)Math.Round(rt * 255.0), 0, 255); int gp = Utility.Clamp((int)Math.Round(gt * 255.0), 0, 255); int bp = Utility.Clamp((int)Math.Round(bt * 255.0), 0, 255); for (int y = 0; y < gradientSurface.Height; ++y) { ColorBgra src = gradientSurface[x, y]; // we are assuming that src.A = 255 int rd = ((rp * ap) + (src.R * (255 - ap))) / 255; int gd = ((gp * ap) + (src.G * (255 - ap))) / 255; int bd = ((bp * ap) + (src.B * (255 - ap))) / 255; // TODO: proper alpha blending! gradientSurface[x, y] = ColorBgra.FromBgra((byte)bd, (byte)gd, (byte)rd, 255); } } g.DrawImage(ra.Bitmap, gradientRect, ra.Bounds, GraphicsUnit.Pixel); } else if (Orientation == Orientation.Vertical) { // TODO } else { throw new InvalidEnumArgumentException(); } } gradientSurface.Dispose(); } else { using (LinearGradientBrush lgb = new LinearGradientBrush(this.ClientRectangle, maxColor, minColor, gradientAngle, false)) { g.FillRectangle(lgb, gradientRect); } } // fill background using (PdnRegion nonGradientRegion = new PdnRegion()) { nonGradientRegion.MakeInfinite(); nonGradientRegion.Exclude(gradientRect); using (SolidBrush sb = new SolidBrush(this.BackColor)) { g.FillRegion(sb, nonGradientRegion.GetRegionReadOnly()); } } // draw value triangles for (int i = 0; i < this.vals.Length; i++) { int pos = ValueToPosition(vals[i]); Brush brush; Pen pen; if (i == highlight) { brush = Brushes.Blue; pen = (Pen)Pens.White.Clone(); } else { brush = Brushes.Black; pen = (Pen)Pens.Gray.Clone(); } g.SmoothingMode = SmoothingMode.AntiAlias; Point a1; Point b1; Point c1; Point a2; Point b2; Point c2; switch (this.orientation) { case Orientation.Horizontal: a1 = new Point(pos - triangleHalfLength, 0); b1 = new Point(pos, triangleSize - 1); c1 = new Point(pos + triangleHalfLength, 0); a2 = new Point(a1.X, Height - 1 - a1.Y); b2 = new Point(b1.X, Height - 1 - b1.Y); c2 = new Point(c1.X, Height - 1 - c1.Y); break; case Orientation.Vertical: a1 = new Point(0, pos - triangleHalfLength); b1 = new Point(triangleSize - 1, pos); c1 = new Point(0, pos + triangleHalfLength); a2 = new Point(Width - 1 - a1.X, a1.Y); b2 = new Point(Width - 1 - b1.X, b1.Y); c2 = new Point(Width - 1 - c1.X, c1.Y); break; default: throw new InvalidEnumArgumentException(); } if (this.drawNearNub) { g.FillPolygon(brush, new Point[] { a1, b1, c1, a1 }); } if (this.drawFarNub) { g.FillPolygon(brush, new Point[] { a2, b2, c2, a2 }); } if (pen != null) { if (this.drawNearNub) { g.DrawPolygon(pen, new Point[] { a1, b1, c1, a1 }); } if (this.drawFarNub) { g.DrawPolygon(pen, new Point[] { a2, b2, c2, a2 }); } pen.Dispose(); } } }
public override ColorBgra Apply(ColorBgra color) { return(ColorBgra.FromBgra(CurveB[color.B], CurveG[color.G], CurveR[color.R], color.A)); }
/// <summary> /// Returns a new ColorBgra with the same color values but with a new alpha component value. /// </summary> public ColorBgra NewAlpha(byte newA) { return(ColorBgra.FromBgra(B, G, R, newA)); }
public override ColorBgra Apply(ColorBgra color) { byte i = color.GetIntensityByte(); return(ColorBgra.FromBgra(i, i, i, color.A)); }
public override ColorBgra Apply(ColorBgra color) { byte average = (byte)(((int)color.R + (int)color.G + (int)color.B) / 3); return(ColorBgra.FromBgra(average, average, average, color.A)); }
public override ColorBgra Apply(ColorBgra color) { return(ColorBgra.FromBgra((byte)(255 - color.B), (byte)(255 - color.G), (byte)(255 - color.R), (byte)(255 - color.A))); }
public BitmapLayer(int width, int height) : this(width, height, ColorBgra.FromBgra(255, 255, 255, 0)) { }
protected unsafe override sealed void OnSaveT( Document input, Stream output, PropertyBasedSaveConfigToken token, Surface scratchSurface, ProgressEventHandler progressCallback) { // flatten the document -- render w/ transparent background scratchSurface.Clear(ColorBgra.Transparent); using (RenderArgs ra = new RenderArgs(scratchSurface)) { input.Render(ra, false); } // load properties from token int thresholdFromToken = GetThresholdFromToken(token); int ditherLevel = GetDitherLevelFromToken(token); Set <SavableBitDepths> allowedBitDepths = CreateAllowedBitDepthListFromToken(token); if (allowedBitDepths.Count == 0) { throw new ArgumentException("there must be at least 1 element returned from CreateAllowedBitDepthListFromToken()"); } // allowedBitDepths.Count >= 1 // set to 1 unless allowedBitDepths contains only Rgb8 and Rgba8 int threshold; if (allowedBitDepths.IsSubsetOf(Set.Create(SavableBitDepths.Rgb8, SavableBitDepths.Rgba8))) { threshold = thresholdFromToken; } else { threshold = 1; } // Analyze image, try to detect what bit-depth or whatever to use, based on allowedBitDepths bool allOpaque; bool all0or255Alpha; int uniqueColorCount; Analyze(scratchSurface, out allOpaque, out all0or255Alpha, out uniqueColorCount); Set <SavableBitDepths> losslessBitDepths = new Set <SavableBitDepths>(); losslessBitDepths.Add(SavableBitDepths.Rgba32); if (allOpaque) { losslessBitDepths.Add(SavableBitDepths.Rgb24); if (uniqueColorCount <= 256) { losslessBitDepths.Add(SavableBitDepths.Rgb8); } } else if (all0or255Alpha && uniqueColorCount < 256) { losslessBitDepths.Add(SavableBitDepths.Rgba8); } SavableBitDepths bitDepth = ChooseBitDepth(allowedBitDepths, losslessBitDepths, allOpaque, all0or255Alpha, uniqueColorCount); if (bitDepth == SavableBitDepths.Rgba8 && threshold == 0 && allowedBitDepths.Contains(SavableBitDepths.Rgba8) && allowedBitDepths.Contains(SavableBitDepths.Rgb8)) { // threshold of 0 should effectively force full 256 color palette, instead of 255+1 transparent bitDepth = SavableBitDepths.Rgb8; } // if bit depth is 24 or 8, then we have to do away with the alpha channel // for 8-bit, we must have pixels that have either 0 or 255 alpha if (bitDepth == SavableBitDepths.Rgb8 || bitDepth == SavableBitDepths.Rgba8 || bitDepth == SavableBitDepths.Rgb24) { UserBlendOps.NormalBlendOp blendOp = new UserBlendOps.NormalBlendOp(); for (int y = 0; y < scratchSurface.Height; ++y) { for (int x = 0; x < scratchSurface.Width; ++x) { ColorBgra p = scratchSurface[x, y]; if (p.A < threshold && bitDepth == SavableBitDepths.Rgba8) { p = ColorBgra.FromBgra(0, 0, 0, 0); } else { p = blendOp.Apply(ColorBgra.White, p); } scratchSurface[x, y] = p; } } } Tracing.Ping("Chose " + bitDepth + ", ditherLevel=" + ditherLevel + ", threshold=" + threshold); // finally, do the save. FinalSave(input, output, scratchSurface, ditherLevel, bitDepth, token, progressCallback); }