I am creating a single pdf page with 6 images in a table in separate cells, even though I am setting the images height and width on the server side exactly the same with ScaleToFit the images sizes are not the same on the pdf page.
Is there anyway to get all the images the exact same size?
PdfPTable table = new PdfPTable(3);
table.HorizontalAlignment = Element.ALIGN_CENTER;
table.WidthPercentage = 100;
table.TotalWidth = 698.5f;
table.LockedWidth = true;
table.SetWidths(new float [] {1,1,1});
iTextSharp.text.Image img1 = iTextSharp.text.Image.GetInstance("C:\\Users\\DaNet\\Downloads\\image.jpg");
img1.Alignment = iTextSharp.text.Image.ALIGN_CENTER;
img1.ScaleToFit(120f, 155.25f);
iTextSharp.text.pdf.PdfPCell imgCell1 = new iTextSharp.text.pdf.PdfPCell(img1);
imgCell1.HorizontalAlignment = Element.ALIGN_CENTER;
imgCell1.BackgroundColor = new BaseColor(255, 255, 255);
imgCell1.Border = iTextSharp.text.Rectangle.NO_BORDER;
table.AddCell(imgCell1);
Two things.
First, see this post about wrapping the Image in a Chunk. Basically:
iTextSharp.text.pdf.PdfPCell imgCell1 = new iTextSharp.text.pdf.PdfPCell();
imgCell1.AddElement(new Chunk(img1, 0, 0));
Second, if you want the exact same size then you want to use ScaleAbsolute instead of ScaleToFit. The latter keeps the aspect ratio of the image so a 100x200 image scaled to fit 50x50 would come out as 25x50.
img1.ScaleAbsolute(120f, 155.25f);
Related
When i run the program, i get a different amount of images(from 20 all the way up to 2000) and i would like to merge all of these images into one image which would preferably be a square.
This is the code i have for getting the file images(the images are in URL format)
int ximg = 1;
int totalImgs = richTextBox1.Lines.Count();
while (ximg < totalImgs)
{
System.Net.WebRequest request = System.Net.WebRequest.Create(richTextBox1.Lines[ximg]);
System.Net.WebResponse response = request.GetResponse();
System.IO.Stream responseStream =
response.GetResponseStream();
Bitmap image = new Bitmap(responseStream);
List<Image> fileList = new List<Image>();
fileList.Add(image);
ximg++;
}
Also every single image has a title in a different richtextbox which i would like to know if it is possible to add a title under the image (richtextbox1.lines[1] (image) = richtextbox2.lines[1] (title)). Is it possible to add a picture as a background picture when merging(to the square image I want to generate)? Is it possible to add a border on every single image picture and merge them with the border? How can the code calculate when its time to change line and start adding images in the next row?
I've tried this code, but it works only if you know the amount of images you want to merge.
Bitmap bitmap = new Bitmap(image1.Width + image2.Width, Math.Max(image1.Height, image2.Height));
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(image1, 0, 0);
g.DrawImage(image2, image1.Width, 0);
}
bitmap.Save("merged.bmp");
I would do it with photoshop but when there are 2000 images to merge together, I just do not have the time.
Is there any way to accomplish such task? Any references would be appreciated!
I have mentioned it above :) !
This solution will create a mosaic of the images from left to right, top to bottom. It does not do anything to maximize the available space. It also assumes that you have a max width and height for the finished image, since it's not realistic to support an arbitrary size.
// where we store the finished mosaic
var mosaic = new Bitmap(maxWidth, maxHeight);
// track the location where we are drawing each image
var imageCorner = new Point(0,0);
// track the height of the current row
var currentRowHeight = 0;
// track the width and height of the mosaic as it grows.
var mosaicWidth = 0;
var mosaicHeight = 0;
using (var g = Graphics.FromImage(bitmap))
{
var borderPen = new Pen(Brushes.Black) { Width = 2 };
var labelFont = new Font("Arial", 10);
var labelBrush = new SolidBrush(Color.Black);
foreach (var image in imageList)
{
if (imageCorner.X + image.Width > maxWidth)
{
// if adding the image to the current row would make it too wide,
// move to the next row by resetting X to zero and adding the
// height of the tallest image to Y
imageCorner.X = 0;
imageCorner.Y += currentRowHeight;
// since this is a new row, it's current height is zero
currentRowHeight = 0;
}
// if adding this image would put us past the
// height of the image, then we're out of room.
if (imageCorner.Y + image.Height > maxHeight)
{
// this skips images if there's no room for them in
// the mosaic, you may want to do something different
Trace.WriteLine($"Image is {image.Height} pixels tall, but only {maxHeight - mosaicHeight} pixels available.");
continue;
}
// draw the image
g.DrawImage(image, imageCorner);
// draw the border
g.DrawRectangle(borderPen,
imageCorner.X, imageCorner.Y,
image.Width, image.Height)
// draw the label
g.DrawText("Image Label", labelBrush, imageCorner.X, imageCorner.Y)
// now that we've drawn the image, we need to shift to the right
imageCorner.X += image.Width;
// row height is the height of the tallest image so far in this row
currentRowHeight = Math.Max(image.Height, currentRowHeight);
// track the total height of the mosaic
mosaicHeight = imageCorner.Y + currentRowHeight;
// mosaic width is just the widest row in the mosaic
mosaicWidth = Math.Max(imageCorner.X, widthOfWidestRow);
}
}
// trim off the parts of the mosaic we didn't fill
mosaic = mosaic.Clone(new Rectangle(0, 0, mosaicWidth, mosaicHeight);
mosaic.Save("merged.bmp");
If you wanted to minimize wasted space, you could sort your list of images in different ways, or calculate ahead of time what a good width and height for the mosaic would be.
I am using ClosedXML (https://github.com/ClosedXML/ClosedXML) for creating an excel file in my C# MVC Controller. As per the documentation in https://github.com/closedxml/closedxml/wiki/How-can-I-insert-an-image, I have inserted an image in a cell and merged that cell with to cells on the right side.My code is as follows:
For adding image
var imagePath = #"c:\myFolder\image.jpg";
var image = MyWorkSheet.AddPicture(imagePath ) .MoveTo((MyWorkSheet.Cell(3,1).Address)) .Scale(0.2);
image.Width = 50;
image.Height = 50;
For merging cell
MyWorkSheet.Range(MyWorkSheet.Cell(3,1).Address, MyWorkSheet.Cell(3, 3).Address).Merge();
But the image lies on the upper left corner of the cell. I cant find any web source explaining how to center the image in the cell range. Anyone please help me.
You have to move your image with an offset from the cell. To do that, you have to calculate that offset.
Column width is returned in point (not in pixel). You have to convert it to pixel to compare with image pixel width.
So you can do :
int iColumnWidth = (MyWorkSheet.Column(1).Width - 1) * 7 + 12; // To convert column width in pixel unit.
int xOffset = (iColumnWidth - image.Width) / 2;
int yOffset = 0;
image.MoveTo(MyWorkSheet.Cell(3,1), New Point(xOffset, yOffset));
You need to do some manual calculation based on the with respect to image and cell size.
Workbook wb = new Workbook();
Worksheet sheet = wb.Worksheets[0];
sheet.Range["A1"].Text = "Align Picture Within A Cell:";
sheet.Range["A1"].Style.VerticalAlignment = VerticalAlignType.Top;
string picPath = #"C:\Users\Administrator\Desktop\scenery.jpg";
ExcelPicture picture = sheet.Pictures.Add(1, 1, picPath);
sheet.Columns[0].ColumnWidth = 50;
sheet.Rows[0].RowHeight = 150;
picture.LeftColumnOffset =100;
picture.TopRowOffset = 25;
wb.SaveToFile("AlignPicture.xlsx", ExcelVersion.Version2013);
I want to create a LiveTile. The text that will be displayed comes from a different backend so I don't have access or control. So I wanted to prerender the text (like this: http://developer.nokia.com/community/wiki/Custom_Live_Tile_with_Formatted_Text).
But I wanted to go 1 step further and Wrap and Trim the string as it MIGHT become longer.
A short version of the code is:
var wbmp = new WriteableBitmap();
var grid = new Grid();
grid.Width = pWidth;
grid.Height = pHeight;
var tblk = new TextBlock();
tblk.Text = pString;
tblk.Width = pWidth; // 691 or 336
tblk.Height = pHeight; // 336
tblk.TextTrimmin = TextTrimming.WordEllipsis;
tblk.TextWrappin = TextWrapping.Wrap;
grid.Children.Add(tblk);
wbmp.Render(grid, null);
wbmp.Invalidate();
This didn't trim the string. Then I read a bit about grids and texttrimming and I already have one xaml-part that does wirk woth both Oo So I did something like this:
var rowDef = new RowDefinition();
rowDef.Height = GridLength(1, GridUnitType.Auto);
grid.RowDefinitions.Add(rowDef);
rowDef = new RowDefinition();
rowDef.Height = GridLength(1, GridUnitType.Star);
grid.RowDefinitions.Add(rowDef);
tblk.SetValue(Grid.RowProperty, 0); // or 1 // or Grid.SetRow(tblk, 1);
and tried different combinations of Rows and Columns, Auto, Pixel and Stars. But nothing works. As the grid is not bound to anything else, "is flying" in the void, it doesn't create multiple rows. If I copy the same text in 4 colours and put it in 4 rows it only shows the upper one, because all others are exactly underneath..
What am I missing here? It can't be impossible to Trim and Wrap at the same time Oo
You have to call the Measure and Arrange methods of the UIElement to actually get the desired image. So here is the full code:
var grid = new Grid();
grid.Width = 80;
grid.Height = 80;
var tblk = new TextBlock();
tblk.Text = "Long enough text to show you text wrapping and trimming at the same time in this example.";
tblk.Width = 80;
tblk.Height = 80;
tblk.TextTrimming = TextTrimming.WordEllipsis;
tblk.TextWrapping = TextWrapping.Wrap;
grid.Children.Add(tblk);
grid.Measure(new Size(80, 80));
grid.Arrange(new Rect(0, 0, 80, 80));
grid.InvalidateVisual();
var renderTargetBitmap = new RenderTargetBitmap(80, 80, 96, 96, PixelFormats.Default);
renderTargetBitmap.Render(tblk);
After that you can use the renderTargetBitmap as a Source for an Image element, and you will see that the text is both trimmed and wrapped.
I am using GhostScript.Net to rasterize PDF to page images before sending the page images to the printer. I am doing this so that I can always rasterize to 300dpi. This allows me to print the PDF in a reasonable amount of time regardless of the size of any image in the PDF (mainly scanned PDFs).
However, it strikes me that in some cases there will not be a need to rasterize as high as 300dpi. It may be possible to rasterize to 200dpi or even 100dpi depending on the content of the page.
Has anyone attempted to determine the maximum DPI for the content of a PDF page? Perhaps using iTextSharp?
My current code is this:
var dpiList = new List<int> {50, 100, 150, 200, 250, 300, 350, 400, 450, 500};
string inputPdfPath = #"C:\10page.pdf";
string outputPath = #"C:\Print\";
var lastInstalledVersion =
GhostscriptVersionInfo.GetLastInstalledVersion(
GhostscriptLicense.GPL | GhostscriptLicense.AFPL,
GhostscriptLicense.GPL);
var rasterizer = new GhostscriptRasterizer();
rasterizer.Open(inputPdfPath, lastInstalledVersion, true);
var imageFiles = new List<string>();
for (int pageNumber = 1; pageNumber <= 10; pageNumber++)
{
foreach (var dpi in dpiList)
{
string pageFilePath = System.IO.Path.Combine(outputPath,
string.Format("{0}-{1}-{2}.png", pageNumber, Guid.NewGuid().ToString("N").Substring(0, 8), dpi));
System.Drawing.Image img = rasterizer.GetPage(dpi, dpi, pageNumber);
img.Save(pageFilePath, ImageFormat.Png);
imageFiles.Add(pageFilePath);
Console.WriteLine(pageFilePath);
}
}
var imageCount = 0;
var pd = new PrintDocument();
pd.PrintPage += delegate(object o, PrintPageEventArgs args)
{
var i = System.Drawing.Image.FromFile(imageFiles[imageCount]);
var pageBounds = args.PageBounds;
var margin = 48;
var imageBounds = new System.Drawing.Rectangle
{
Height = pageBounds.Height - margin,
Width = pageBounds.Width - margin,
Location = new System.Drawing.Point(margin / 2, margin / 2)
};
args.Graphics.DrawImage(i, imageBounds);
imageCount++;
};
foreach (var imagefile in imageFiles)
{
pd.Print();
}
PDF pages don't have a resolution. Images within them can be considered to have a resolution, which is given by the width of the image on the page, divided by the number of image samples in the x direction, and the height of the image on the page divided by the number of image samples in the y direction.
So this leaves calculating the width and height of the image on the page. This is given by the image matrix, modified by the Current Transformation Matrix. So in order to work out the width and height on the page, you need to interpret the content stream up to the point where the image is rendered, tracking the graphics state CTM.
For general PDF files, the only way to know this is to use a PDF interpreter. In the strictly limited case where the whole page content is a single image you can gamble that there is no scaling taking place and simply divide the media width by the image width, and the media height by the image height to give the x and y resolutions.
However this definitely won't work in the general case.
I'm having a weird problem with images in iTextSharp library.
I'm adding the image to the PdfPCell and for some reason it gets scaled up.
How do i keep it to original size?
I though that the images would be same when printed but the difference on the pic is the same on the printed version. Having to manually scale the image with ScaleXXX to get it to right seems a bit illogical and does not give a good result.
So how do I put the image in its original size inside a PdfPCell of a table without having to scale it?
Here's my code:
private PdfPTable CreateTestPDF()
{
PdfPTable table = new PdfPTable(1);
table.WidthPercentage = 100;
Phrase phrase = new Phrase("MY TITLE", _font24Bold);
table.AddCell(phrase);
PdfPTable nestedTable = new PdfPTable(5);
table.WidthPercentage = 100;
Phrase cellText = new Phrase("cell 1", _font9BoldBlack);
nestedTable.AddCell(cellText);
cellText = new Phrase("cell 2", _font9BoldBlack);
nestedTable.AddCell(cellText);
cellText = new Phrase("cell 3", _font9BoldBlack);
nestedTable.AddCell(cellText);
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(#"d:\MyPic.jpg");
image.Alignment = iTextSharp.text.Image.ALIGN_CENTER;
PdfPCell cell = new PdfPCell(image);
cell.HorizontalAlignment = PdfPCell.ALIGN_MIDDLE;
nestedTable.AddCell(cell);
cellText = new Phrase("cell 5", _font9BoldBlack);
nestedTable.AddCell(cellText);
nestedTable.AddCell("");
string articleInfo = "Test Text";
cellText = new Phrase(articleInfo, _font8Black);
nestedTable.AddCell(cellText);
nestedTable.AddCell("");
nestedTable.AddCell("");
nestedTable.AddCell("");
table.AddCell(nestedTable);
SetBorderSizeForAllCells(table, iTextSharp.text.Rectangle.NO_BORDER);
return table;
}
static BaseColor _textColor = new BaseColor(154, 154, 154);
iTextSharp.text.Font _font8 = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 8, iTextSharp.text.Font.NORMAL, _textColor);
iTextSharp.text.Font _font8Black = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 8, iTextSharp.text.Font.NORMAL, BaseColor.BLACK);
iTextSharp.text.Font _font9 = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 9, iTextSharp.text.Font.NORMAL, _textColor);
iTextSharp.text.Font _font9BoldBlack = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 9, iTextSharp.text.Font.BOLD, BaseColor.BLACK);
iTextSharp.text.Font _font10 = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 10, iTextSharp.text.Font.NORMAL, _textColor);
iTextSharp.text.Font _font10Black = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 10, iTextSharp.text.Font.NORMAL, BaseColor.BLACK);
iTextSharp.text.Font _font10BoldBlack = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 10, iTextSharp.text.Font.BOLD, BaseColor.BLACK);
iTextSharp.text.Font _font24Bold = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 24, iTextSharp.text.Font.BOLD, _textColor);
I'm using iTextSharp v4.1.2 and I get the following behavior:
Using this code, adding the image directly to the table via the AddCell method, the image is scaled up to fit the cell:
nestedTable.AddCell(image);
Using this code, adding the image to a cell, then adding the cell to the table, the image is displayed at its original size:
PdfPCell cell = new PdfPCell(image);
cell.HorizontalAlignment = PdfPCell.ALIGN_CENTER;
nestedTable.AddCell(cell);
Have you added the image directly to the pdf document (outside the table) just to compare/double-check the image sizes?
document.add(image);
I assume that you want the image centered in the cell with some space around it. As a last resort, you can change your image. Make it a png with a transparent background, and just make sure that there is some transparent 'margin' around all the edges of your image.
EDIT
I just downloaded the v5.0.2 and I get the same results as mentioned above. I've tried it with images that are both smaller and larger than the size of the cell, and the behavior is the same; the first method scales the image, the second method does not.
EDIT
Well, apparently I have been wrong for years about the whole DPI thing when it comes to images. I can't seem to see that it makes any difference at all what the DPI of the image is.
I created a 600x400px image at three different resolutions, 72dpi, 96 dpi, and 110 dpi. Then I added each these images to a new document that was exactly 600x400.
Dim pSize As Rectangle = New Rectangle(600, 1000)
Dim document As Document = New Document(pSize, 0, 0, 0, 0)
For each of the three image files, when added to the document with
document.add(image)
they fit the document perfectly, with no differences for the different DPI settings.
#Stewbob's answer does work, but it's only incidently related to the methods of the table.
The thing with iTextSharp is that it will behave differently depending on which constructor you use. This will (annoyingly) scale up the image to fill the cell:
PdfPCell c = new PdfPCell();
c.Add(image);
c.setHorizontalAlignment(Element.ALIGN_CENTER); // this will be ignored
But this will leave the image at the size you set it (and allow for alignment):
PdfPCell c = new PdfPCell(image);
c.setHorizontalAlignment(Element.ALIGN_CENTER);
I don't know exactly why this is, it's got something to do with the cell being in 'text mode' if you add the image in the constructor versus 'composite mode' if you add it later (in which case each object is supposed to look after it's own alignment).
Some more info (in Java, but still applies) http://tutorials.jenkov.com/java-itext/table.html#cell-modes
So if you have to mantain the size of the image in the PdfPCell you can loock at this code :
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(imageFilePath);
// Save the image width
float width = image.Width;
PdfPCell cell = new PdfPCell();
cell.AddElement(image);
// Now find the Image element in the cell and resize it
foreach (IElement element in cell.CompositeElements)
{
// The inserted image is stored in a PdfPTable, so when you find
// the table element just set the table width with the image width, and lock it.
PdfPTable tblImg = element as PdfPTable;
if (tblImg != null)
{
tblImg.TotalWidth = width;
tblImg.LockedWidth = true;
}
}
The function has a property to fit image. Only add a true
cell.AddElement(image,true);
For those asking for the overload, use this :
var imageCell = new PdfPCell(image, true);
instead of :
cell.AddElement(image,true);