protected internal virtual void ApplyRotationLayout(Rectangle layoutBox) { float angle = (float)this.GetPropertyAsFloat(Property.ROTATION_ANGLE); float x = occupiedArea.GetBBox().GetX(); float y = occupiedArea.GetBBox().GetY(); float height = occupiedArea.GetBBox().GetHeight(); float width = occupiedArea.GetBBox().GetWidth(); SetProperty(Property.ROTATION_INITIAL_WIDTH, width); SetProperty(Property.ROTATION_INITIAL_HEIGHT, height); AffineTransform rotationTransform = new AffineTransform(); // here we calculate and set the actual occupied area of the rotated content if (IsPositioned()) { float?rotationPointX = this.GetPropertyAsFloat(Property.ROTATION_POINT_X); float?rotationPointY = this.GetPropertyAsFloat(Property.ROTATION_POINT_Y); if (rotationPointX == null || rotationPointY == null) { // if rotation point was not specified, the most bottom-left point is used rotationPointX = x; rotationPointY = y; } // transforms apply from bottom to top rotationTransform.Translate((float)rotationPointX, (float)rotationPointY); // move point back at place rotationTransform.Rotate(angle); // rotate rotationTransform.Translate((float)-rotationPointX, (float)-rotationPointY); // move rotation point to origin IList <Point> rotatedPoints = TransformPoints(RectangleToPointsList(occupiedArea.GetBBox()), rotationTransform ); Rectangle newBBox = CalculateBBox(rotatedPoints); // make occupied area be of size and position of actual content occupiedArea.GetBBox().SetWidth(newBBox.GetWidth()); occupiedArea.GetBBox().SetHeight(newBBox.GetHeight()); float occupiedAreaShiftX = newBBox.GetX() - x; float occupiedAreaShiftY = newBBox.GetY() - y; Move(occupiedAreaShiftX, occupiedAreaShiftY); } else { rotationTransform = AffineTransform.GetRotateInstance(angle); IList <Point> rotatedPoints = TransformPoints(RectangleToPointsList(occupiedArea.GetBBox()), rotationTransform ); float[] shift = CalculateShiftToPositionBBoxOfPointsAt(x, y + height, rotatedPoints); foreach (Point point in rotatedPoints) { point.SetLocation(point.GetX() + shift[0], point.GetY() + shift[1]); } Rectangle newBBox = CalculateBBox(rotatedPoints); occupiedArea.GetBBox().SetWidth(newBBox.GetWidth()); occupiedArea.GetBBox().SetHeight(newBBox.GetHeight()); float heightDiff = height - newBBox.GetHeight(); Move(0, heightDiff); } }
public override void SetTransformation(double translateX, double translateY, double rotate, double scaleX, double scaleY) { translateX *= MmToPt; translateY *= MmToPt; _canvas.RestoreState(); _lastStrokingColor = 0; _lastNonStrokingColor = 0; _lastLineWidth = 1; _lastFont = null; _lastFontSize = 0; _canvas.SaveState(); AffineTransform matrix = new AffineTransform(); matrix.Translate(translateX, translateY); if (rotate != 0) { matrix.Rotate(rotate); } if (scaleX != 1 || scaleY != 1) { matrix.Scale(scaleX, scaleY); } _canvas.ConcatMatrix(matrix); }
private AffineTransform GetGradientTransformToUserSpaceOnUse(Rectangle objectBoundingBox, bool isObjectBoundingBox ) { AffineTransform gradientTransform = new AffineTransform(); if (isObjectBoundingBox) { gradientTransform.Translate(objectBoundingBox.GetX(), objectBoundingBox.GetY()); // We need to scale with dividing the lengths by 0.75 as further we should // concatenate gradient transformation matrix which has no absolute parsing. // For example, if gradientTransform is set to translate(1, 1) and gradientUnits // is set to "objectBoundingBox" then the gradient should be shifted horizontally // and vertically exactly by the size of the element bounding box. So, again, // as we parse translate(1, 1) to translation(0.75, 0.75) the bounding box in // the gradient vector space should be 0.75x0.75 in order for such translation // to shift by the complete size of bounding box. gradientTransform.Scale(objectBoundingBox.GetWidth() / 0.75, objectBoundingBox.GetHeight() / 0.75); } AffineTransform svgGradientTransformation = GetGradientTransform(); if (svgGradientTransformation != null) { gradientTransform.Concatenate(svgGradientTransformation); } return(gradientTransform); }
public virtual void ProcessAspectRatioPositionXMidYMax() { String alignValue = SvgConstants.Values.XMID_YMAX; AffineTransform cmpTransform = new AffineTransform(); cmpTransform.Translate(147.5, 442); ProcessAspectRatioPositionAndCompare(alignValue, cmpTransform); }
public virtual void ProcessAspectRatioPositionXMinYMid() { String alignValue = SvgConstants.Values.XMIN_YMID; AffineTransform cmpTransform = new AffineTransform(); cmpTransform.Translate(0, 221); ProcessAspectRatioPositionAndCompare(alignValue, cmpTransform); }
public virtual void ProcessAspectRatioPositionNone() { String alignValue = SvgConstants.Values.NONE; AffineTransform cmpTransform = new AffineTransform(); cmpTransform.Translate(0, 0); ProcessAspectRatioPositionAndCompare(alignValue, cmpTransform); }
public virtual void ProcessAspectRatioPositionXMaxYMin() { String alignValue = SvgConstants.Values.XMAX_YMIN; AffineTransform cmpTransform = new AffineTransform(); cmpTransform.Translate(295, 0); ProcessAspectRatioPositionAndCompare(alignValue, cmpTransform); }
public virtual void ProcessAspectRatioPositionDefault() { //default aspect ration is xMidYMid String alignValue = SvgConstants.Values.DEFAULT_ASPECT_RATIO; AffineTransform cmpTransform = new AffineTransform(); cmpTransform.Translate(147.5, 221); ProcessAspectRatioPositionAndCompare(alignValue, cmpTransform); }
private static AffineTransform CreateGradientTransform(Rectangle2D r) { double cx = r.CenterX; double cy = r.CenterY; AffineTransform xform = AffineTransform.GetTranslateInstance(cx, cy); xform.Scale(r.Width / 2, r.Height / 2); xform.Translate(-cx, -cy); return(xform); }
private byte[] CreatePdfWithRotatedXObject(String xobjectText) { MemoryStream baos = new MemoryStream(); Document doc = new Document(); PdfWriter writer = PdfWriter.GetInstance(doc, baos); writer.CompressionLevel = 0; doc.Open(); doc.Add(new Paragraph("A")); doc.Add(new Paragraph("B")); bool rotate = true; PdfTemplate template = writer.DirectContent.CreateTemplate(20, 100); template.SetColorStroke(BaseColor.GREEN); template.Rectangle(0, 0, template.Width, template.Height); template.Stroke(); AffineTransform tx = new AffineTransform(); if (rotate) { tx.Translate(0, template.Height); tx.Rotate(-90 / 180f * Math.PI); } template.Transform(tx); template.BeginText(); template.SetFontAndSize(BaseFont.CreateFont(), 12); if (rotate) { template.MoveText(0, template.Width - 12); } else { template.MoveText(0, template.Height - 12); } template.ShowText(xobjectText); template.EndText(); Image xobjectImage = Image.GetInstance(template); if (rotate) { xobjectImage.RotationDegrees = 90; } doc.Add(xobjectImage); doc.Add(new Paragraph("C")); doc.Close(); return(baos.ToArray()); }
private void TranslateImage(float xDistance, float yDistance, AffineTransform t) { t.Translate(xDistance, yDistance); t.GetMatrix(matrix); if (fixedXPosition != null) { fixedXPosition += (float)t.GetTranslateX(); } if (fixedYPosition != null) { fixedYPosition += (float)t.GetTranslateY(); } }
// --------------------------------------------------------------------------- /** * Creates a PDF document. */ public byte[] CreatePdf() { // step 1 Rectangle rect = new Rectangle(-595, -842, 595, 842); using (MemoryStream ms = new MemoryStream()) { using (Document document = new Document(rect)) { // step 2 PdfWriter writer = PdfWriter.GetInstance(document, ms); // step 3 document.Open(); // step 4 PdfContentByte canvas = writer.DirectContent; // draw coordinate system canvas.MoveTo(-595, 0); canvas.LineTo(595, 0); canvas.MoveTo(0, -842); canvas.LineTo(0, 842); canvas.Stroke(); // read the PDF with the logo PdfReader reader = new PdfReader(RESOURCE); PdfTemplate template = writer.GetImportedPage(reader, 1); // add it canvas.SaveState(); canvas.AddTemplate(template, 0, 0); AffineTransform af = new AffineTransform(); af.Translate(-595, 0); af.Scale(0.5f, 0.5f); canvas.Transform(af); canvas.AddTemplate(template, 0, 0); canvas.ConcatCTM(AffineTransform.GetTranslateInstance(595, 595)); canvas.AddTemplate(template, 0, 0); canvas.RestoreState(); canvas.SaveState(); af = new AffineTransform(1f, 0f, 0.4f, 1f, -750f, -650f); canvas.AddTemplate(template, af); canvas.RestoreState(); canvas.SaveState(); af = new AffineTransform(0, -1, -1, 0, 650, 0); canvas.AddTemplate(template, af); af = new AffineTransform(0, -0.2f, -0.5f, 0, 350, 0); canvas.AddTemplate(template, af); canvas.RestoreState(); } return(ms.ToArray()); } }
private void MoveShape(Point start, Point end) { if (CurrentState.IsMoveShape == false) { return; } AffineTransform affine = new AffineTransform(); affine.Translate(end.X - start.X, end.Y - start.Y); foreach (Shape currShape in ListOfInstances) { if (currShape.IsChosen == true) { currShape.PixelsInLine = affine.Transform(savedPointInLine); currShape.PixelsInArea = affine.Transform(savedPointInArea); } } }
/// <exception cref="System.Exception"/> private byte[] CreatePdfWithRotatedXObject(String xobjectText) { MemoryStream baos = new MemoryStream(); PdfDocument pdfDocument = new PdfDocument(new PdfWriter(baos).SetCompressionLevel(0)); Document document = new Document(pdfDocument); document.Add(new Paragraph("A")); document.Add(new Paragraph("B")); PdfFormXObject template = new PdfFormXObject(new Rectangle(20, 100)); PdfCanvas canvas = new PdfCanvas(template, pdfDocument); canvas.SetStrokeColor(Color.GREEN).Rectangle(0, 0, template.GetWidth(), template.GetHeight()).Stroke(); AffineTransform tx = new AffineTransform(); tx.Translate(0, template.GetHeight()); tx.Rotate((float)(-90 / 180f * Math.PI)); canvas.ConcatMatrix(tx).BeginText().SetFontAndSize(PdfFontFactory.CreateFont(FontConstants.HELVETICA), 12) .MoveText(0, template.GetWidth() - 12).ShowText(xobjectText).EndText(); document.Add(new Image(template).SetRotationAngle(Math.PI / 2)).Add(new Paragraph("C")); document.Close(); return(baos.ToArray()); }
/// <summary>Evaluates the minimal domain that covers the box with vector normals.</summary> /// <remarks> /// Evaluates the minimal domain that covers the box with vector normals. /// The domain corresponding to the initial vector is [0, 1]. /// </remarks> /// <param name="coords"> /// the array of exactly two elements that describe /// the base vector (corresponding to [0,1] domain, that need to be adjusted /// to cover the box /// </param> /// <param name="toCover">the box that needs to be covered</param> /// <returns> /// the array of two elements in ascending order specifying the calculated covering /// domain /// </returns> protected internal static double[] EvaluateCoveringDomain(Point[] coords, Rectangle toCover) { if (toCover == null) { return(new double[] { 0d, 1d }); } AffineTransform transform = new AffineTransform(); double scale = 1d / (coords[0].Distance(coords[1])); double sin = -(coords[1].GetY() - coords[0].GetY()) * scale; double cos = (coords[1].GetX() - coords[0].GetX()) * scale; if (Math.Abs(cos) < ZERO_EPSILON) { cos = 0d; sin = sin > 0d ? 1d : -1d; } else { if (Math.Abs(sin) < ZERO_EPSILON) { sin = 0d; cos = cos > 0d ? 1d : -1d; } } transform.Concatenate(new AffineTransform(cos, sin, -sin, cos, 0, 0)); transform.Scale(scale, scale); transform.Translate(-coords[0].GetX(), -coords[0].GetY()); Point[] rectanglePoints = toCover.ToPointsArray(); double minX = transform.Transform(rectanglePoints[0], null).GetX(); double maxX = minX; for (int i = 1; i < rectanglePoints.Length; ++i) { double currentX = transform.Transform(rectanglePoints[i], null).GetX(); minX = Math.Min(minX, currentX); maxX = Math.Max(maxX, currentX); } return(new double[] { minX, maxX }); }
public void TranslateAndRotate(double xT, double yT, double rad) { _transform.Translate(xT, yT); _transform.Rotate(rad); }
/// <summary>If present, process the preserveAspectRatio position.</summary> /// <param name="context">the svg draw context</param> /// <param name="viewBoxValues">the four values depicting the viewbox [min-x min-y width height]</param> /// <param name="align">alignment method to use</param> /// <param name="scaleWidth">the multiplier for scaling width</param> /// <param name="scaleHeight">the multiplier for scaling height</param> /// <returns>the transformation based on the preserveAspectRatio value</returns> internal virtual AffineTransform ProcessAspectRatioPosition(SvgDrawContext context, float[] viewBoxValues, String align, float scaleWidth, float scaleHeight) { AffineTransform transform = new AffineTransform(); Rectangle currentViewPort = context.GetCurrentViewPort(); float midXBox = viewBoxValues[0] + (viewBoxValues[2] / 2); float midYBox = viewBoxValues[1] + (viewBoxValues[3] / 2); float midXPort = currentViewPort.GetX() + (currentViewPort.GetWidth() / 2); float midYPort = currentViewPort.GetY() + (currentViewPort.GetHeight() / 2); float x = 0f; float y = 0f; // if x attribute of svg is present, then x value of current viewport should be set according to it if (attributesAndStyles.ContainsKey(SvgConstants.Attributes.X)) { x = CssUtils.ParseAbsoluteLength(attributesAndStyles.Get(SvgConstants.Attributes.X)); } // if y attribute of svg is present, then y value of current viewport should be set according to it if (attributesAndStyles.ContainsKey(SvgConstants.Attributes.Y)) { y = CssUtils.ParseAbsoluteLength(attributesAndStyles.Get(SvgConstants.Attributes.Y)); } // need to consider previous (parent) translation before applying the current one x -= currentViewPort.GetX(); y -= currentViewPort.GetY(); switch (align.ToLowerInvariant()) { case SvgConstants.Values.NONE: { break; } case SvgConstants.Values.XMIN_YMIN: { x -= viewBoxValues[0]; y -= viewBoxValues[1]; break; } case SvgConstants.Values.XMIN_YMID: { x -= viewBoxValues[0]; y += (midYPort - midYBox); break; } case SvgConstants.Values.XMIN_YMAX: { x -= viewBoxValues[0]; y += (currentViewPort.GetHeight() - viewBoxValues[3]); break; } case SvgConstants.Values.XMID_YMIN: { x += (midXPort - midXBox); y -= viewBoxValues[1]; break; } case SvgConstants.Values.XMID_YMAX: { x += (midXPort - midXBox); y += (currentViewPort.GetHeight() - viewBoxValues[3]); break; } case SvgConstants.Values.XMAX_YMIN: { x += (currentViewPort.GetWidth() - viewBoxValues[2]); y -= viewBoxValues[1]; break; } case SvgConstants.Values.XMAX_YMID: { x += (currentViewPort.GetWidth() - viewBoxValues[2]); y += (midYPort - midYBox); break; } case SvgConstants.Values.XMAX_YMAX: { x += (currentViewPort.GetWidth() - viewBoxValues[2]); y += (currentViewPort.GetHeight() - viewBoxValues[3]); break; } case SvgConstants.Values.DEFAULT_ASPECT_RATIO: default: { x += (midXPort - midXBox); y += (midYPort - midYBox); break; } } //Rescale x and y x /= scaleWidth; y /= scaleHeight; transform.Translate(x, y); return(transform); }
/// <summary> /// Watermarks a PDF file. /// </summary> /// <paramref name="fileName"/> private void WatermarkPdf(string fileName) { var watermarkText = _operation.WatermarkText; var sourceFile = $"{_operation.SourcePath}\\{fileName}"; var destinationPath = $"{_operation.DestinationPath}\\{PathWatermarked}"; var destinationFile = $"{destinationPath}\\{fileName}"; ValidatePath(destinationPath); const float watermarkTrimmingRectangleWidth = 600; const float watermarkTrimmingRectangleHeight = 600; const float formWidth = 300; const float formHeight = 300; const float formXOffset = 0; const float formYOffset = 0; const float xTranslation = 50; const float yTranslation = 25; const double rotationInRads = Math.PI / 3; try { FontCache.ClearSavedFonts(); } catch (Exception exception) { Log.Error(exception.Message); } var font = PdfFontFactory.CreateFont(StandardFonts.COURIER); const float fontSize = 119; using var reader = new PdfReader(new MemoryStream(File.ReadAllBytes(sourceFile))); using var pdfDoc = new PdfDocument(reader, new PdfWriter(destinationFile)); var numberOfPages = pdfDoc.GetNumberOfPages(); PdfPage page = null; for (var i = 1; i <= numberOfPages; i++) { page = pdfDoc.GetPage(i); var ps = page.GetPageSize(); //Center the annotation var bottomLeftX = ps.GetWidth() / 2 - watermarkTrimmingRectangleWidth / 2; var bottomLeftY = ps.GetHeight() / 2 - watermarkTrimmingRectangleHeight / 2; var watermarkTrimmingRectangle = new Rectangle(bottomLeftX, bottomLeftY, watermarkTrimmingRectangleWidth, watermarkTrimmingRectangleHeight); var watermark = new PdfWatermarkAnnotation(watermarkTrimmingRectangle); //Apply linear algebra rotation math //Create identity matrix var transform = new AffineTransform(); //No-args constructor creates the identity transform //Apply translation transform.Translate(xTranslation, yTranslation); //Apply rotation transform.Rotate(rotationInRads); var fixedPrint = new PdfFixedPrint(); watermark.SetFixedPrint(fixedPrint); //Create appearance var formRectangle = new Rectangle(formXOffset, formYOffset, formWidth, formHeight); //Observation: font XObject will be resized to fit inside the watermark rectangle var form = new PdfFormXObject(formRectangle); var gs1 = new PdfExtGState().SetFillOpacity(0.6f); var canvas = new PdfCanvas(form, pdfDoc); var transformValues = new float[6]; transform.GetMatrix(transformValues); canvas.SaveState() .BeginText().SetColor(ColorConstants.GRAY, true).SetExtGState(gs1) .SetTextMatrix(transformValues[0], transformValues[1], transformValues[2], transformValues[3], transformValues[4], transformValues[5]) .SetFontAndSize(font, fontSize) .ShowText(watermarkText) .EndText() .RestoreState(); canvas.Release(); watermark.SetAppearance(PdfName.N, new PdfAnnotationAppearance(form.GetPdfObject())); watermark.SetFlags(PdfAnnotation.PRINT); page.AddAnnotation(watermark); } page?.Flush(); pdfDoc.Close(); }
public bool AddWaterMarkerToPdf(string pdfFile, string destFile, string text, string fontFamily, string fontColor, int fontSize = 50) { if (File.Exists(pdfFile)) { try { using (var pr = new PdfReader(pdfFile)) { var rgbColor = System.Drawing.ColorTranslator.FromHtml(fontColor); PdfFont font = fontFamily.Contains("STSong") ? PdfFontFactory.CreateFont(fontFamily, "UniGB-UCS2-H", true) : PdfFontFactory.CreateFont(fontFamily);//PdfFontFactory.CreateFont(fontFamily, "UniGB-UCS2-H", true); if (font != null) { var textLength = font.GetWidth(text, fontSize); var pw = new PdfWriter(destFile); var pdfDoc = new PdfDocument(pr, pw); Rectangle ps; PdfCanvas canvas; var pageCount = pdfDoc.GetNumberOfPages(); for (var i = 1; i < pageCount + 1; i++) { var page = pdfDoc.GetPage(i); ps = page.GetPageSize(); float watermarkTrimmingRectangleWidth = textLength; //Math.Min(ps.GetWidth(), ps.GetHeight()); float watermarkTrimmingRectangleHeight = watermarkTrimmingRectangleWidth; var rotationInRads = MathF.Atan2(ps.GetHeight(), ps.GetWidth()); //var angle = rotationInRads * 180f / MathF.PI; float formWidth = ps.GetWidth(); //watermarkTrimmingRectangleWidth; float formHeight = ps.GetHeight(); //watermarkTrimmingRectangleWidth; float formXOffset = 0; float formYOffset = 0; float xTranslation = (formWidth - watermarkTrimmingRectangleWidth * MathF.Cos(rotationInRads)) / 2; float yTranslation = (formHeight - watermarkTrimmingRectangleWidth * MathF.Sin(rotationInRads)) / 2; //Center the annotation Rectangle watermarkTrimmingRectangle = new Rectangle(0, 0, formWidth, formHeight);//watermarkTrimmingRectangleWidth, watermarkTrimmingRectangleWidth); PdfWatermarkAnnotation watermark = new PdfWatermarkAnnotation(watermarkTrimmingRectangle); //Apply linear algebra rotation math //Create identity matrix AffineTransform transform = new AffineTransform(); //No-args constructor creates the identity transform //Apply translation //transform.Translate(xTranslation, yTranslation); //Apply rotation transform.Translate(xTranslation, yTranslation); transform.Rotate(rotationInRads); PdfFixedPrint fixedPrint = new PdfFixedPrint(); watermark.SetFixedPrint(fixedPrint); //Create appearance Rectangle formRectangle = new Rectangle(formXOffset, formYOffset, formWidth, formHeight); //Observation: font XObject will be resized to fit inside the watermark rectangle PdfFormXObject form = new PdfFormXObject(formRectangle); PdfExtGState gs1 = new PdfExtGState().SetFillOpacity(rgbColor.A / 255f); canvas = new PdfCanvas(form, pdfDoc); float[] transformValues = new float[6]; transform.GetMatrix(transformValues); canvas.SaveState() .BeginText().SetFillColorRgb(rgbColor.R / 225f, rgbColor.G / 225f, rgbColor.B / 255f).SetExtGState(gs1) .SetTextMatrix(transformValues[0], transformValues[1], transformValues[2], transformValues[3], transformValues[4], transformValues[5]) .SetFontAndSize(font, fontSize) .ShowText(text) .EndText() .RestoreState(); canvas.Release(); watermark.SetAppearance(PdfName.N, new PdfAnnotationAppearance(form.GetPdfObject())); watermark.SetFlags(PdfAnnotation.PRINT); page.AddAnnotation(watermark); } pdfDoc.Close(); } else { App.Current.Dispatcher.Invoke(() => { MessageBoxX.Show($"没有找到字体{fontFamily},请确认已安装", "字体错误"); }); return(false); } return(true); } } catch (Exception ex) { Analytics.TrackEvent("PDFError", new Dictionary <string, string> { ["message"] = ex.ToString() }); } finally { File.Delete(pdfFile); } } return(false); }
public override void Draw(PdfCanvas canvas) { Point start = new Point(startPoint.x * .75, startPoint.y * .75); // pixels to points double rx = Math.Abs(CssUtils.ParseAbsoluteLength(coordinates[0])); double ry = Math.Abs(CssUtils.ParseAbsoluteLength(coordinates[1])); // φ is taken mod 360 degrees. double rotation = Double.Parse(coordinates[2], System.Globalization.CultureInfo.InvariantCulture) % 360.0; // rotation argument is given in degrees, but we need radians for easier trigonometric calculations rotation = MathUtil.ToRadians(rotation); // binary flags (Value correction: any nonzero value for either of the flags fA or fS is taken to mean the value 1.) bool largeArc = !CssUtils.CompareFloats((float)CssUtils.ParseFloat(coordinates[3]), 0); bool sweep = !CssUtils.CompareFloats((float)CssUtils.ParseFloat(coordinates[4]), 0); Point end = new Point(CssUtils.ParseAbsoluteLength(coordinates[5]), CssUtils.ParseAbsoluteLength(coordinates [6])); if (CssUtils.CompareFloats(start.x, end.x) && CssUtils.CompareFloats(start.y, end.y)) { /* edge case: If the endpoints (x1, y1) and (x2, y2) are identical, * then this is equivalent to omitting the elliptical arc segment entirely. */ return; } if (CssUtils.CompareFloats(rx, 0) || CssUtils.CompareFloats(ry, 0)) { /* edge case: If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a "lineto") * joining the endpoints. */ canvas.LineTo(end.x, end.y); } else { /* This is the first step of calculating a rotated elliptical path. * We must simulate a transformation on the end-point in order to calculate appropriate EllipseArc angles; * if we don't do this, then the EllipseArc class will calculate the correct bounding rectangle, * but an incorrect starting angle and/or extent. */ EllipticalCurveTo.EllipseArc arc; if (CssUtils.CompareFloats(rotation, 0)) { arc = EllipticalCurveTo.EllipseArc.GetEllipse(start, end, rx, ry, sweep, largeArc); } else { AffineTransform normalizer = AffineTransform.GetRotateInstance(-rotation); normalizer.Translate(-start.x, -start.y); Point newArcEnd = normalizer.Transform(end, null); newArcEnd.Translate(start.x, start.y); arc = EllipticalCurveTo.EllipseArc.GetEllipse(start, newArcEnd, rx, ry, sweep, largeArc); } Point[][] points = MakePoints(PdfCanvas.BezierArc(arc.ll.x, arc.ll.y, arc.ur.x, arc.ur.y, arc.startAng, arc .extent)); if (sweep) { points = Rotate(points, rotation, points[0][0]); for (int i = 0; i < points.Length; i++) { DrawCurve(canvas, points[i][1], points[i][2], points[i][3]); } } else { points = Rotate(points, rotation, points[points.Length - 1][3]); for (int i = points.Length - 1; i >= 0; i--) { DrawCurve(canvas, points[i][2], points[i][1], points[i][0]); } } } }
/// <summary>If present, process the preserveAspectRatio.</summary> /// <param name="context">the svg draw context</param> /// <param name="viewBoxValues">the four values depicting the viewbox [min-x min-y width height]</param> /// <returns>the transformation based on the preserveAspectRatio value</returns> private AffineTransform ProcessAspectRatio(SvgDrawContext context, float[] viewBoxValues) { AffineTransform transform = new AffineTransform(); if (this.attributesAndStyles.ContainsKey(SvgConstants.Attributes.PRESERVE_ASPECT_RATIO)) { Rectangle currentViewPort = context.GetCurrentViewPort(); String preserveAspectRatioValue = this.attributesAndStyles.Get(SvgConstants.Attributes.PRESERVE_ASPECT_RATIO ); IList <String> values = SvgCssUtils.SplitValueList(preserveAspectRatioValue); if (SvgConstants.Values.DEFER.EqualsIgnoreCase(values[0])) { values.JRemoveAt(0); } String align = values[0]; float x = 0f; float y = 0f; float midXBox = viewBoxValues[0] + (viewBoxValues[2] / 2); float midYBox = viewBoxValues[1] + (viewBoxValues[3] / 2); float midXPort = currentViewPort.GetX() + (currentViewPort.GetWidth() / 2); float midYPort = currentViewPort.GetY() + (currentViewPort.GetHeight() / 2); switch (align.ToLowerInvariant()) { case SvgConstants.Values.NONE: { break; } case SvgConstants.Values.XMIN_YMIN: { x = -viewBoxValues[0]; y = -viewBoxValues[1]; break; } case SvgConstants.Values.XMIN_YMID: { x = -viewBoxValues[0]; y = midYPort - midYBox; break; } case SvgConstants.Values.XMIN_YMAX: { x = -viewBoxValues[0]; y = currentViewPort.GetHeight() - viewBoxValues[3]; break; } case SvgConstants.Values.XMID_YMIN: { x = midXPort - midXBox; y = -viewBoxValues[1]; break; } case SvgConstants.Values.XMID_YMAX: { x = midXPort - midXBox; y = currentViewPort.GetHeight() - viewBoxValues[3]; break; } case SvgConstants.Values.XMAX_YMIN: { x = currentViewPort.GetWidth() - viewBoxValues[2]; y = -viewBoxValues[1]; break; } case SvgConstants.Values.XMAX_YMID: { x = currentViewPort.GetWidth() - viewBoxValues[2]; y = midYPort - midYBox; break; } case SvgConstants.Values.XMAX_YMAX: { x = currentViewPort.GetWidth() - viewBoxValues[2]; y = currentViewPort.GetHeight() - viewBoxValues[3]; break; } case SvgConstants.Values.DEFAULT_ASPECT_RATIO: default: { x = midXPort - midXBox; y = midYPort - midYBox; break; } } transform.Translate(x, y); } return(transform); }
/// <summary> /// 每页两张发票 /// </summary> /// <param name="files"></param> /// <param name="outputFile"></param> public static void Merge4(IEnumerable <string> files, string outputFile) { var queue = new ConcurrentQueue <string>(files); var document = new Document(); var margin = 20; try { var writer = PdfWriter.GetInstance(document, new FileStream(outputFile, FileMode.Create)); var size = PageSize.A4.Rotate(); document.Open(); document.SetPageSize(size); PdfContentByte cb = writer.DirectContent; do { document.NewPage(); for (int i = 0; i < 4; i++) { if (TryAppendPage(i) == false) { break; } } } while (queue.Count > 0); bool TryAppendPage(int type) { if (queue.TryDequeue(out var p) == false) { return(false); } var reader = new PdfReader(p); var page = writer.GetImportedPage(reader, 1); AffineTransform af = new AffineTransform(); var scaleHeight = (size.Height - margin * 4) / 2 / page.Height; var scaleWidth = (size.Width - margin * 4) / 2 / page.Width; var scale = Math.Min(scaleHeight, scaleWidth); var height = ((size.Height - margin * 4) / 2 - scale * page.Height) / 2; var width = ((size.Width - margin * 4) / 2 - scale * page.Width) / 2; switch (type) { case 2: default: af.Translate(margin + width, margin + height); break; case 3: af.Translate(margin + width + size.Width / 2, margin + height); break; case 0: af.Translate(margin + width, margin + height + size.Height / 2); break; case 1: af.Translate(margin + width + size.Width / 2, margin + height + size.Height / 2); break; } af.Scale(scale, scale); cb.AddTemplate(page, af); return(true); } } catch (Exception e) { throw e; } finally { document.Close(); } }
static int borderThickness = 1; // It's just 1. Won't really change, but whatever. If you change it, things will get fucky. public static bool MakePDF(Ragecomic comic, string pdffile) { using (System.IO.FileStream fs = new FileStream(pdffile, FileMode.Create)) { int rows = (int)Math.Ceiling((double)comic.panels / 2); int width = rowWidth * 2 + borderThickness * 3; int height = rowHeight * rows + borderThickness * rows + borderThickness; // 239 per row, plus 1 pixel border per row, plus 1 pixel extra border ZipFile drawImageZip = new ZipFile(); bool hasDrawImages = comic.items.getDrawImageCount() > 0; if (hasDrawImages) { drawImageZip.Dispose(); string addition = ""; int nr = 1; while (File.Exists(pdffile + ".drawimages" + addition + ".zip")) { addition = "_" + (nr++).ToString(); } drawImageZip = new ZipFile(pdffile + ".drawimages" + addition + ".zip"); } // Create an instance of the document class which represents the PDF document itself. Rectangle pageSize = new Rectangle(width, height); Document document = new Document(pageSize, 0, 0, 0, 0); // Create an instance to the PDF file by creating an instance of the PDF // Writer class using the document and the filestrem in the constructor. PdfWriter writer = PdfWriter.GetInstance(document, fs); document.AddAuthor("Derp"); document.AddCreator("RagemakerToPDF"); document.AddKeywords("rage, comic"); document.AddSubject("A rage comic"); document.AddTitle("A rage comic"); // Open the document to enable you to write to the document document.Open(); PdfContentByte cb = writer.DirectContent; // Fill background with white Rectangle rect = new iTextSharp.text.Rectangle(0, 0, width, height); rect.BackgroundColor = new BaseColor(255, 255, 255); cb.Rectangle(rect); // Draw grid on bottom if it isn't set to be on top. if (!comic.gridAboveAll && comic.showGrid) { DrawGrid(cb, width, height, rows, comic); } //List<MyMedia.FontFamily> families = MyMedia.Fonts.SystemFontFamilies.ToList(); // This was a neat idea, but it's much too slow //List<string> files = FontFinder.GetFilesForFont("Courier New").ToList(); //string filename = FontFinder.GetSystemFontFileName(families[0].) //Draw.Font testFont = new Draw.Font(new Draw.FontFamily("Courier New"),12f,Draw.FontStyle.Regular | Draw.FontStyle.Bold); string courierPath = FontFinder.GetSystemFontFileName("Courier New", true); string courierBoldPath = FontFinder.GetSystemFontFileName("Courier New", true, Draw.FontStyle.Bold); string tahomaPath = FontFinder.GetSystemFontFileName("Tahoma", true, Draw.FontStyle.Bold); // Define base fonts Font[] fonts = new Font[3]; fonts[0] = new Font(BaseFont.CreateFont(courierPath, BaseFont.CP1252, BaseFont.EMBEDDED)); fonts[1] = new Font(BaseFont.CreateFont(courierBoldPath, BaseFont.CP1252, BaseFont.EMBEDDED)); fonts[2] = new Font(BaseFont.CreateFont(tahomaPath, BaseFont.CP1252, BaseFont.EMBEDDED)); /*fonts[0] = BaseFont.CreateFont("fonts/TRCourierNew.ttf", BaseFont.CP1252, BaseFont.EMBEDDED); * fonts[1] = BaseFont.CreateFont("fonts/TRCourierNewBold.ttf", BaseFont.CP1252, BaseFont.EMBEDDED); * fonts[2] = new Font(BaseFont.CreateFont("fonts/Tahoma-Bold.ttf", BaseFont.CP1252, BaseFont.EMBEDDED));*/ int drawimageindex = 0; int index = 0; foreach (var item in comic.items) { if (item is Face) { Face face = (Face)item; Image pdfImage; System.Drawing.Image faceImage; // If mirroring is necessary, we have to read the image via C# and use RotateFlip, as iTextSharp doesn't support mirroring. if (face.mirrored) { // If it's a JPEG, open it with Flux.JPEG.Core, because the internal JPEG decoder (and also LibJpeg.NET) creates weird dithering artifacts with greyscale JPGs, which some of the rage faces are. if (Path.GetExtension(face.file).ToLower() == ".jpeg" || Path.GetExtension(face.file).ToLower() == ".jpg") { FileStream jpegstream = File.OpenRead("images/" + face.file); FluxJpeg.Core.DecodedJpeg myJpeg = new JpegDecoder(jpegstream).Decode(); // Only use this JPEG decoder if the colorspace is Gray. Otherwise the normal one is just fine. if (myJpeg.Image.ColorModel.colorspace == FluxJpeg.Core.ColorSpace.Gray) { myJpeg.Image.ChangeColorSpace(FluxJpeg.Core.ColorSpace.YCbCr); faceImage = myJpeg.Image.ToBitmap(); } else { faceImage = System.Drawing.Image.FromFile("images/" + face.file); } } else { faceImage = System.Drawing.Image.FromFile("images/" + face.file); } // Apply mirroring faceImage.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipX); pdfImage = Image.GetInstance(faceImage, System.Drawing.Imaging.ImageFormat.Png); } else { // Just let iTextSharp handle it if no mirroring is required. Will also save space (presumably) pdfImage = Image.GetInstance("images/" + face.file); } pdfImage.ScalePercent(face.scalex * 100, face.scaley * 100); pdfImage.Rotation = -(float)Math.PI * face.rotation / 180.0f; pdfImage.SetAbsolutePosition(item.x, (height - item.y) - pdfImage.ScaledHeight); // Set opacity to proper value if (face.opacity < 1) { PdfGState graphicsState = new PdfGState(); graphicsState.FillOpacity = face.opacity; cb.SetGState(graphicsState); } cb.AddImage(pdfImage); // Set back to normal if (face.opacity < 1) { PdfGState graphicsState = new PdfGState(); graphicsState.FillOpacity = 1f; cb.SetGState(graphicsState); } } else if (item is DrawImage) { DrawImage drawimage = (DrawImage)item; drawImageZip.AddEntry("drawimage_" + (drawimageindex++).ToString() + ".png", drawimage.imagedata); System.Drawing.Image pngImage = System.Drawing.Image.FromStream(new MemoryStream(drawimage.imagedata)); Image pdfImage = Image.GetInstance(pngImage, System.Drawing.Imaging.ImageFormat.Png); // Rotation is NOT to be applied. Ragemaker actually has a bug that causes it to save rotated images in their rotated form, but save the rotation value anyway // Thus rotating the image by the rotation value will actually rotate them double compared to what they originally looked like // The irony is that ragemaker *itself* cannot properly load an xml it created with this rotation value, as it will also apply the rotation // As such, this tool is currently the only way to correctly display that .xml file as it was originally meant to look, not even ragemaker itself can properly load it again. //pdfImage.Rotation = -(float)Math.PI * item.rotation / 180.0f; pdfImage.SetAbsolutePosition(item.x, (height - item.y) - pdfImage.ScaledHeight); // Opacity likewise seems to be baked in, and in fact the opacity value doesn't even exist. // Implementing it anyway, in case it ever becomes a thing. if (drawimage.opacity < 1) { PdfGState graphicsState = new PdfGState(); graphicsState.FillOpacity = drawimage.opacity; cb.SetGState(graphicsState); } cb.AddImage(pdfImage); // Set back to normal if (drawimage.opacity < 1) { PdfGState graphicsState = new PdfGState(); graphicsState.FillOpacity = 1f; cb.SetGState(graphicsState); } } else if (item is Text) { int padding = 4; Text text = (Text)item; // Create template PdfTemplate xobject = cb.CreateTemplate(text.width, text.height); // Background color (if set) if (text.bgOn) { Rectangle bgRectangle = new Rectangle(0, 0, text.width, text.height); System.Drawing.Color bgColor = System.Drawing.ColorTranslator.FromHtml(text.bgColor); rect.BackgroundColor = new BaseColor(bgColor.R, bgColor.G, bgColor.B, (int)Math.Floor(text.opacity * 255)); xobject.Rectangle(rect); } // Create text Rectangle textangle = new Rectangle(padding, 0, text.width - padding, text.height); ColumnText ct = new ColumnText(xobject); ct.SetSimpleColumn(textangle); Paragraph paragraph = new Paragraph(text.text); Font myFont = fonts[text.style]; // More specific treatment if it's an AnyFont element which allows the user to select any font and styles, not just the normal 3 presets // This isn't perfect, as the current FontFinder doesn't indicate whether he actually found an Italic/Bold typeface, hence it's not possible // to determine whether faux-italic/faux-bold should be applied. Currently it will only work correctly if each used font has a specific typeface // for the needed styles (bold or italic), otherwise incorrect results. // TODO Fix, for example let FontFinder return array of strings, one of which is indicating the suffix that was found. if (text is AnyFontText) { AnyFontText anyfont = (AnyFontText)text; string fontname = anyfont.font; string fontfile = ""; if (anyfont.bold) { fontfile = FontFinder.GetSystemFontFileName(fontname, true, Draw.FontStyle.Bold); int fontStyle = 0; if (anyfont.italic) { fontStyle |= Font.ITALIC; } if (anyfont.underline) { fontStyle |= Font.UNDERLINE; } myFont = new Font(BaseFont.CreateFont(fontfile, BaseFont.CP1252, BaseFont.EMBEDDED), 100f, fontStyle); } else if (anyfont.italic) { fontfile = FontFinder.GetSystemFontFileName(fontname, true, Draw.FontStyle.Italic); int fontStyle = 0; if (anyfont.underline) { fontStyle |= Font.UNDERLINE; } myFont = new Font(BaseFont.CreateFont(fontfile, BaseFont.CP1252, BaseFont.EMBEDDED), 100f, fontStyle); } else { fontfile = FontFinder.GetSystemFontFileName(fontname, true, Draw.FontStyle.Regular); int fontStyle = 0; if (anyfont.underline) { fontStyle |= Font.UNDERLINE; } myFont = new Font(BaseFont.CreateFont(fontfile, BaseFont.CP1252, BaseFont.EMBEDDED), 100f, fontStyle); } } myFont.Size = text.size; System.Drawing.Color color = (System.Drawing.Color)(new System.Drawing.ColorConverter()).ConvertFromString(text.color); myFont.Color = new BaseColor(color.R, color.G, color.B, (int)Math.Floor(text.opacity * 255)); paragraph.Font = myFont; paragraph.Alignment = text.align == Text.ALIGN.LEFT ? PdfContentByte.ALIGN_LEFT : (text.align == Text.ALIGN.RIGHT ? PdfContentByte.ALIGN_RIGHT : PdfContentByte.ALIGN_CENTER); paragraph.SetLeading(0, 1.12f); ct.AddElement(paragraph); ct.Go(); // Angle to radians float angle = (float)Math.PI * text.rotation / 180.0f; // Calculate Bounding Box size for correct placement later GraphicsPath gp = new GraphicsPath(); gp.AddRectangle(new System.Drawing.Rectangle(0, 0, (int)Math.Round(text.width), (int)Math.Round(text.height))); Matrix translateMatrix = new Matrix(); translateMatrix.RotateAt(text.rotation, new System.Drawing.PointF(text.width / 2, text.height / 2)); gp.Transform(translateMatrix); var gbp = gp.GetBounds(); float newWidth = gbp.Width, newHeight = gbp.Height; // Create correct placement // Background info: I rotate around the center of the text box, thus the center of the text box is what I attempt to place correctly with the initial .Translate() AffineTransform transform = new AffineTransform(); transform.Translate(item.x + newWidth / 2 - text.width / 2, height - (item.y + newHeight / 2 - text.height / 2) - text.height); transform.Rotate(-angle, text.width / 2, text.height / 2); cb.AddTemplate(xobject, transform); } index++; } if (comic.gridAboveAll && comic.showGrid) { DrawGrid(cb, width, height, rows, comic); } //document.Add(new Paragraph("Hello World!")); // Close the document document.Close(); // Close the writer instance writer.Close(); // Always close open filehandles explicity fs.Close(); if (hasDrawImages) { drawImageZip.Save(); } drawImageZip.Dispose(); } return(false); }