/// <summary> /// Converts an XColor into a string with up to 3 decimal digits and a decimal point. /// </summary> public static string ToString(XColor color, PdfColorMode colorMode) { const string format = Config.SignificantFigures3; // If not defined let color decide if (colorMode == PdfColorMode.Undefined) { if (color.ColorSpace == XColorSpace.GrayScale) { return(string.Format(CultureInfo.InvariantCulture, "{0:" + format + "}", color.GS)); } colorMode = color.ColorSpace == XColorSpace.Cmyk ? PdfColorMode.Cmyk : PdfColorMode.Rgb; } switch (colorMode) { case PdfColorMode.Cmyk: return(String.Format(CultureInfo.InvariantCulture, "{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "}", color.C, color.M, color.Y, color.K)); default: return(String.Format(CultureInfo.InvariantCulture, "{0:" + format + "} {1:" + format + "} {2:" + format + "}", color.R / 255.0, color.G / 255.0, color.B / 255.0)); } }
internal void RealizeNonStrokeTransparency(double transparency, PdfColorMode colorMode) { XColor color = _realizedFillColor; color.A = transparency; RealizeFillColor(color, _realizedNonStrokeOverPrint, colorMode); }
/// <summary> /// Checks whether a color mode and a color match. /// </summary> public static XColor EnsureColorMode(PdfColorMode colorMode, XColor color) { #if true if (colorMode == PdfColorMode.Rgb && color.ColorSpace != XColorSpace.Rgb) { return(XColor.FromArgb((int)(color.A * 255), color.R, color.G, color.B)); } if (colorMode == PdfColorMode.Cmyk && color.ColorSpace != XColorSpace.Cmyk) { return(XColor.FromCmyk(color.A, color.C, color.M, color.Y, color.K)); } return(color); #else if (colorMode == PdfColorMode.Rgb && color.ColorSpace != XColorSpace.Rgb) { throw new InvalidOperationException(PSSR.InappropriateColorSpace(colorMode, color.ColorSpace)); } if (colorMode == PdfColorMode.Cmyk && color.ColorSpace != XColorSpace.Cmyk) { throw new InvalidOperationException(PSSR.InappropriateColorSpace(colorMode, color.ColorSpace)); } #endif }
public void RealizeBrush(XBrush brush, PdfColorMode colorMode, int renderingMode, double fontEmSize, bool isForPen = false) { // Rendering mode 2 is used for bold simulation. // Reference: TABLE 5.3 Text rendering modes / Page 402 XSolidBrush solidBrush = brush as XSolidBrush; if (solidBrush != null) { XColor color = solidBrush.Color; bool overPrint = solidBrush.Overprint; if (renderingMode == 0) { RealizeFillColor(color, overPrint, colorMode); } else if (renderingMode == 2) { // Come here in case of bold simulation. RealizeFillColor(color, false, colorMode); //color = XColors.Green; RealizePen(new XPen(color, fontEmSize * Const.BoldEmphasis), colorMode); } else { throw new InvalidOperationException("Only rendering modes 0 and 2 are currently supported."); } } else { if (renderingMode != 0) { throw new InvalidOperationException("Rendering modes other than 0 can only be used with solid color brushes."); } if (brush is XBaseGradientBrush gradientBrush) { Debug.Assert(UnrealizedCtm.IsIdentity, "Must realize ctm first."); XMatrix matrix = _renderer.DefaultViewMatrix; matrix.Prepend(EffectiveCtm); PdfShadingPattern pattern = new PdfShadingPattern(_renderer.Owner); pattern.SetupFromBrush(gradientBrush, matrix, _renderer); string name = _renderer.Resources.AddPattern(pattern); if (isForPen) { _renderer.AppendFormatString("/Pattern CS\n", name); _renderer.AppendFormatString("{0} SCN\n", name); } else { _renderer.AppendFormatString("/Pattern cs\n", name); _renderer.AppendFormatString("{0} scn\n", name); } // Invalidate fill color. _realizedFillColor = XColor.Empty; } } }
internal void SetupFromBrush(XRadialGradientBrush brush, XGraphicsPdfRenderer renderer) { if (brush == null) { throw new ArgumentNullException("brush"); } PdfColorMode colorMode = _document.Options.ColorMode; XColor color1 = ColorSpaceHelper.EnsureColorMode(colorMode, brush._color1); XColor color2 = ColorSpaceHelper.EnsureColorMode(colorMode, brush._color2); PdfDictionary function = new PdfDictionary(); Elements[Keys.ShadingType] = new PdfInteger(3); if (colorMode != PdfColorMode.Cmyk) { Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB"); } else { Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK"); } XPoint p1 = renderer.WorldToView(brush._center1); XPoint p2 = renderer.WorldToView(brush._center2); var rv1 = renderer.WorldToView(new XPoint(brush._r1 + brush._center1.X, brush._center1.Y)); var rv2 = renderer.WorldToView(new XPoint(brush._r2 + brush._center2.X, brush._center2.Y)); var dx1 = rv1.X - p1.X; var dy1 = rv1.Y - p1.Y; var dx2 = rv2.X - p2.X; var dy2 = rv2.Y - p2.Y; var r1 = Math.Sqrt(dx1 * dx1 + dy1 * dy1); var r2 = Math.Sqrt(dx2 * dx2 + dy2 * dy2); const string format = Config.SignificantFigures3; Elements[Keys.Coords] = new PdfLiteral("[{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "}]", p1.X, p1.Y, r1, p2.X, p2.Y, r2); //Elements[Keys.Background] = new PdfRawItem("[0 1 1]"); //Elements[Keys.Domain] = Elements[Keys.Function] = function; //Elements[Keys.Extend] = new PdfRawItem("[true true]"); string clr1 = "[" + PdfEncoders.ToString(color1, colorMode, true) + "]"; string clr2 = "[" + PdfEncoders.ToString(color2, colorMode, true) + "]"; function.Elements["/FunctionType"] = new PdfInteger(2); function.Elements["/C0"] = new PdfLiteral(clr1); function.Elements["/C1"] = new PdfLiteral(clr2); function.Elements["/Domain"] = new PdfLiteral("[0 1]"); function.Elements["/N"] = new PdfInteger(1); }
public void RealizeBrush(XBrush brush, PdfColorMode colorMode) { if (brush is XSolidBrush) { XColor color = ((XSolidBrush)brush).Color; color = ColorSpaceHelper.EnsureColorMode(colorMode, color); if (colorMode != PdfColorMode.Cmyk) { if (this.realizedFillColor.Rgb != color.Rgb) { this.renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Rgb)); this.renderer.Append(" rg\n"); } } else { if (!ColorSpaceHelper.IsEqualCmyk(this.realizedFillColor, color)) { this.renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Cmyk)); this.renderer.Append(" k\n"); } } if (this.renderer.Owner.Version >= 14 && this.realizedFillColor.A != color.A) { PdfExtGState extGState = this.renderer.Owner.ExtGStateTable.GetExtGStateNonStroke(color.A); string gs = this.renderer.Resources.AddExtGState(extGState); this.renderer.AppendFormat("{0} gs\n", gs); // Must create transparany group if (this.renderer.page != null && color.A < 1) { this.renderer.page.transparencyUsed = true; } } this.realizedFillColor = color; } else if (brush is XLinearGradientBrush) { XMatrix matrix = this.renderer.defaultViewMatrix; matrix.Prepend(this.Transform); PdfShadingPattern pattern = new PdfShadingPattern(this.renderer.Owner); pattern.SetupFromBrush((XLinearGradientBrush)brush, matrix); string name = this.renderer.Resources.AddPattern(pattern); this.renderer.AppendFormat("/Pattern cs\n", name); this.renderer.AppendFormat("{0} scn\n", name); // Invalidate fill color this.realizedFillColor = XColor.Empty; } }
PdfShading BuildShading(RadialGradientBrush brush, double scaleX, double scaleY) { // Setup shading //<< // /AntiAlias false // /ColorSpace 12 0 R // /Coords [120 120 120 120 120 0] // /Domain [0 1] // /Extend [false false] // /Function 14 0 R // /ShadingType 3 //>> PdfShading shading = Context.PdfDocument.Internals.CreateIndirectObject <PdfShading>(); shading.Elements.SetInteger(PdfShading.Keys.ShadingType, 3); // Radial shading PdfColorMode colorMode = PdfColorMode.Rgb; //this.document.Options.ColorMode; if (colorMode != PdfColorMode.Cmyk) { shading.Elements[PdfShading.Keys.ColorSpace] = new PdfName("/DeviceRGB"); } else { shading.Elements[PdfShading.Keys.ColorSpace] = new PdfName("/DeviceCMYK"); } //bool invers = true; PdfDictionary function = null; // BuildShadingFunction(brush.GradientStops, false, colorMode); #if DEBUG_ if (DevHelper.RenderComments) { funcRegular.Elements.SetString("/@comment", "This is the shading function of a RadialGradientBrushPattern"); } #endif shading.Elements[PdfShading.Keys.Function] = function; shading.Elements[PdfShading.Keys.Extend] = new PdfLiteral("[false false]"); double x0 = brush.Center.X / scaleX; double y0 = brush.Center.Y / scaleY; double r0 = Math.Max(brush.RadiusX, brush.RadiusY); double x1 = brush.GradientOrigin.X / scaleX; double y1 = brush.GradientOrigin.Y / scaleY; double r1 = 0; shading.Elements[PdfShading.Keys.Coords] = new PdfLiteral("[{0:0.###} {1:0.###} {2:0.###} {3:0.###} {4:0.###} {5:0.###}]", x0, y0, r0, x1, y1, r1); return(shading); }
/// <summary> /// Checks whether a color mode and a color match. /// </summary> public static XColor EnsureColorMode(PdfColorMode colorMode, XColor color) { if (colorMode == PdfColorMode.Rgb && color.ColorSpace != XColorSpace.Rgb) { return(XColor.FromArgb((int)(color.A * 255), color.R, color.G, color.B)); } if (colorMode == PdfColorMode.Cmyk && color.ColorSpace != XColorSpace.Cmyk) { return(XColor.FromCmyk(color.A, color.C, color.M, color.Y, color.K)); } return(color); }
/// <summary> /// Builds a PdfShading from the specified brush. If a gradient contains transparency, a soft mask is created an added to the /// specified graphic state. /// </summary> PdfShading BuildShading(LinearGradientBrush brush) { // Setup shading PdfShading shading = new PdfShading(Context.PdfDocument); #if DEBUG if (DevHelper.RenderComments) { shading.Elements.SetString("/@comment", "This is the shading of a LinearGradientBrush"); } #endif PdfColorMode colorMode = PdfColorMode.Rgb; //this.document.Options.ColorMode; PdfDictionary function = BuildShadingFunction(brush.GradientStops, false, colorMode); #if DEBUG if (DevHelper.RenderComments) { function.Elements.SetString("/@comment", "This is the shading function of a LinearGradientBrush"); } #endif shading.Elements.SetBoolean(PdfShading.Keys.AntiAlias, false); shading.Elements[PdfShading.Keys.Function] = function; shading.Elements.SetInteger(PdfShading.Keys.ShadingType, 2); // Axial shading shading.Elements.SetName(PdfShading.Keys.ColorSpace, "/DeviceRGB"); // TODO: respect ColorMode double x1 = brush.StartPoint.X; double y1 = brush.StartPoint.Y; double x2 = brush.EndPoint.X; double y2 = brush.EndPoint.Y; shading.Elements[PdfShading.Keys.Coords] = new PdfLiteral("[{0:0.####} {1:0.####} {2:0.####} {3:0.####}]", x1, y1, x2, y2); shading.Elements[PdfShading.Keys.Domain] = new PdfLiteral("[0 1]"); if (brush.SpreadMethod == SpreadMethod.Pad) { shading.Elements[PdfShading.Keys.Extend] = new PdfLiteral("[true true]"); } else { DevHelper.NotImplemented("SpreadMethod." + brush.SpreadMethod.ToString() + " Background painted in green."); #if DEBUG // Note from PDF reference: The background color is applied only when the shading is used as part of // a shading pattern, not when it is painted directly with the sh operator. shading.Elements[PdfShading.Keys.Background] = new PdfLiteral("[0 1 0]"); // TODO: respect ColorMode #else // Best we can currently do shading.Elements[PdfShading.Keys.Extend] = new PdfLiteral("[true true]"); #endif } return(shading); }
private void RealizeFillColor(XColor color, bool overPrint, PdfColorMode colorMode) { color = ColorSpaceHelper.EnsureColorMode(colorMode, color); switch (color.ColorSpace) { case XColorSpace.Rgb: if (_realizedFillColor.IsEmpty || _realizedFillColor.Rgb != color.Rgb) { _renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Rgb)); _renderer.Append(" rg\n"); } break; case XColorSpace.Cmyk: if (_realizedFillColor.IsEmpty || !ColorSpaceHelper.IsEqualCmyk(_realizedFillColor, color)) { _renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Cmyk)); _renderer.Append(" k\n"); } break; case XColorSpace.GrayScale: if (_realizedFillColor.IsEmpty || _realizedFillColor.GS != color.GS) { _renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Undefined)); _renderer.Append(" g\n"); } break; default: break; } if (_renderer.Owner.Version >= 14 && color.ColorSpace != XColorSpace.GrayScale && (_realizedFillColor.A != color.A || _realizedNonStrokeOverPrint != overPrint)) { PdfExtGState extGState = _renderer.Owner.ExtGStateTable.GetExtGStateNonStroke(color.A, overPrint); string gs = _renderer.Resources.AddExtGState(extGState); _renderer.AppendFormatString("{0} gs\n", gs); // Must create transparency group. if (_renderer._page != null && color.A < 1) { _renderer._page.TransparencyUsed = true; } } _realizedFillColor = color; _realizedNonStrokeOverPrint = overPrint; }
/// <summary> /// Builds a monochrome shading for a form XObject of a soft mask. /// </summary> PdfShading BuildShadingForSoftMask(RadialGradientBrush brush) { // Setup shading //<< // /ShadingType 2 // /AntiAlias false // /BBox [0 0 510.236 680.315] // /ColorSpace /DeviceGray // /Coords [5 5 153.492 -86.924] // /Domain [0 1] // /Extend [true true] // /Function 18 0 R //>> PdfShading shading = Context.PdfDocument.Internals.CreateIndirectObject <PdfShading>(); #if DEBUG if (DevHelper.RenderComments) { shading.Elements.SetString("/@comment", "This is the shading function of a soft mask"); } #endif shading.Elements.SetInteger(PdfShading.Keys.ShadingType, 2); // Axial shading shading.Elements.SetBoolean(PdfShading.Keys.AntiAlias, false); // TODO: BBox full page //shading.Elements.SetValue(PdfShading.Keys.BBox, new PdfLiteral("[0 0 480 640]")); shading.Elements.SetName(PdfShading.Keys.ColorSpace, "/DeviceGray"); ////double x1 = brush.StartPoint.X; ////double y1 = brush.StartPoint.Y; ////double x2 = brush.EndPoint.X; ////double y2 = brush.EndPoint.Y; ////shading.Elements.SetValue(PdfShading.Keys.Coords, new PdfLiteral("[{0:0.####} {1:0.####} {2:0.####} {3:0.####}]", x1, y1, x2, y2)); shading.Elements.SetValue(PdfShading.Keys.Domain, new PdfLiteral("[0 1]")); shading.Elements.SetValue(PdfShading.Keys.Extend, new PdfLiteral("[true true]")); PdfColorMode colorMode = PdfColorMode.Rgb; //this.document.Options.ColorMode; PdfDictionary func; PdfDictionary function = BuildShadingFunction(brush.GradientStops, true, colorMode, true, out func); #if true shading.Elements.SetValue(PdfShading.Keys.Function, function); #else Context.PdfDocument.Internals.AddObject(function); shading.Elements.SetReference(PdfShading.Keys.Function, function); #endif return(shading); }
/// <summary> /// Checks whether a color mode and a color match. /// </summary> public static XColor EnsureColorMode(PdfColorMode colorMode, XColor color) { #if true if (colorMode == PdfColorMode.Rgb && color.ColorSpace != XColorSpace.Rgb) return XColor.FromArgb((int)(color.A * 255), color.R, color.G, color.B); if (colorMode == PdfColorMode.Cmyk && color.ColorSpace != XColorSpace.Cmyk) return XColor.FromCmyk(color.A, color.C, color.M, color.Y, color.K); return color; #else if (colorMode == PdfColorMode.Rgb && color.ColorSpace != XColorSpace.Rgb) throw new InvalidOperationException(PSSR.InappropriateColorSpace(colorMode, color.ColorSpace)); if (colorMode == PdfColorMode.Cmyk && color.ColorSpace != XColorSpace.Cmyk) throw new InvalidOperationException(PSSR.InappropriateColorSpace(colorMode, color.ColorSpace)); #endif }
/// <summary> /// Converts an XColor into a string with up to 3 decimal digits and a decimal point. /// </summary> public static string ToString(XColor color, PdfColorMode colorMode) { // If not defined let color decide if (colorMode == PdfColorMode.Undefined) { colorMode = color.ColorSpace == XColorSpace.Cmyk ? PdfColorMode.Cmyk : PdfColorMode.Rgb; } switch (colorMode) { case PdfColorMode.Cmyk: return(String.Format(CultureInfo.InvariantCulture, "{0:0.###} {1:0.###} {2:0.###} {3:0.###}", color.C, color.M, color.Y, color.K)); default: return(String.Format(CultureInfo.InvariantCulture, "{0:0.###} {1:0.###} {2:0.###}", color.R / 255.0, color.G / 255.0, color.B / 255.0)); } }
public static string InappropriateColorSpace(PdfColorMode colorMode, XColorSpace colorSpace) { string mode; switch (colorMode) { case PdfColorMode.Rgb: mode = "RGB"; break; case PdfColorMode.Cmyk: mode = "CMYK"; break; default: mode = "(undefined)"; break; } string space; switch (colorSpace) { case XColorSpace.Rgb: space = "RGB"; break; case XColorSpace.Cmyk: space = "CMYK"; break; case XColorSpace.GrayScale: space = "grayscale"; break; default: space = "(undefined)"; break; } return(String.Format("The document requires color mode {0}, but a color is defined using {1}. " + "Use only colors that match the color mode of the PDF document", mode, space)); }
private void RealizeFillColor(XColor color, bool overPrint, PdfColorMode colorMode) { color = ColorSpaceHelper.EnsureColorMode(colorMode, color); if (colorMode != PdfColorMode.Cmyk) { if (_realizedFillColor.IsEmpty || _realizedFillColor.Rgb != color.Rgb) { _renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Rgb)); _renderer.Append(" rg\n"); } } else { Debug.Assert(colorMode == PdfColorMode.Cmyk); if (_realizedFillColor.IsEmpty || !ColorSpaceHelper.IsEqualCmyk(_realizedFillColor, color)) { _renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Cmyk)); _renderer.Append(" k\n"); } } if (_renderer.Owner.Version >= 14 && (_realizedFillColor.A != color.A || _realizedNonStrokeOverPrint != overPrint)) { PdfExtGState extGState = _renderer.Owner.ExtGStateTable.GetExtGStateNonStroke(color.A, overPrint); string gs = _renderer.Resources.AddExtGState(extGState); _renderer.AppendFormatString("{0} gs\n", gs); // Must create transparency group. if (_renderer._page != null && color.A < 1) { _renderer._page.TransparencyUsed = true; } } _realizedFillColor = color; _realizedNonStrokeOverPrint = overPrint; }
PdfDictionary BuildShadingFunction3(GradientStopCollection gradients, bool softMask, PdfColorMode colorMode) { int count = gradients.Count; Debug.Assert(count >= 2); // // Build a Type 3 function with an array of n-1 Type 2 functions PdfDictionary fn1 = new PdfDictionary(); fn1.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function fn1.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn1.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray = new PdfArray(); fn1.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0.ScA) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1.ScA) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1]"); } else { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); } fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) { bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); } encode.Append("0 1"); } bounds.Append(']'); encode.Append(']'); fn1.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); fn1.Elements["/Encode"] = new PdfLiteral(encode.ToString()); return(fn1); }
/// <summary> /// Builds the shading function of the specified gradient stop collection. /// </summary> protected PdfDictionary BuildShadingFunction(GradientStopCollection gradients, bool softMask, PdfColorMode colorMode, bool reverse, out PdfDictionary funcReverse) { PdfDictionary func = new PdfDictionary(); int count = gradients.Count; Debug.Assert(count >= 2); if (CanOptimizeForTwoColors(gradients)) { funcReverse = null; // Build a Type 3 function with an array of 2 Type 2 functions func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); PdfArray fnarray = new PdfArray(); func.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0.ScA) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1.ScA) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1]"); } else { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); } fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) { bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); } encode.Append(reverse ? "1 0" : "0 1"); } bounds.Append(']'); encode.Append(']'); func.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); func.Elements["/Encode"] = new PdfLiteral(encode.ToString()); } else { #if true funcReverse = BuildShadingFunction3(gradients, softMask, colorMode); Context.PdfDocument.Internals.AddObject(funcReverse); func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); func.Elements["/Encode"] = new PdfLiteral("[1 0]"); func.Elements["/Bounds"] = new PdfLiteral("[]"); func.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray0 = new PdfArray(); fnarray0.Elements.Add(funcReverse); func.Elements["/Functions"] = fnarray0; #else // // Build a Type 3 function with an array of n-1 Type 2 functions PdfDictionary fn1 = new PdfDictionary(); func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); func.Elements["/Encode"] = new PdfLiteral("[1 0]"); func.Elements["/Bounds"] = new PdfLiteral("[]"); func.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray0 = new PdfArray(); fnarray0.Elements.Add(fn1); func.Elements["/Functions"] = fnarray0; fn1.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function fn1.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn1.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray = new PdfArray(); fn1.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0.ScA) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1.ScA) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1]"); } else { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); } fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); //this.renderer.Owner.Internals.AddObject(fn2); //fnarray.Elements.Add(fn2.Reference); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) { bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); } encode.Append("0 1"); } bounds.Append(']'); encode.Append(']'); fn1.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); fn1.Elements["/Encode"] = new PdfLiteral(encode.ToString()); #endif } return(func); }
/// <summary> /// Builds the shading function of the specified gradient stop collection. /// </summary> protected PdfDictionary BuildShadingFunction(GradientStopCollection gradients, bool softMask, PdfColorMode colorMode, bool reverse, out PdfDictionary funcReverse) { PdfDictionary func = new PdfDictionary(); int count = gradients.Count; Debug.Assert(count >= 2); if (CanOptimizeForTwoColors(gradients)) { funcReverse = null; // Build a Type 3 function with an array of 2 Type 2 functions func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); PdfArray fnarray = new PdfArray(); func.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0.ScA) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1.ScA) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1]"); } else { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); } fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); encode.Append(reverse ? "1 0" : "0 1"); } bounds.Append(']'); encode.Append(']'); func.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); func.Elements["/Encode"] = new PdfLiteral(encode.ToString()); } else { #if true funcReverse = BuildShadingFunction3(gradients, softMask, colorMode); Context.PdfDocument.Internals.AddObject(funcReverse); func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); func.Elements["/Encode"] = new PdfLiteral("[1 0]"); func.Elements["/Bounds"] = new PdfLiteral("[]"); func.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray0 = new PdfArray(); fnarray0.Elements.Add(funcReverse); func.Elements["/Functions"] = fnarray0; #else // // Build a Type 3 function with an array of n-1 Type 2 functions PdfDictionary fn1 = new PdfDictionary(); func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); func.Elements["/Encode"] = new PdfLiteral("[1 0]"); func.Elements["/Bounds"] = new PdfLiteral("[]"); func.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray0 = new PdfArray(); fnarray0.Elements.Add(fn1); func.Elements["/Functions"] = fnarray0; fn1.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function fn1.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn1.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray = new PdfArray(); fn1.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0.ScA) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1.ScA) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1]"); } else { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); } fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); //this.renderer.Owner.Internals.AddObject(fn2); //fnarray.Elements.Add(fn2.Reference); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); encode.Append("0 1"); } bounds.Append(']'); encode.Append(']'); fn1.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); fn1.Elements["/Encode"] = new PdfLiteral(encode.ToString()); #endif } return func; }
PdfShadingPattern BuildPattern(RadialGradientBrush brush, XRect boundingBox, XMatrix transform) { //<< // /BBox [0 0 600 760] // /Length 123 // /Matrix [0.75 0 0 -0.75 0 480] // /PaintType 1 // /PatternType 1 // /Resources // << // /ColorSpace // << // /CS0 12 0 R // /CS1 12 0 R // >> // /ExtGState // << // /GS0 10 0 R // /GS1 16 0 R // >> // /Shading // << // /Sh0 15 0 R // >> // >> // /TilingType 3 // /Type /Pattern // /XStep 600 // /YStep 1520 //>> //stream // /CS0 cs 1 0 0 scn // 1 i // /GS0 gs // 0 0 600 759.999 re // f // q // 0 0 600 760 re // W n // q // 0 g // /GS1 gs // 1 0 0 0.5 0 0 cm // BX /Sh0 sh EX Q // Q //endstream XRect bbox = new XRect(-600, -700, 1200, 1520); // HACK XMatrix matrix = transform; //matrix.Prepend(brush.Transform.Matrix); double xStep = 600; double yStep = 1520; // HACK PdfShadingPattern pattern = Context.PdfDocument.Internals.CreateIndirectObject <PdfShadingPattern>(); pattern.Elements.SetInteger(PdfTilingPattern.Keys.PatternType, 1); // Tiling pattern.Elements.SetInteger(PdfTilingPattern.Keys.PaintType, 1); // Color pattern.Elements.SetInteger(PdfTilingPattern.Keys.TilingType, 3); // Constant spacing and faster tiling pattern.Elements.SetMatrix(PdfTilingPattern.Keys.Matrix, matrix); pattern.Elements.SetRectangle(PdfTilingPattern.Keys.BBox, new PdfRectangle(bbox)); pattern.Elements.SetReal(PdfTilingPattern.Keys.XStep, xStep); pattern.Elements.SetReal(PdfTilingPattern.Keys.YStep, yStep); double dx = 2 * brush.RadiusX; double dy = 2 * brush.RadiusY; XRect brushBox = new XRect(brush.Center.X - brush.RadiusX, brush.Center.Y - brush.RadiusY, dx, dy); Debug.Assert(dx * dy > 0, "Radius is 0."); double scaleX, scaleY; if (dx > dy) { scaleX = 1; scaleY = dy / dx; } else { scaleX = dx / dy; scaleY = 1; } PdfColorMode colorMode = PdfColorMode.Rgb; PdfDictionary funcReflected; PdfDictionary funcRegular = BuildShadingFunction(brush.GradientStops, false, colorMode, true, out funcReflected); if (brush.SpreadMethod != SpreadMethod.Pad) { if (CanOptimizeForTwoColors(brush.GradientStops)) { PdfDictionary dummy; funcReflected = BuildShadingFunction(brush.GradientStops, false, colorMode, false, out dummy); } else { Context.PdfDocument.Internals.AddObject(funcRegular); } } //PdfShading shading = BuildShading(brush, scaleX, scaleY); int shadingCount = 1; if (brush.SpreadMethod != SpreadMethod.Pad) { // TODO: Calculate number of required shadings shadingCount = Convert.ToInt32(Math.Max(boundingBox.Width / (2 * brush.RadiusX), boundingBox.Height / (2 * brush.RadiusY)) + 1); // HACK: Rule of thumb, better than nothing shadingCount *= 2; } PdfShading[] shadings = new PdfShading[shadingCount]; // Create the shadings for (int idx = 0; idx < shadingCount; idx++) { PdfShading shading = BuildShading2(brush, scaleX, scaleY, idx, brush.SpreadMethod == SpreadMethod.Reflect && idx % 2 == 1 ? funcReflected : funcRegular); shadings[idx] = shading; } PdfContentWriter writer = new PdfContentWriter(Context, pattern); writer.BeginContentRaw(); // Fill background (even if spread method is not pad) writer.WriteLiteral("q /DeviceRGB cs\n"); //writer.WriteLiteral(PdfEncoders.ToString(clr0, colorMode) + " rg 1 i\n"); writer.WriteLiteral(PdfEncoders.ToString(brush.GradientStops[brush.GradientStops.Count - 1].Color, PdfColorMode.Rgb) + " rg 1 i\n"); writer.WriteLiteral("1 i\n"); PdfExtGState gs = Context.PdfDocument.Internals.CreateIndirectObject <PdfExtGState>(); gs.SetDefault1(); writer.WriteGraphicsState(gs); writer.WriteLiteral("0 0 600 760 re f\n"); XMatrix mat = brush.Transform.Matrix; if (!mat.IsIdentity) { writer.WriteMatrix(mat); } // Just work: silly loop thru shadings for (int idx = shadingCount - 1; idx >= 0; idx--) { writer.WriteLiteral("q 0 0 600 760 re W n\n"); writer.WriteLiteral("q 0 g\n"); gs = Context.PdfDocument.Internals.CreateIndirectObject <PdfExtGState>(); gs.SetDefault2(); writer.WriteGraphicsState(gs); XMatrix transformation = new XMatrix(scaleX, 0, 0, scaleY, 0, 0); writer.WriteMatrix(transformation); string shName = writer.Resources.AddShading(shadings[idx]); writer.WriteLiteral("BX " + shName + " sh EX Q Q\n"); } writer.WriteLiteral("Q\n"); writer.EndContent(); return(pattern); }
/// <summary> /// Setups the shading from the specified brush. /// </summary> public void SetupFromBrush(XLinearGradientBrush brush) { if (brush == null) { throw new ArgumentNullException("brush"); } PdfColorMode colorMode = this.document.Options.ColorMode; XColor color1 = ColorSpaceHelper.EnsureColorMode(colorMode, brush.color1); XColor color2 = ColorSpaceHelper.EnsureColorMode(colorMode, brush.color2); PdfDictionary function = new PdfDictionary(); Elements[Keys.ShadingType] = new PdfInteger(2); if (colorMode != PdfColorMode.Cmyk) { Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB"); } else { Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK"); } double x1 = 0, y1 = 0, x2 = 0, y2 = 0; if (brush.useRect) { switch (brush.linearGradientMode) { case XLinearGradientMode.Horizontal: x1 = brush.rect.x; y1 = brush.rect.y; x2 = brush.rect.x + brush.rect.width; y2 = brush.rect.y; break; case XLinearGradientMode.Vertical: x1 = brush.rect.x; y1 = brush.rect.y; x2 = brush.rect.x; y2 = brush.rect.y + brush.rect.height; break; case XLinearGradientMode.ForwardDiagonal: x1 = brush.rect.x; y1 = brush.rect.y; x2 = brush.rect.x + brush.rect.width; y2 = brush.rect.y + brush.rect.height; break; case XLinearGradientMode.BackwardDiagonal: x1 = brush.rect.x + brush.rect.width; y1 = brush.rect.y; x2 = brush.rect.x; y2 = brush.rect.y + brush.rect.height; break; } } else { x1 = brush.point1.x; y1 = brush.point1.y; x2 = brush.point2.x; y2 = brush.point2.y; } Elements[Keys.Coords] = new PdfLiteral("[{0:0.###} {1:0.###} {2:0.###} {3:0.###}]", x1, y1, x2, y2); //Elements[Keys.Background] = new PdfRawItem("[0 1 1]"); //Elements[Keys.Domain] = Elements[Keys.Function] = function; //Elements[Keys.Extend] = new PdfRawItem("[true true]"); string clr1 = "[" + PdfEncoders.ToString(color1, colorMode) + "]"; string clr2 = "[" + PdfEncoders.ToString(color2, colorMode) + "]"; function.Elements["/FunctionType"] = new PdfInteger(2); function.Elements["/C0"] = new PdfLiteral(clr1); function.Elements["/C1"] = new PdfLiteral(clr2); function.Elements["/Domain"] = new PdfLiteral("[0 1]"); function.Elements["/N"] = new PdfInteger(1); }
public void RealizePen(XPen pen, PdfColorMode colorMode) { XColor color = pen.Color; color = ColorSpaceHelper.EnsureColorMode(colorMode, color); if (realizedLineWith != pen.width) { renderer.AppendFormat("{0:0.###} w\n", pen.width); realizedLineWith = pen.width; } if (realizedLineCap != (int)pen.lineCap) { renderer.AppendFormat("{0} J\n", (int)pen.lineCap); realizedLineCap = (int)pen.lineCap; } if (realizedLineJoin != (int)pen.lineJoin) { renderer.AppendFormat("{0} j\n", (int)pen.lineJoin); realizedLineJoin = (int)pen.lineJoin; } if (realizedLineCap == (int)XLineJoin.Miter) { if (realizedMiterLimit != (int)pen.miterLimit && (int)pen.miterLimit != 0) { renderer.AppendFormat("{0} M\n", (int)pen.miterLimit); realizedMiterLimit = (int)pen.miterLimit; } } if (realizedDashStyle != pen.dashStyle || pen.dashStyle == XDashStyle.Custom) { double dot = pen.Width; double dash = 3 * dot; // Line width 0 is not recommended but valid XDashStyle dashStyle = pen.DashStyle; if (dot == 0) { dashStyle = XDashStyle.Solid; } switch (dashStyle) { case XDashStyle.Solid: renderer.Append("[]0 d\n"); break; case XDashStyle.Dash: renderer.AppendFormat("[{0:0.##} {1:0.##}]0 d\n", dash, dot); break; case XDashStyle.Dot: renderer.AppendFormat("[{0:0.##}]0 d\n", dot); break; case XDashStyle.DashDot: renderer.AppendFormat("[{0:0.##} {1:0.##} {1:0.##} {1:0.##}]0 d\n", dash, dot); break; case XDashStyle.DashDotDot: renderer.AppendFormat("[{0:0.##} {1:0.##} {1:0.##} {1:0.##} {1:0.##} {1:0.##}]0 d\n", dash, dot); break; case XDashStyle.Custom: { StringBuilder pdf = new StringBuilder("[", 256); int len = pen.dashPattern == null ? 0 : pen.dashPattern.Length; for (int idx = 0; idx < len; idx++) { if (idx > 0) { pdf.Append(' '); } pdf.Append(PdfEncoders.ToString(pen.dashPattern[idx] * pen.width)); } // Make an even number of values look like in GDI+ if (len > 0 && len % 2 == 1) { pdf.Append(' '); pdf.Append(PdfEncoders.ToString(0.2 * pen.width)); } pdf.AppendFormat(CultureInfo.InvariantCulture, "]{0:0.###} d\n", pen.dashOffset * pen.width); string pattern = pdf.ToString(); // BUG: [email protected] reported a realizing problem // HACK: I romove the if clause //if (this.realizedDashPattern != pattern) { realizedDashPattern = pattern; renderer.Append(pattern); } } break; } realizedDashStyle = dashStyle; } if (colorMode != PdfColorMode.Cmyk) { if (realizedStrokeColor.Rgb != color.Rgb) { renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Rgb)); renderer.Append(" RG\n"); } } else { if (!ColorSpaceHelper.IsEqualCmyk(realizedStrokeColor, color)) { renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Cmyk)); renderer.Append(" K\n"); } } if (renderer.Owner.Version >= 14 && realizedStrokeColor.A != color.A) { PdfExtGState extGState = renderer.Owner.ExtGStateTable.GetExtGStateStroke(color.A); string gs = renderer.Resources.AddExtGState(extGState); renderer.AppendFormat("{0} gs\n", gs); // Must create transparany group if (renderer.page != null && color.A < 1) { renderer.page.transparencyUsed = true; } } realizedStrokeColor = color; }
public void RealizePen(XPen pen, PdfColorMode colorMode) { const string frmt2 = Config.SignificantFigures2; const string format = Config.SignificantFigures3; XColor color = pen.Color; bool overPrint = pen.Overprint; color = ColorSpaceHelper.EnsureColorMode(colorMode, color); if (_realizedLineWith != pen._width) { _renderer.AppendFormatArgs("{0:" + format + "} w\n", pen._width); _realizedLineWith = pen._width; } if (_realizedLineCap != (int)pen._lineCap) { _renderer.AppendFormatArgs("{0} J\n", (int)pen._lineCap); _realizedLineCap = (int)pen._lineCap; } if (_realizedLineJoin != (int)pen._lineJoin) { _renderer.AppendFormatArgs("{0} j\n", (int)pen._lineJoin); _realizedLineJoin = (int)pen._lineJoin; } if (_realizedLineCap == (int)XLineJoin.Miter) { if (_realizedMiterLimit != (int)pen._miterLimit && (int)pen._miterLimit != 0) { _renderer.AppendFormatInt("{0} M\n", (int)pen._miterLimit); _realizedMiterLimit = (int)pen._miterLimit; } } if (_realizedDashStyle != pen._dashStyle || pen._dashStyle == XDashStyle.Custom) { double dot = pen.Width; double dash = 3 * dot; // Line width 0 is not recommended but valid. XDashStyle dashStyle = pen.DashStyle; if (dot == 0) { dashStyle = XDashStyle.Solid; } switch (dashStyle) { case XDashStyle.Solid: _renderer.Append("[]0 d\n"); break; case XDashStyle.Dash: _renderer.AppendFormatArgs("[{0:" + frmt2 + "} {1:" + frmt2 + "}]0 d\n", dash, dot); break; case XDashStyle.Dot: _renderer.AppendFormatArgs("[{0:" + frmt2 + "}]0 d\n", dot); break; case XDashStyle.DashDot: _renderer.AppendFormatArgs("[{0:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "}]0 d\n", dash, dot); break; case XDashStyle.DashDotDot: _renderer.AppendFormatArgs("[{0:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "}]0 d\n", dash, dot); break; case XDashStyle.Custom: { StringBuilder pdf = new StringBuilder("[", 256); int len = pen._dashPattern == null ? 0 : pen._dashPattern.Length; for (int idx = 0; idx < len; idx++) { if (idx > 0) { pdf.Append(' '); } pdf.Append(PdfEncoders.ToString(pen._dashPattern[idx] * pen._width)); } // Make an even number of values look like in GDI+ if (len > 0 && len % 2 == 1) { pdf.Append(' '); pdf.Append(PdfEncoders.ToString(0.2 * pen._width)); } pdf.AppendFormat(CultureInfo.InvariantCulture, "]{0:" + format + "} d\n", pen._dashOffset * pen._width); string pattern = pdf.ToString(); // BUG: [email protected] reported a realizing problem // HACK: I remove the if clause //if (_realizedDashPattern != pattern) { _realizedDashPattern = pattern; _renderer.Append(pattern); } } break; } _realizedDashStyle = dashStyle; } if (colorMode != PdfColorMode.Cmyk) { if (_realizedStrokeColor.Rgb != color.Rgb) { _renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Rgb)); _renderer.Append(" RG\n"); } } else { if (!ColorSpaceHelper.IsEqualCmyk(_realizedStrokeColor, color)) { _renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Cmyk)); _renderer.Append(" K\n"); } } if (_renderer.Owner.Version >= 14 && (_realizedStrokeColor.A != color.A || _realizedStrokeOverPrint != overPrint)) { PdfExtGState extGState = _renderer.Owner.ExtGStateTable.GetExtGStateStroke(color.A, overPrint); string gs = _renderer.Resources.AddExtGState(extGState); _renderer.AppendFormatString("{0} gs\n", gs); // Must create transparency group. if (_renderer._page != null && color.A < 1) { _renderer._page.TransparencyUsed = true; } } _realizedStrokeColor = color; _realizedStrokeOverPrint = overPrint; }
/// <summary> /// Converts an XColor into a string with up to 3 decimal digits and a decimal point. /// </summary> public static string ToString(XColor color, PdfColorMode colorMode) { // If not defined let color decide if (colorMode == PdfColorMode.Undefined) { if (color.ColorSpace == XColorSpace.Cmyk) colorMode = PdfColorMode.Cmyk; else colorMode = PdfColorMode.Rgb; } switch (colorMode) { case PdfColorMode.Cmyk: return String.Format(CultureInfo.InvariantCulture, "{0:0.###} {1:0.###} {2:0.###} {3:0.###}", color.C, color.M, color.Y, color.K); default: return String.Format(CultureInfo.InvariantCulture, "{0:0.###} {1:0.###} {2:0.###}", color.R / 255.0, color.G / 255.0, color.B / 255.0); } }
public void RealizeBrush(XBrush brush, PdfColorMode colorMode, int renderingMode, double fontEmSize) { // Rendering mode 2 is used for bold simulation. // Reference: TABLE 5.3 Text rendering modes / Page 402 XSolidBrush solidBrush = brush as XSolidBrush; if (solidBrush != null) { XColor color = solidBrush.Color; bool overPrint = solidBrush.Overprint; if (renderingMode == 0) { RealizeFillColor(color, overPrint, colorMode); } else if (renderingMode == 2) { // Come here in case of bold simulation. RealizeFillColor(color, false, colorMode); //color = XColors.Green; RealizePen(new XPen(color, fontEmSize * Const.BoldEmphasis), colorMode); } else throw new InvalidOperationException("Only rendering modes 0 and 2 are currently supported."); } else { if (renderingMode != 0) throw new InvalidOperationException("Rendering modes other than 0 can only be used with solid color brushes."); XLinearGradientBrush gradientBrush = brush as XLinearGradientBrush; if (gradientBrush != null) { Debug.Assert(UnrealizedCtm.IsIdentity, "Must realize ctm first."); XMatrix matrix = _renderer.DefaultViewMatrix; matrix.Prepend(EffectiveCtm); PdfShadingPattern pattern = new PdfShadingPattern(_renderer.Owner); pattern.SetupFromBrush(gradientBrush, matrix, _renderer); string name = _renderer.Resources.AddPattern(pattern); _renderer.AppendFormatString("/Pattern cs\n", name); _renderer.AppendFormatString("{0} scn\n", name); // Invalidate fill color. _realizedFillColor = XColor.Empty; } } }
private void RealizeFillColor(XColor color, bool overPrint, PdfColorMode colorMode) { color = ColorSpaceHelper.EnsureColorMode(colorMode, color); if (colorMode != PdfColorMode.Cmyk) { if (_realizedFillColor.IsEmpty || _realizedFillColor.Rgb != color.Rgb) { _renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Rgb)); _renderer.Append(" rg\n"); } } else { Debug.Assert(colorMode == PdfColorMode.Cmyk); if (_realizedFillColor.IsEmpty || !ColorSpaceHelper.IsEqualCmyk(_realizedFillColor, color)) { _renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Cmyk)); _renderer.Append(" k\n"); } } if (_renderer.Owner.Version >= 14 && (_realizedFillColor.A != color.A || _realizedNonStrokeOverPrint != overPrint)) { PdfExtGState extGState = _renderer.Owner.ExtGStateTable.GetExtGStateNonStroke(color.A, overPrint); string gs = _renderer.Resources.AddExtGState(extGState); _renderer.AppendFormatString("{0} gs\n", gs); // Must create transparency group. if (_renderer._page != null && color.A < 1) _renderer._page.TransparencyUsed = true; } _realizedFillColor = color; _realizedNonStrokeOverPrint = overPrint; }
//void RealizeImageBrush(ImageBrush brush, XForm xform) //{ //} //void RealizeVisualBrush(VisualBrush brush, XForm xform) //{ //} /// <summary> /// Builds the shading function of the specified gradient stop collection. /// </summary> PdfDictionary BuildShadingFunction(GradientStopCollection gradients, PdfColorMode colorMode) { bool softMask = this.writer.renderMode == RenderMode.SoftMask; PdfDictionary func = new PdfDictionary(); int count = gradients.Count; Debug.Assert(count >= 2); if (count == 2) { // Build one Type 2 function func.Elements["/FunctionType"] = new PdfInteger(2); // Type 2 - Exponential Interpolation Function Color clr0 = gradients[0].Color; Color clr1 = gradients[1].Color; if (softMask) { clr0 = Utils.AlphaToGray(clr0); clr1 = Utils.AlphaToGray(clr1); } func.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); func.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); func.Elements["/Domain"] = new PdfLiteral("[0 1]"); func.Elements["/N"] = new PdfInteger(1); // be linear } else { // Build a Type 3 function with an array of n-1 Type 2 functions func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); PdfArray fnarray = new PdfArray(); func.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { clr0 = Utils.AlphaToGray(clr0); clr1 = Utils.AlphaToGray(clr1); } fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); //this.renderer.Owner.Internals.AddObject(fn2); //fnarray.Elements.Add(fn2.Reference); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); encode.Append("0 1"); } bounds.Append(']'); //encode.Append(" 0 1"); encode.Append(']'); func.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); func.Elements["/Encode"] = new PdfLiteral(encode.ToString()); } return func; }
//[Obsolete] // void RealizeLinearGradientBrush(LinearGradientBrush brush, XForm xform) // { // XMatrix matrix = this.currentTransform; // PdfShadingPattern pattern = new PdfShadingPattern(this.writer.Owner); // pattern.Elements[PdfShadingPattern.Keys.PatternType] = new PdfInteger(2); // shading pattern // // Setup shading // PdfShading shading = new PdfShading(this.writer.Owner); // PdfColorMode colorMode = PdfColorMode.Rgb; //this.document.Options.ColorMode; // PdfDictionary function = BuildShadingFunction(brush.GradientStops, colorMode); // function.Elements.SetString("/@", "This is the shading function of a LinearGradientBrush"); // shading.Elements[PdfShading.Keys.Function] = function; // shading.Elements[PdfShading.Keys.ShadingType] = new PdfInteger(2); // Axial shading // //if (colorMode != PdfColorMode.Cmyk) // shading.Elements[PdfShading.Keys.ColorSpace] = new PdfName("/DeviceRGB"); // //else // //shading.Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK"); // //double x1 = 0, y1 = 0, x2 = 0, y2 = 0; // double x1 = brush.StartPoint.X; // double y1 = brush.StartPoint.Y; // double x2 = brush.EndPoint.X; // double y2 = brush.EndPoint.Y; // shading.Elements[PdfShading.Keys.Coords] = new PdfLiteral("[{0:0.###} {1:0.###} {2:0.###} {3:0.###}]", x1, y1, x2, y2); // // old: Elements[Keys.Background] = new PdfRawItem("[0 1 1]"); // // old: Elements[Keys.Domain] = // shading.Elements[PdfShading.Keys.Extend] = new PdfLiteral("[true true]"); // // Setup pattern // pattern.Elements[PdfShadingPattern.Keys.Shading] = shading; // pattern.Elements[PdfShadingPattern.Keys.Matrix] = PdfLiteral.FromMatrix(matrix); // new PdfLiteral("[" + PdfEncoders.ToString(matrix) + "]"); // string name = this.writer.Resources.AddPattern(pattern); // this.writer.WriteLiteral("/Pattern cs\n", name); // this.writer.WriteLiteral("{0} scn\n", name); // double alpha = brush.Opacity * brush.GradientStops.GetAverageAlpha(); // if (alpha < 1 && this.writer.renderMode == RenderMode.Default) // { //#if true // PdfExtGState extGState = this.writer.Owner.ExtGStateTable.GetExtGStateNonStroke(alpha); // string gs = this.writer.Resources.AddExtGState(extGState); // this.writer.WriteLiteral("{0} gs\n", gs); //#else //#if true // if (xform == null) // { // PdfExtGState extGState = this.writer.Owner.ExtGStateTable.GetExtGStateNonStroke(alpha); // string gs = this.writer.Resources.AddExtGState(extGState); // this.writer.WriteGraphicState(extGState); // } // else // { // //PdfFormXObject pdfForm = this.writer.Owner.FormTable.GetForm(form); // PdfFormXObject pdfForm = xform.pdfForm; // pdfForm.Elements.SetString("/@", "This is the Form XObject of the soft mask"); // string formName = this.writer.Resources.AddForm(pdfForm); // PdfTransparencyGroupAttributes tgAttributes = new PdfTransparencyGroupAttributes(this.writer.Owner); // //this.writer.Owner.Internals.AddObject(tgAttributes); // tgAttributes.Elements.SetName(PdfTransparencyGroupAttributes.Keys.CS, "/DeviceRGB"); // // Set reference to transparency group attributes // pdfForm.Elements.SetObject(PdfFormXObject.Keys.Group, tgAttributes); // pdfForm.Elements[PdfFormXObject.Keys.Matrix] = new PdfLiteral("[1.001 0 0 1.001 0.001 0.001]"); // PdfSoftMask softmask = new PdfSoftMask(this.writer.Owner); // this.writer.Owner.Internals.AddObject(softmask); // softmask.Elements.SetString("/@", "This is the soft mask"); // softmask.Elements.SetName(PdfSoftMask.Keys.S, "/Luminosity"); // softmask.Elements.SetReference(PdfSoftMask.Keys.G, pdfForm); // //pdfForm.Elements.SetName(PdfFormXObject.Keys.Type, "Group"); // //pdfForm.Elements.SetName(PdfFormXObject.Keys.ss.Ss.Type, "Group"); // PdfExtGState extGState = new PdfExtGState(this.writer.Owner); // this.writer.Owner.Internals.AddObject(extGState); // extGState.Elements.SetReference(PdfExtGState.Keys.SMask, softmask); // this.writer.WriteGraphicState(extGState); // } //#else // XForm form = new XForm(this.writer.Owner, 220, 140); // XGraphics formGfx = XGraphics.FromForm(form); // // draw something // //XSolidBrush xbrush = new XSolidBrush(XColor.FromArgb(128, 128, 128)); // XLinearGradientBrush xbrush = new XLinearGradientBrush(new XPoint(0, 0), new XPoint(220,0), XColors.White, XColors.Black); // formGfx.DrawRectangle(xbrush, -10000, -10000, 20000, 20000); // //formGfx.DrawString("Text, Graphics, Images, and Forms", new XFont("Verdana", 10, XFontStyle.Regular), XBrushes.Navy, 3, 0, XStringFormat.TopLeft); // formGfx.Dispose(); // // Close form // form.Finish(); // PdfFormXObject pdfForm = this.writer.Owner.FormTable.GetForm(form); // string formName = this.writer.Resources.AddForm(pdfForm); // //double x = 20, y = 20; // //double cx = 1; // //double cy = 1; // //this.writer.AppendFormat("q {2:0.###} 0 0 -{3:0.###} {0:0.###} {4:0.###} cm 100 Tz {5} Do Q\n", // // x, y, cx, cy, y + 0, formName); // //this.writer.AppendFormat("q {2:0.###} 0 0 -{3:0.###} {0:0.###} {4:0.###} cm 100 Tz {5} Do Q\n", // // x, y, cx, cy, y + 220/1.5, formName); // PdfTransparencyGroupAttributes tgAttributes = new PdfTransparencyGroupAttributes(this.writer.Owner); // this.writer.Owner.Internals.AddObject(tgAttributes); // tgAttributes.Elements.SetName(PdfTransparencyGroupAttributes.Keys.CS, "/DeviceRGB"); // // Set reference to transparency group attributes // pdfForm.Elements.SetReference(PdfFormXObject.Keys.Group, tgAttributes); // PdfSoftMask softmask = new PdfSoftMask(this.writer.Owner); // this.writer.Owner.Internals.AddObject(softmask); // softmask.Elements.SetName(PdfSoftMask.Keys.S, "/Luminosity"); // softmask.Elements.SetReference(PdfSoftMask.Keys.G, pdfForm); // //pdfForm.Elements.SetName(PdfFormXObject.Keys.Type, "Group"); // //pdfForm.Elements.SetName(PdfFormXObject.Keys.ss.Ss.Type, "Group"); // PdfExtGState extGState = new PdfExtGState(this.writer.Owner); // this.writer.Owner.Internals.AddObject(extGState); // extGState.Elements.SetReference(PdfExtGState.Keys.SMask, softmask); // this.writer.WriteGraphicState(extGState); //#endif //#endif // } // } // [Obsolete] // void RealizeRadialGradientBrush(RadialGradientBrush brush, XForm xform) // { // XMatrix matrix = new XMatrix(); // this.renderer.defaultViewMatrix; // //matrix.MultiplyPrepend(this.Transform); // matrix = this.currentTransform; // //matrix.MultiplyPrepend(XMatrix.CreateScaling(1.3, 1)); // PdfShadingPattern pattern = new PdfShadingPattern(this.writer.Owner); // pattern.Elements[PdfShadingPattern.Keys.PatternType] = new PdfInteger(2); // shading pattern // // Setup shading // PdfShading shading = new PdfShading(this.writer.Owner); // PdfColorMode colorMode = PdfColorMode.Rgb; //this.document.Options.ColorMode; // PdfDictionary function = BuildShadingFunction(brush.GradientStops, colorMode); // shading.Elements[PdfShading.Keys.ShadingType] = new PdfInteger(3); // Radial shading // //if (colorMode != PdfColorMode.Cmyk) // shading.Elements[PdfShading.Keys.ColorSpace] = new PdfName("/DeviceRGB"); // //else // //shading.Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK"); // double x0 = brush.GradientOrigin.X; // double y0 = brush.GradientOrigin.Y; // double r0 = 0; // double x1 = brush.Center.X; // double y1 = brush.Center.Y; // double r1 = brush.RadiusX; // shading.Elements[PdfShading.Keys.Coords] = // new PdfLiteral("[{0:0.###} {1:0.###} {2:0.###} {3:0.###} {4:0.###} {5:0.###}]", x0, y0, r0, x1, y1, r1); // // old: Elements[Keys.Background] = new PdfRawItem("[0 1 1]"); // // old: Elements[Keys.Domain] = // shading.Elements[PdfShading.Keys.Function] = function; // shading.Elements[PdfShading.Keys.Extend] = new PdfLiteral("[true true]"); // // Setup pattern // pattern.Elements[PdfShadingPattern.Keys.Shading] = shading; // pattern.Elements[PdfShadingPattern.Keys.Matrix] = PdfLiteral.FromMatrix(matrix); // new PdfLiteral("[" + PdfEncoders.ToString(matrix) + "]"); // string name = this.writer.Resources.AddPattern(pattern); // this.writer.WriteLiteral("/Pattern cs\n", name); // this.writer.WriteLiteral("{0} scn\n", name); // double alpha = brush.Opacity * brush.GradientStops.GetAverageAlpha(); // if (alpha < 1) // { //#if true // PdfExtGState extGState = this.writer.Owner.ExtGStateTable.GetExtGStateNonStroke(alpha); // string gs = this.writer.Resources.AddExtGState(extGState); // this.writer.WriteLiteral("{0} gs\n", gs); //#else // if (xform == null) // { // PdfExtGState extGState = this.writer.Owner.ExtGStateTable.GetExtGStateNonStroke(alpha); // string gs = this.writer.Resources.AddExtGState(extGState); // this.writer.WriteGraphicState(extGState); // } // else // { // //PdfFormXObject pdfForm = this.writer.Owner.FormTable.GetForm(form); // PdfFormXObject pdfForm = xform.pdfForm; // pdfForm.Elements.SetString("/@", "This is the Form XObject of the soft mask"); // string formName = this.writer.Resources.AddForm(pdfForm); // PdfTransparencyGroupAttributes tgAttributes = new PdfTransparencyGroupAttributes(this.writer.Owner); // //this.writer.Owner.Internals.AddObject(tgAttributes); // tgAttributes.Elements.SetName(PdfTransparencyGroupAttributes.Keys.CS, "/DeviceRGB"); // // Set reference to transparency group attributes // pdfForm.Elements.SetObject(PdfFormXObject.Keys.Group, tgAttributes); // pdfForm.Elements[PdfFormXObject.Keys.Matrix] = new PdfLiteral("[1.001 0 0 1.001 0.001 0.001]"); // PdfSoftMask softmask = new PdfSoftMask(this.writer.Owner); // this.writer.Owner.Internals.AddObject(softmask); // softmask.Elements.SetString("/@", "This is the soft mask"); // softmask.Elements.SetName(PdfSoftMask.Keys.S, "/Luminosity"); // softmask.Elements.SetReference(PdfSoftMask.Keys.G, pdfForm); // //pdfForm.Elements.SetName(PdfFormXObject.Keys.Type, "Group"); // //pdfForm.Elements.SetName(PdfFormXObject.Keys.ss.Ss.Type, "Group"); // PdfExtGState extGState = new PdfExtGState(this.writer.Owner); // this.writer.Owner.Internals.AddObject(extGState); // extGState.Elements.SetReference(PdfExtGState.Keys.SMask, softmask); // this.writer.WriteGraphicState(extGState); // } //#endif // } // } //void RealizeImageBrush(ImageBrush brush, XForm xform) //{ //} //void RealizeVisualBrush(VisualBrush brush, XForm xform) //{ //} /// <summary> /// Builds the shading function of the specified gradient stop collection. /// </summary> PdfDictionary BuildShadingFunction(GradientStopCollection gradients, PdfColorMode colorMode) { bool softMask = this.writer.renderMode == RenderMode.SoftMask; PdfDictionary func = new PdfDictionary(); int count = gradients.Count; Debug.Assert(count >= 2); if (count == 2) { // Build one Type 2 function func.Elements["/FunctionType"] = new PdfInteger(2); // Type 2 - Exponential Interpolation Function Color clr0 = gradients[0].Color; Color clr1 = gradients[1].Color; if (softMask) { clr0 = Utils.AlphaToGray(clr0); clr1 = Utils.AlphaToGray(clr1); } func.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); func.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); func.Elements["/Domain"] = new PdfLiteral("[0 1]"); func.Elements["/N"] = new PdfInteger(1); // be linear } else { // Build a Type 3 function with an array of n-1 Type 2 functions func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); PdfArray fnarray = new PdfArray(); func.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { clr0 = Utils.AlphaToGray(clr0); clr1 = Utils.AlphaToGray(clr1); } fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); //this.renderer.Owner.Internals.AddObject(fn2); //fnarray.Elements.Add(fn2.Reference); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) { bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); } encode.Append("0 1"); } bounds.Append(']'); //encode.Append(" 0 1"); encode.Append(']'); func.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); func.Elements["/Encode"] = new PdfLiteral(encode.ToString()); } return(func); }
public void RealizePen(XPen pen, PdfColorMode colorMode) { XColor color = pen.Color; color = ColorSpaceHelper.EnsureColorMode(colorMode, color); if (this.realizedLineWith != pen.width) { this.renderer.AppendFormat("{0:0.###} w\n", pen.width); this.realizedLineWith = pen.width; } if (this.realizedLineCap != (int)pen.lineCap) { this.renderer.AppendFormat("{0} J\n", (int)pen.lineCap); this.realizedLineCap = (int)pen.lineCap; } if (this.realizedLineJoin != (int)pen.lineJoin) { this.renderer.AppendFormat("{0} j\n", (int)pen.lineJoin); this.realizedLineJoin = (int)pen.lineJoin; } if (this.realizedLineCap == (int)XLineJoin.Miter) { if (this.realizedMiterLimit != (int)pen.miterLimit && (int)pen.miterLimit != 0) { this.renderer.AppendFormat("{0} M\n", (int)pen.miterLimit); this.realizedMiterLimit = (int)pen.miterLimit; } } if (this.realizedDashStyle != pen.dashStyle || pen.dashStyle == XDashStyle.Custom) { double dot = pen.Width; double dash = 3 * dot; // Line width 0 is not recommended but valid XDashStyle dashStyle = pen.DashStyle; if (dot == 0) dashStyle = XDashStyle.Solid; switch (dashStyle) { case XDashStyle.Solid: this.renderer.Append("[]0 d\n"); break; case XDashStyle.Dash: this.renderer.AppendFormat("[{0:0.##} {1:0.##}]0 d\n", dash, dot); break; case XDashStyle.Dot: this.renderer.AppendFormat("[{0:0.##}]0 d\n", dot); break; case XDashStyle.DashDot: this.renderer.AppendFormat("[{0:0.##} {1:0.##} {1:0.##} {1:0.##}]0 d\n", dash, dot); break; case XDashStyle.DashDotDot: this.renderer.AppendFormat("[{0:0.##} {1:0.##} {1:0.##} {1:0.##} {1:0.##} {1:0.##}]0 d\n", dash, dot); break; case XDashStyle.Custom: { StringBuilder pdf = new StringBuilder("[", 256); int len = pen.dashPattern == null ? 0 : pen.dashPattern.Length; for (int idx = 0; idx < len; idx++) { if (idx > 0) pdf.Append(' '); pdf.Append(PdfEncoders.ToString(pen.dashPattern[idx] * pen.width)); } // Make an even number of values look like in GDI+ if (len > 0 && len % 2 == 1) { pdf.Append(' '); pdf.Append(PdfEncoders.ToString(0.2 * pen.width)); } pdf.AppendFormat(CultureInfo.InvariantCulture, "]{0:0.###} d\n", pen.dashOffset * pen.width); string pattern = pdf.ToString(); // BUG: [email protected] reported a realizing problem // HACK: I romove the if clause //if (this.realizedDashPattern != pattern) { this.realizedDashPattern = pattern; this.renderer.Append(pattern); } } break; } this.realizedDashStyle = dashStyle; } if (colorMode != PdfColorMode.Cmyk) { if (this.realizedStrokeColor.Rgb != color.Rgb) { this.renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Rgb)); this.renderer.Append(" RG\n"); } } else { if (!ColorSpaceHelper.IsEqualCmyk(this.realizedStrokeColor, color)) { this.renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Cmyk)); this.renderer.Append(" K\n"); } } if (this.renderer.Owner.Version >= 14 && this.realizedStrokeColor.A != color.A) { PdfExtGState extGState = this.renderer.Owner.ExtGStateTable.GetExtGStateStroke(color.A); string gs = this.renderer.Resources.AddExtGState(extGState); this.renderer.AppendFormat("{0} gs\n", gs); // Must create transparany group if (this.renderer.page != null && color.A < 1) this.renderer.page.transparencyUsed = true; } this.realizedStrokeColor = color; }
public void RealizeBrush(XBrush brush, PdfColorMode colorMode) { if (brush is XSolidBrush) { XColor color = ((XSolidBrush)brush).Color; color = ColorSpaceHelper.EnsureColorMode(colorMode, color); if (colorMode != PdfColorMode.Cmyk) { if (this.realizedFillColor.Rgb != color.Rgb) { this.renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Rgb)); this.renderer.Append(" rg\n"); } } else { if (!ColorSpaceHelper.IsEqualCmyk(this.realizedFillColor, color)) { this.renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Cmyk)); this.renderer.Append(" k\n"); } } if (this.renderer.Owner.Version >= 14 && this.realizedFillColor.A != color.A) { PdfExtGState extGState = this.renderer.Owner.ExtGStateTable.GetExtGStateNonStroke(color.A); string gs = this.renderer.Resources.AddExtGState(extGState); this.renderer.AppendFormat("{0} gs\n", gs); // Must create transparany group if (this.renderer.page != null && color.A < 1) this.renderer.page.transparencyUsed = true; } this.realizedFillColor = color; } else if (brush is XLinearGradientBrush) { XMatrix matrix = this.renderer.defaultViewMatrix; matrix.Prepend(this.Transform); PdfShadingPattern pattern = new PdfShadingPattern(this.renderer.Owner); pattern.SetupFromBrush((XLinearGradientBrush)brush, matrix); string name = this.renderer.Resources.AddPattern(pattern); this.renderer.AppendFormat("/Pattern cs\n", name); this.renderer.AppendFormat("{0} scn\n", name); // Invalidate fill color this.realizedFillColor = XColor.Empty; } }
public void RealizePen(XPen pen, PdfColorMode colorMode) { const string frmt2 = Config.SignificantFigures2; const string format = Config.SignificantFigures3; XColor color = pen.Color; bool overPrint = pen.Overprint; color = ColorSpaceHelper.EnsureColorMode(colorMode, color); if (_realizedLineWith != pen._width) { _renderer.AppendFormatArgs("{0:" + format + "} w\n", pen._width); _realizedLineWith = pen._width; } if (_realizedLineCap != (int)pen._lineCap) { _renderer.AppendFormatArgs("{0} J\n", (int)pen._lineCap); _realizedLineCap = (int)pen._lineCap; } if (_realizedLineJoin != (int)pen._lineJoin) { _renderer.AppendFormatArgs("{0} j\n", (int)pen._lineJoin); _realizedLineJoin = (int)pen._lineJoin; } if (_realizedLineCap == (int)XLineJoin.Miter) { if (_realizedMiterLimit != (int)pen._miterLimit && (int)pen._miterLimit != 0) { _renderer.AppendFormatInt("{0} M\n", (int)pen._miterLimit); _realizedMiterLimit = (int)pen._miterLimit; } } if (_realizedDashStyle != pen._dashStyle || pen._dashStyle == XDashStyle.Custom) { double dot = pen.Width; double dash = 3 * dot; // Line width 0 is not recommended but valid. XDashStyle dashStyle = pen.DashStyle; if (dot == 0) dashStyle = XDashStyle.Solid; switch (dashStyle) { case XDashStyle.Solid: _renderer.Append("[]0 d\n"); break; case XDashStyle.Dash: _renderer.AppendFormatArgs("[{0:" + frmt2 + "} {1:" + frmt2 + "}]0 d\n", dash, dot); break; case XDashStyle.Dot: _renderer.AppendFormatArgs("[{0:" + frmt2 + "}]0 d\n", dot); break; case XDashStyle.DashDot: _renderer.AppendFormatArgs("[{0:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "}]0 d\n", dash, dot); break; case XDashStyle.DashDotDot: _renderer.AppendFormatArgs("[{0:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "} {1:" + frmt2 + "}]0 d\n", dash, dot); break; case XDashStyle.Custom: { StringBuilder pdf = new StringBuilder("[", 256); int len = pen._dashPattern == null ? 0 : pen._dashPattern.Length; for (int idx = 0; idx < len; idx++) { if (idx > 0) pdf.Append(' '); pdf.Append(PdfEncoders.ToString(pen._dashPattern[idx] * pen._width)); } // Make an even number of values look like in GDI+ if (len > 0 && len % 2 == 1) { pdf.Append(' '); pdf.Append(PdfEncoders.ToString(0.2 * pen._width)); } pdf.AppendFormat(CultureInfo.InvariantCulture, "]{0:" + format + "} d\n", pen._dashOffset * pen._width); string pattern = pdf.ToString(); // BUG: [email protected] reported a realizing problem // HACK: I remove the if clause //if (_realizedDashPattern != pattern) { _realizedDashPattern = pattern; _renderer.Append(pattern); } } break; } _realizedDashStyle = dashStyle; } if (colorMode != PdfColorMode.Cmyk) { if (_realizedStrokeColor.Rgb != color.Rgb) { _renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Rgb)); _renderer.Append(" RG\n"); } } else { if (!ColorSpaceHelper.IsEqualCmyk(_realizedStrokeColor, color)) { _renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Cmyk)); _renderer.Append(" K\n"); } } if (_renderer.Owner.Version >= 14 && (_realizedStrokeColor.A != color.A || _realizedStrokeOverPrint != overPrint)) { PdfExtGState extGState = _renderer.Owner.ExtGStateTable.GetExtGStateStroke(color.A, overPrint); string gs = _renderer.Resources.AddExtGState(extGState); _renderer.AppendFormatString("{0} gs\n", gs); // Must create transparency group. if (_renderer._page != null && color.A < 1) _renderer._page.TransparencyUsed = true; } _realizedStrokeColor = color; _realizedStrokeOverPrint = overPrint; }
void RealizeRadialGradientBrush(RadialGradientBrush brush, XForm xform) { XMatrix matrix = new XMatrix(); // this.renderer.defaultViewMatrix; //matrix.MultiplyPrepend(this.Transform); matrix = currentTransform; //matrix.MultiplyPrepend(XMatrix.CreateScaling(1.3, 1)); PdfShadingPattern pattern = new PdfShadingPattern(writer.Owner); pattern.Elements[PdfShadingPattern.Keys.PatternType] = new PdfInteger(2); // shading pattern // Setup shading PdfShading shading = new PdfShading(writer.Owner); PdfColorMode colorMode = PdfColorMode.Rgb; //this.document.Options.ColorMode; PdfDictionary function = BuildShadingFunction(brush.GradientStops, colorMode); shading.Elements[PdfShading.Keys.ShadingType] = new PdfInteger(3); // Radial shading //if (colorMode != PdfColorMode.Cmyk) shading.Elements[PdfShading.Keys.ColorSpace] = new PdfName("/DeviceRGB"); //else //shading.Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK"); double x0 = brush.GradientOrigin.X; double y0 = brush.GradientOrigin.Y; double r0 = 0; double x1 = brush.Center.X; double y1 = brush.Center.Y; double r1 = brush.RadiusX; shading.Elements[PdfShading.Keys.Coords] = new PdfLiteral("[{0:0.###} {1:0.###} {2:0.###} {3:0.###} {4:0.###} {5:0.###}]", x0, y0, r0, x1, y1, r1); // old: Elements[Keys.Background] = new PdfRawItem("[0 1 1]"); // old: Elements[Keys.Domain] = shading.Elements[PdfShading.Keys.Function] = function; shading.Elements[PdfShading.Keys.Extend] = new PdfLiteral("[true true]"); // Setup pattern pattern.Elements[PdfShadingPattern.Keys.Shading] = shading; pattern.Elements[PdfShadingPattern.Keys.Matrix] = PdfLiteral.FromMatrix(matrix); // new PdfLiteral("[" + PdfEncoders.ToString(matrix) + "]"); string name = writer.Resources.AddPattern(pattern); writer.WriteLiteral("/Pattern cs\n", name); writer.WriteLiteral("{0} scn\n", name); double alpha = brush.Opacity * brush.GradientStops.GetAverageAlpha(); if (alpha < 1) { #if true PdfExtGState extGState = writer.Owner.ExtGStateTable.GetExtGStateNonStroke(alpha); string gs = writer.Resources.AddExtGState(extGState); writer.WriteLiteral("{0} gs\n", gs); #else if (xform == null) { PdfExtGState extGState = this.writer.Owner.ExtGStateTable.GetExtGStateNonStroke(alpha); string gs = this.writer.Resources.AddExtGState(extGState); this.writer.WriteGraphicState(extGState); } else { //PdfFormXObject pdfForm = this.writer.Owner.FormTable.GetForm(form); PdfFormXObject pdfForm = xform.pdfForm; pdfForm.Elements.SetString("/@", "This is the Form XObject of the soft mask"); string formName = this.writer.Resources.AddForm(pdfForm); PdfTransparencyGroupAttributes tgAttributes = new PdfTransparencyGroupAttributes(this.writer.Owner); //this.writer.Owner.Internals.AddObject(tgAttributes); tgAttributes.Elements.SetName(PdfTransparencyGroupAttributes.Keys.CS, "/DeviceRGB"); // Set reference to transparency group attributes pdfForm.Elements.SetObject(PdfFormXObject.Keys.Group, tgAttributes); pdfForm.Elements[PdfFormXObject.Keys.Matrix] = new PdfLiteral("[1.001 0 0 1.001 0.001 0.001]"); PdfSoftMask softmask = new PdfSoftMask(this.writer.Owner); this.writer.Owner.Internals.AddObject(softmask); softmask.Elements.SetString("/@", "This is the soft mask"); softmask.Elements.SetName(PdfSoftMask.Keys.S, "/Luminosity"); softmask.Elements.SetReference(PdfSoftMask.Keys.G, pdfForm); //pdfForm.Elements.SetName(PdfFormXObject.Keys.Type, "Group"); //pdfForm.Elements.SetName(PdfFormXObject.Keys.ss.Ss.Type, "Group"); PdfExtGState extGState = new PdfExtGState(this.writer.Owner); this.writer.Owner.Internals.AddObject(extGState); extGState.Elements.SetReference(PdfExtGState.Keys.SMask, softmask); this.writer.WriteGraphicState(extGState); } #endif } }
PdfDictionary BuildShadingFunction3(GradientStopCollection gradients, bool softMask, PdfColorMode colorMode) { int count = gradients.Count; Debug.Assert(count >= 2); // // Build a Type 3 function with an array of n-1 Type 2 functions PdfDictionary fn1 = new PdfDictionary(); fn1.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function fn1.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn1.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray = new PdfArray(); fn1.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0.ScA) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1.ScA) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1]"); } else { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); } fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); encode.Append("0 1"); } bounds.Append(']'); encode.Append(']'); fn1.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); fn1.Elements["/Encode"] = new PdfLiteral(encode.ToString()); return fn1; }
public static string InappropriateColorSpace(PdfColorMode colorMode, XColorSpace colorSpace) { string mode; switch (colorMode) { case PdfColorMode.Rgb: mode = "RGB"; break; case PdfColorMode.Cmyk: mode = "CMYK"; break; default: mode = "(undefined)"; break; } string space; switch (colorSpace) { case XColorSpace.Rgb: space = "RGB"; break; case XColorSpace.Cmyk: space = "CMYK"; break; case XColorSpace.GrayScale: space = "grayscale"; break; default: space = "(undefined)"; break; } return String.Format("The document requires color mode {0}, but a color is defined using {1}. " + "Use only colors that match the color mode of the PDF document", mode, space); }
void RealizeLinearGradientBrush(LinearGradientBrush brush, XForm xform) { XMatrix matrix = currentTransform; PdfShadingPattern pattern = new PdfShadingPattern(writer.Owner); pattern.Elements[PdfShadingPattern.Keys.PatternType] = new PdfInteger(2); // shading pattern // Setup shading PdfShading shading = new PdfShading(writer.Owner); PdfColorMode colorMode = PdfColorMode.Rgb; //this.document.Options.ColorMode; PdfDictionary function = BuildShadingFunction(brush.GradientStops, colorMode); function.Elements.SetString("/@", "This is the shading function of a LinearGradientBrush"); shading.Elements[PdfShading.Keys.Function] = function; shading.Elements[PdfShading.Keys.ShadingType] = new PdfInteger(2); // Axial shading //if (colorMode != PdfColorMode.Cmyk) shading.Elements[PdfShading.Keys.ColorSpace] = new PdfName("/DeviceRGB"); //else //shading.Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK"); //double x1 = 0, y1 = 0, x2 = 0, y2 = 0; double x1 = brush.StartPoint.X; double y1 = brush.StartPoint.Y; double x2 = brush.EndPoint.X; double y2 = brush.EndPoint.Y; shading.Elements[PdfShading.Keys.Coords] = new PdfLiteral("[{0:0.###} {1:0.###} {2:0.###} {3:0.###}]", x1, y1, x2, y2); // old: Elements[Keys.Background] = new PdfRawItem("[0 1 1]"); // old: Elements[Keys.Domain] = shading.Elements[PdfShading.Keys.Extend] = new PdfLiteral("[true true]"); // Setup pattern pattern.Elements[PdfShadingPattern.Keys.Shading] = shading; pattern.Elements[PdfShadingPattern.Keys.Matrix] = PdfLiteral.FromMatrix(matrix); // new PdfLiteral("[" + PdfEncoders.ToString(matrix) + "]"); string name = writer.Resources.AddPattern(pattern); writer.WriteLiteral("/Pattern cs\n", name); writer.WriteLiteral("{0} scn\n", name); double alpha = brush.Opacity * brush.GradientStops.GetAverageAlpha(); if (alpha < 1 && writer.renderMode == RenderMode.Default) { #if true PdfExtGState extGState = writer.Owner.ExtGStateTable.GetExtGStateNonStroke(alpha); string gs = writer.Resources.AddExtGState(extGState); writer.WriteLiteral("{0} gs\n", gs); #else #if true if (xform == null) { PdfExtGState extGState = this.writer.Owner.ExtGStateTable.GetExtGStateNonStroke(alpha); string gs = this.writer.Resources.AddExtGState(extGState); this.writer.WriteGraphicState(extGState); } else { //PdfFormXObject pdfForm = this.writer.Owner.FormTable.GetForm(form); PdfFormXObject pdfForm = xform.pdfForm; pdfForm.Elements.SetString("/@", "This is the Form XObject of the soft mask"); string formName = this.writer.Resources.AddForm(pdfForm); PdfTransparencyGroupAttributes tgAttributes = new PdfTransparencyGroupAttributes(this.writer.Owner); //this.writer.Owner.Internals.AddObject(tgAttributes); tgAttributes.Elements.SetName(PdfTransparencyGroupAttributes.Keys.CS, "/DeviceRGB"); // Set reference to transparency group attributes pdfForm.Elements.SetObject(PdfFormXObject.Keys.Group, tgAttributes); pdfForm.Elements[PdfFormXObject.Keys.Matrix] = new PdfLiteral("[1.001 0 0 1.001 0.001 0.001]"); PdfSoftMask softmask = new PdfSoftMask(this.writer.Owner); this.writer.Owner.Internals.AddObject(softmask); softmask.Elements.SetString("/@", "This is the soft mask"); softmask.Elements.SetName(PdfSoftMask.Keys.S, "/Luminosity"); softmask.Elements.SetReference(PdfSoftMask.Keys.G, pdfForm); //pdfForm.Elements.SetName(PdfFormXObject.Keys.Type, "Group"); //pdfForm.Elements.SetName(PdfFormXObject.Keys.ss.Ss.Type, "Group"); PdfExtGState extGState = new PdfExtGState(this.writer.Owner); this.writer.Owner.Internals.AddObject(extGState); extGState.Elements.SetReference(PdfExtGState.Keys.SMask, softmask); this.writer.WriteGraphicState(extGState); } #else XForm form = new XForm(this.writer.Owner, 220, 140); XGraphics formGfx = XGraphics.FromForm(form); // draw something //XSolidBrush xbrush = new XSolidBrush(XColor.FromArgb(128, 128, 128)); XLinearGradientBrush xbrush = new XLinearGradientBrush(new XPoint(0, 0), new XPoint(220, 0), XColors.White, XColors.Black); formGfx.DrawRectangle(xbrush, -10000, -10000, 20000, 20000); //formGfx.DrawString("Text, Graphics, Images, and Forms", new XFont("Verdana", 10, XFontStyle.Regular), XBrushes.Navy, 3, 0, XStringFormat.TopLeft); formGfx.Dispose(); // Close form form.Finish(); PdfFormXObject pdfForm = this.writer.Owner.FormTable.GetForm(form); string formName = this.writer.Resources.AddForm(pdfForm); //double x = 20, y = 20; //double cx = 1; //double cy = 1; //this.writer.AppendFormat("q {2:0.###} 0 0 -{3:0.###} {0:0.###} {4:0.###} cm 100 Tz {5} Do Q\n", // x, y, cx, cy, y + 0, formName); //this.writer.AppendFormat("q {2:0.###} 0 0 -{3:0.###} {0:0.###} {4:0.###} cm 100 Tz {5} Do Q\n", // x, y, cx, cy, y + 220/1.5, formName); PdfTransparencyGroupAttributes tgAttributes = new PdfTransparencyGroupAttributes(this.writer.Owner); this.writer.Owner.Internals.AddObject(tgAttributes); tgAttributes.Elements.SetName(PdfTransparencyGroupAttributes.Keys.CS, "/DeviceRGB"); // Set reference to transparency group attributes pdfForm.Elements.SetReference(PdfFormXObject.Keys.Group, tgAttributes); PdfSoftMask softmask = new PdfSoftMask(this.writer.Owner); this.writer.Owner.Internals.AddObject(softmask); softmask.Elements.SetName(PdfSoftMask.Keys.S, "/Luminosity"); softmask.Elements.SetReference(PdfSoftMask.Keys.G, pdfForm); //pdfForm.Elements.SetName(PdfFormXObject.Keys.Type, "Group"); //pdfForm.Elements.SetName(PdfFormXObject.Keys.ss.Ss.Type, "Group"); PdfExtGState extGState = new PdfExtGState(this.writer.Owner); this.writer.Owner.Internals.AddObject(extGState); extGState.Elements.SetReference(PdfExtGState.Keys.SMask, softmask); this.writer.WriteGraphicState(extGState); #endif #endif } }
/// <summary> /// Setups the shading from the specified brush. /// </summary> internal void SetupFromBrush(XLinearGradientBrush brush, XGraphicsPdfRenderer renderer) { if (brush == null) { throw new ArgumentNullException("brush"); } PdfColorMode colorMode = _document.Options.ColorMode; XColor color1 = ColorSpaceHelper.EnsureColorMode(colorMode, brush._color1); XColor color2 = ColorSpaceHelper.EnsureColorMode(colorMode, brush._color2); PdfDictionary function = new PdfDictionary(); Elements[Keys.ShadingType] = new PdfInteger(2); if (colorMode != PdfColorMode.Cmyk) { Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB"); } else { Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK"); } double x1 = 0, y1 = 0, x2 = 0, y2 = 0; if (brush._useRect) { XPoint pt1 = renderer.WorldToView(brush._rect.TopLeft); XPoint pt2 = renderer.WorldToView(brush._rect.BottomRight); switch (brush._linearGradientMode) { case XLinearGradientMode.Horizontal: x1 = pt1.X; y1 = pt1.Y; x2 = pt2.X; y2 = pt1.Y; break; case XLinearGradientMode.Vertical: x1 = pt1.X; y1 = pt1.Y; x2 = pt1.X; y2 = pt2.Y; break; case XLinearGradientMode.ForwardDiagonal: x1 = pt1.X; y1 = pt1.Y; x2 = pt2.X; y2 = pt2.Y; break; case XLinearGradientMode.BackwardDiagonal: x1 = pt2.X; y1 = pt1.Y; x2 = pt1.X; y2 = pt2.Y; break; } } else { XPoint pt1 = renderer.WorldToView(brush._point1); XPoint pt2 = renderer.WorldToView(brush._point2); x1 = pt1.X; y1 = pt1.Y; x2 = pt2.X; y2 = pt2.Y; } const string format = Config.SignificantFigures3; Elements[Keys.Coords] = new PdfLiteral("[{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "}]", x1, y1, x2, y2); //Elements[Keys.Background] = new PdfRawItem("[0 1 1]"); //Elements[Keys.Domain] = Elements[Keys.Function] = function; //Elements[Keys.Extend] = new PdfRawItem("[true true]"); string clr1 = "[" + PdfEncoders.ToString(color1, colorMode) + "]"; string clr2 = "[" + PdfEncoders.ToString(color2, colorMode) + "]"; function.Elements["/FunctionType"] = new PdfInteger(2); function.Elements["/C0"] = new PdfLiteral(clr1); function.Elements["/C1"] = new PdfLiteral(clr2); function.Elements["/Domain"] = new PdfLiteral("[0 1]"); function.Elements["/N"] = new PdfInteger(1); }
/// <summary> /// Converts an XColor into a string with up to 3 decimal digits and a decimal point. /// </summary> public static string ToString(XColor color, PdfColorMode colorMode) { const string format = Config.SignificantFigures3; // If not defined let color decide if (colorMode == PdfColorMode.Undefined) colorMode = color.ColorSpace == XColorSpace.Cmyk ? PdfColorMode.Cmyk : PdfColorMode.Rgb; switch (colorMode) { case PdfColorMode.Cmyk: return String.Format(CultureInfo.InvariantCulture, "{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "}", color.C, color.M, color.Y, color.K); default: return String.Format(CultureInfo.InvariantCulture, "{0:" + format + "} {1:" + format + "} {2:" + format + "}", color.R / 255.0, color.G / 255.0, color.B / 255.0); } }