Resize existing image in DocX using OpenXML sdk - c#

Got template docx with image placeholder which replaced by correct picture.
private void SetImagePartData(ImagePart imagePart, byte[] data)
{
if (imagePart != null)
{
using (var writer = new BinaryWriter(imagePart.GetStream()))
{
writer.Write(data);
}
}
}
but it preserves placeholder size. How to change it to actual image size? Byte array is aqquared from image on server, so size is known.

If you mean a content control with your placeholder you can use following code I once needed:
//Get SdtElement (can be a block, run... so I use the base class) with corresponding Tag
SdtElement block = doc.MainDocumentPart.Document.Body.Descendants<SdtElement>()
.FirstOrDefault(sdt => sdt.SdtProperties.GetFirstChild<Tag>()?.Val == contentControlTag);
//Get First drawing Element and get the original sizes of placeholder SDT
//I use SDT placeholder size as maximum size to calculate picture size with correct ratios
Drawing sdtImage = block.Descendants<Drawing>().First();
double sdtWidth = sdtImage.Inline.Extent.Cx;
double sdtHeight = sdtImage.Inline.Extent.Cy;
double sdtRatio = sdtWidth / sdtHeight;
*Calculate final width/height of image*
//Resize picture placeholder
sdtImage.Inline.Extent.Cx = finalWidth;
sdtImage.Inline.Extent.Cy = finalHeight;
//Change width/height of picture shapeproperties Transform
//This will override above height/width until you manually drag image for example
sdtImage.Inline.Graphic.GraphicData
.GetFirstChild<DocumentFormat.OpenXml.Drawing.Pictures.Picture>()
.ShapeProperties.Transform2D.Extents.Cx = finalWidth;
sdtImage.Inline.Graphic.GraphicData
.GetFirstChild<DocumentFormat.OpenXml.Drawing.Pictures.Picture>()
.ShapeProperties.Transform2D.Extents.Cy = finalHeight;
But you can use it if you are just using an image in your word document too. You just need to locate the correct Drawing element which contains the reference to your imagepart. Then you can use the bottom part of the code to adjust the image size. It's important you adjust both the Transform2D x and y as well as the Inline x and y or the image size won't be changed.

Related

SVG not rendering text within a shape

I am using an SVGDocument to convert a graph created using Mermaid to bitmap format so it can be copied to the clipboard, saved as a bitmaps to disk etc. The code I am using is shown below. I fill the bitmap with white first as if not the image has a light grey background when copied to the clipboard.
var HTMLDocument = new HtmlAgilityPack.HtmlDocument();
HTMLDocument.LoadHtml(HTML);
// Get the SVG representing the diagram
var SVGElement = HTMLDocument.DocumentNode.Descendants("svg").FirstOrDefault();
if (SVGElement == null)
{
return;
}
// Create a SVG document from the svg element in the HTML
var Document = SvgDocument.FromSvg<SvgDocument>(SVGElement.OuterHtml);
// Get the size of the SVG element so we can create a bitmap
// to match
var Bounds = Document.Bounds;
// Adjust the width and height to take account of the position
var Width = Bounds.Width + Bounds.Left + 10;
var Height = Bounds.Height + Bounds.Top + 100;
// Create a new bitmap of the correct size
var Bitmap = new Bitmap((int)Width, (int)Height);
// Fill it with white and then draw the SVG diagram
using (var BitMapGraphics = Graphics.FromImage(Bitmap))
{
BitMapGraphics.FillRectangle(new SolidBrush(Color.White), 0, 0, Width, Height);
Document.Draw(BitMapGraphics);
}
However, when pasted from the clipboard, the image does not show any text within the graph shapes. The original Mermaid diagram is:
When pasted from the clipboard using the bitmap created above becomes:
Any thoughts on why the text within the shapes is not being rendered would be much appreciated.

How to scale text within a fixed rectangle with itext7?

I'm trying to make a pdf document with itext7 in c# which should have fixed rectangles containing varying text that should scale within the boundaries of the (invisible) rectangles.
I have tried to find if there's automatic scaling, but so far only found auto-scaling for formfields. Since the pdf will be used for plotting text, formfields are of no use.
Code below is a snippet placing a 'box' with fixed dimensions, where all the text should be shown scaled (on one line)
float fontSize = 22f;
Text lineTxt = new Text("A VERY LONG TEXT SHOULD BE SCALED").SetFont(lineFont).SetFontSize(fontSize);
iText.Kernel.Geom.Rectangle lineTxtRect = new iText.Kernel.Geom.Rectangle(100, posHeight - 200, (float)plotline.producttype_plotmaxwidthpts, (float)plotline.producttype_plotmaxheightpts);
Div lineDiv = new Div();
lineDiv.SetMaxHeight((float)plotline.producttype_plotmaxheightpts);
lineDiv.SetWidth((float)plotline.producttype_plotmaxwidthpts);
lineDiv.SetHeight((float)plotline.producttype_plotmaxheightpts);
lineDiv.SetVerticalAlignment(VerticalAlignment.MIDDLE);
lineDiv.SetBorder(new DashedBorder(1));
Paragraph linePara = new Paragraph().Add(lineTxt).
SetTextAlignment(iText.Layout.Properties.TextAlignment.CENTER).
SetBorder(new DottedBorder(1)).
SetMultipliedLeading(0.7f).
SetMaxHeight((float)plotline.producttype_plotmaxheightpts).
SetHeight((float)plotline.producttype_plotmaxheightpts);
lineDiv.Add(linePara);
new Canvas(PageCanvas, pdf, lineTxtRect).Add(lineDiv).SetBorder(new SolidBorder(1f));
Layout module of iText 7 allows you to simulate rendering of an element (by creating the renderer tree from the element and then using Layout method) and check whether it fits the given area (by checking LayoutResult object). Thus what you can do is check whether the text fits into your fixed rectangle with the given font size. Then you can just do a binary search on the font size.
Here is a sample code:
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName));
Text lineTxt = new Text("A VERY LONG TEXT SHOULD BE SCALED");
iText.Kernel.Geom.Rectangle lineTxtRect =
new iText.Kernel.Geom.Rectangle(100,200,100,100);
Div lineDiv = new Div();
lineDiv.SetVerticalAlignment(VerticalAlignment.MIDDLE);
lineDiv.SetBorder(new DashedBorder(1));
Paragraph linePara =
new Paragraph()
.Add(lineTxt)
.SetTextAlignment(iText.Layout.Properties.TextAlignment.CENTER)
.SetBorder(new DottedBorder(1))
.SetMultipliedLeading(0.7f);
lineDiv.Add(linePara);
// 1 is the font size that is definitely small enough to draw all the text
float fontSizeL = 1;
// 20 is the maximum value of the font size you want to use
float fontSizeR = 20;
Canvas canvas =
new Canvas(
new PdfCanvas(pdfDocument.AddNewPage()),
pdfDocument,
lineTxtRect);
// Binary search on the font size
while (Math.Abs(fontSizeL - fontSizeR) > 1e-1) {
float curFontSize = (fontSizeL + fontSizeR) / 2;
lineDiv.SetFontSize(curFontSize);
// It is important to set parent for the current element renderer
// to a root renderer.
IRenderer renderer =
lineDiv.CreateRendererSubTree()
.SetParent(canvas.GetRenderer());
LayoutContext context =
new LayoutContext(
new LayoutArea(1, lineTxtRect));
if (renderer.Layout(context).GetStatus() == LayoutResult.FULL) {
// we can fit all the text with curFontSize
fontSizeL = curFontSize;
} else {
fontSizeR = curFontSize;
}
}
// Use the biggest font size that is still small enough to fit all the
// text.
lineDiv.SetFontSize(fontSizeL);
canvas.Add(lineDiv);
pdfDocument.Close();

how to get pdf image orientation using itextsharp

Im editing a pdf. The client wants the image inside pdf to be resize and rotated.
so what i did is to extract the image inside the pdf to be able to manipulate the image then insert it again to the the pdf(replacing the old one)
here is the code where i got the code for extracting image
https://psycodedeveloper.wordpress.com/2013/01/10/how-to-extract-images-from-pdf-files-using-c-and-itextsharp/
but when i extract the image to image is rotated 180 degree
i even used the free Spire.PDF to extract the image but the extracted image of the spire.pdf is rotated 90 degree. so how can i get the image orientation of the pdf. so that i can make the image to its original orientation. thank you
There are two relevant factors deciding on the effective rotation of an image, the current transformation matrix at the time the image is drawn (which also fixes the dimensions of the image) and the page rotation.
You can determine these values as shown below in the code you refer to:
...
public static Dictionary<string, System.Drawing.Image> ExtractImages(string filename)
{
var images = new Dictionary<string, System.Drawing.Image>();
using (var reader = new PdfReader(filename))
{
var parser = new PdfReaderContentParser(reader);
ImageRenderListener listener = null;
for (var i = 1; i <= reader.NumberOfPages; i++)
{
// v-- Determine clockwise rotation of page
Console.WriteLine("Page {1} is rotated by {0}°.\n", reader.GetPageRotation(i), i);
// ^-- Determine clockwise rotation of page
parser.ProcessContent(i, (listener = new ImageRenderListener()));
var index = 1;
[...]
}
return images;
}
}
...
public void RenderImage(ImageRenderInfo renderInfo)
{
// v-- Determine transformation matrix of image
Matrix ctm = renderInfo.GetImageCTM();
Console.WriteLine("Found image with transformation matrix:\n{0}\n", ctm);
// ^-- Determine transformation matrix of image
PdfImageObject image = renderInfo.GetImage();
PdfName filter = (PdfName)image.Get(PdfName.FILTER);
[...]
}
...
The output in your case:
Page 1 is rotated by 270°.
Found image with transformation matrix:
792,0001 0 0
0 612 0
0 0 1
Found 1 images on page 1.
Thus, the transformation matrix obviously only scales the image to the appropriate dimensions without rotating it but the page itself is defined to be shown rotated by 270°.
This corresponds to my observations. In particular in contrast to what you said:
but when i extract the image to image is rotated 180 degree
I get an image from your code which has to be rotated by 270° clockwise to be upright.
If you indeed get an image rotated by 180°, you should check the version of iTextSharp you use. The archive on the web site you refer to contains a fairly old version, 5.3.5.0, and bugs might have been fixed in the meantime.

Barcode i25 using ItextSharp

i am using BarcodeInter25 class to make barcode. I am able to make it but its just blur how can it become more sharp ??
also its background white colour is not completely white
My Code:
BarcodeInter25 code25 = new BarcodeInter25();
Rectangle r = new iTextSharp.text.Rectangle(38, 152);
code25.ChecksumText = false;
code25.Code = "some digits";
code25.BarHeight = 2
System.Drawing.Image i = code25.CreateDrawingImage(System.Drawing.Color.Black, System.Drawing.Color.White);
MemoryStream ms = new MemoryStream();
i.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
Image img = Image.GetInstance(ms.ToArray());
ms.Dispose();
Looking at your code, it should be obvious why the barcode is blurry. You convert it to a System.Drawing.Image (making it a raster image) and then you convert it to an iTextSharp.text.Image (but by then the image is already blurry).
The correct way to achieve what you want, is to create an iTextSharp.text.Image straight from the barcode (do not pass through System.Drawing.Image). This can be done like this:
BarcodeInter25 code25 = new BarcodeInter25();
Rectangle r = new iTextSharp.text.Rectangle(38, 152);
code25.ChecksumText = false;
code25.Code = "some digits";
code25.BarHeight = 2;
PdfContentByte cb = writer.DirectContent;
Image img = code25.CreateImageWithBarcode(cb, null, null);
Now the Image object won't be a raster image (with pixels that make the lines blurry), but it will be a true vector image (no pixels, but instructions such as moveTo(), lineTo() and stroke()). Vector data has the advantage that it is resolution independent: you can zoom in and zoom out as much as you want, it will always be sharp.
This is explained in Chapter 10 of my book where you'll find the Barcodes example. In that chapter, you'll also discover the setFont() (or in iTextSharp the Font property). I quote from the API documentation:
public void setFont(BaseFont font)
Sets the text font.
Parameters:
font - the text font. Set to null to suppress any text
So if you don't want to see any text, you can add the following line to the above code snippet:
code25.Font = null;
You should avoid re-sizing by any means. The output is most likely pixel-perfect but when you scale it up/down a bilinear filter will smooth it rendering it blurry.
I had the same exact problem by embedding a QRC code in a PDF and solved it by avoiding a resize.
If you really need a different size apply it programmatically in code by using the correct interpolation algorithm.

PdfSmartCopy is copying the contents at the bottom (footer) of the new PDF file

I have a function which is cropping the specific part of the pdf file and adding it into the new Pdf file but the main problem that i am getting is that it is showing the cropped part of the page into the bottom (footer) of the newly created pdf file.
Here is the code..
public static void CropPdfFile(string sourceFilePath, string outputFilePath)
{
// Allows PdfReader to read a pdf document without the owner's password
PdfReader.unethicalreading = true;
// Reads the PDF document
using (PdfReader pdfReader = new PdfReader(sourceFilePath))
{
// Set which part of the source document will be copied.
// PdfRectangel(bottom-left-x, bottom-left-y, upper-right-x, upper-right-y)
PdfRectangle rect = new PdfRectangle(0f, 9049.172f, 594.0195f, 700.3f);
using (var output = new FileStream(outputFilePath, FileMode.CreateNew, FileAccess.Write))
{
// Create a new document
using (Document doc = new Document())
{
// Make a copy of the document
PdfSmartCopy smartCopy = new PdfSmartCopy(doc, output);
// Open the newly created document
doc.Open();
// Loop through all pages of the source document
for (int i = 4; i <= pdfReader.NumberOfPages; i++)
{
// Get a page
var page = pdfReader.GetPageN(i);
// Apply the rectangle filter we created
page.Put(PdfName.CROPBOX, rect);
page.Put(PdfName.MEDIABOX, rect);
// Copy the content and insert into the new document
smartCopy.SetLinearPageMode();
var copiedPage = smartCopy.GetImportedPage(pdfReader, i);
smartCopy.AddPage(copiedPage);
}
// Close the output document
doc.Close();
}
}
}
Please help me to solve this..
The size of a PDF page (expressed in user units) depends on the value of the mediabox. For instance: The media box of an A4 page is usually defined like this [0 0 595 842]
In this case, the origin of the coordinate system (0, 0) coincides with the lower-left corner. The coordinate of the upper right corner is (595, 842).
Another possible value for an A4 page would be [0 842 595 1684]. Same width (595 user units), same height (1684 - 842 = 842 user units), but the lower-left corner now has the coordinate (0, 842) and the coordinate of the upper-right corner is (595, 1684).
You write that you create a PdfRectangle using these parameters: (bottom-left-x, bottom-left-y, upper-right-x, upper-right-y). However, you're using these hard-coded values: 0f, 9049.172f, 594.0195f, 700.3f.
Your lower-left-y (9049.172) is at a higher position than your upper-right-y (700.3). This doesn't really make sense. Hence: you should consider changing that value to something that does make sense. What value that should be, is a question only you can answer since only you know the value of the MediaBox of the file you want to crop.
In your comment, you explain that your PDF is an A4 page. You can check this by using the PdfReader method named getPageSize(). If you want to crop the page so that you only see the header of your document, you need to use something like this:
PdfRectangle rect = new PdfRectangle(0f, 842 - x, 595, 842);
Where x is the height of the header. For instance, if the header is 100 user units, then you'd need:
PdfRectangle rect = new PdfRectangle(0f, 742, 595, 842);
It is unclear why you're always talking about 100px. If you want to convert pixels to points, please read Convert Pixels to Points
Using the formula mentioned there 100 pixels equals 75 points.

Categories