iTextSharp renders image with poor quality in PDF - asp.net

I'm using iTextSharp to print a PDF document. Everything goes ok until I have to print the company logo in it.
First I noticed that the logo had poor quality, but after testing with several images, I realize that was the iTextSharp rendering it poorly.
The test I did to say this was to print the PDF using my code and then edit the document with Acrobat 8.0 and I drew an image. Then printed the two documents and saw the noticeable difference.
My question is that if anyone know if this can be due to a scaling problem where I'm failing to tell iTextSharp how it must render the image or is an iTextSharp limitation.
The code to render the image is the following:
Dim para As Paragraph = New Paragraph
para.Alignment = Image.RIGHT_ALIGN
para.Add(text)
Dim imageFile As String = String.Format("{0}{1}", GetAppSetting("UploadDirectory"), myCompany.LogoUrl)
Dim thisImage As Image = Image.GetInstance(imageFile)
thisImage.Alignment = Image.LEFT_ALIGN
para.Add(thisImage)
The printed images are the following:
alt text http://img710.imageshack.us/img710/4199/sshot2y.png
Image printed directly with iTextSharp
alt text http://img231.imageshack.us/img231/3610/sshot1z.png
Image edited and printed with Acrobat 8
EDIT:
These logo images are loaded from an Upload page where the user uploades whatever the logo image he wants, and I was scaling that image using the following code:
Dim graph As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(newImage)
graph.CompositingMode = Drawing.Drawing2D.CompositingMode.SourceOver
graph.CompositingQuality = Drawing.Drawing2D.CompositingQuality.HighQuality
graph.InterpolationMode = Drawing.Drawing2D.InterpolationMode.Bicubic
graph.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality
graph.PixelOffsetMode = Drawing.Drawing2D.PixelOffsetMode.HighQuality
graph.DrawImage(newImage, 0, 0, newWidth, newHeight)
graph.Dispose()
graph = Nothing
This was causing to lose info from the original image, so when printed in the pdf, that lose of info was very noticeable because, somehow, iTextSharp was drawing bigger than it was, no matter the scaling I put in there.
So I tried to store the image as it was originally, preventing the user to not upload images bigger than 200K and resizing the image so I could mantain the aspect ratio, and using that resizing with the iTextSharp Image object before it was printed.
This solved my problem of the image being printed with poor quality for these bigger images but caused the pdf document to have a page break or just not fit in the page, weird thing because the picture looks good in size but it behaves like it was bigger.
This is a screen capture of the new image:
alt text http://img38.imageshack.us/img38/5756/sshot3tc.png
EDIT 2:
When inspecting the iTextSharp Image that is sent to be printed, it shows no changes after the scaling using ScaleAbsolute, that's why the page breaks. But is shown correctly, like the image was successfully scaled, but the background "paper" wasn't.
The code used so far is the following:
Dim imageFile As String = String.Format("{0}{1}", GetAppSetting("UploadDirectory"), myCompany.LogoUrl)
Dim thisImage As Image = Image.GetInstance(imageFile)
thisImage.Alignment = Image.LEFT_ALIGN
Dim newWidth As Integer = myCompany.LogoWidth
Dim newHeight As Integer = myCompany.LogoHeight
ResizeImageToMaxValues(newWidth, newHeight)
thisImage.ScaleAbsolute(newWidth, newHeight)
para.Add(thisImage)
pdf.PdfDocument.Add(para)
The method ResizeImage() do the resizing of the width and height respecting the aspect ratio and keeping in a max width and a max height limits.
Please let me know if I need to provide more info. Thanks

Apart from the printer issue (See above), the 3 X tip by Your Friend was the final solution.
So, to rephrase, if you want the image to be 100 X 100 on the PDF, then make sure that your image is 300px X 300px or larger.
I try to also use 300dpi images and I have not tested with lower quality images.
This is my image adding code:
try
{
string uri = Environment.CurrentDirectory + "/" + "pdfwithimage_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".pdf";
string strImgJpg = Environment.CurrentDirectory + "/HeaderImage.jpg";
Image imgJpg = Image.GetInstance(System.Drawing.Image.FromFile(strImgJpg), new BaseColor(System.Drawing.Color.White));
using (Document pdf = new Document(PageSize.A4, 20, 20, 20, 20))
{
if (pdf == null)
{
throw new NullReferenceException("PDF has not been instanciated");
}
if (File.Exists(uri))
{
File.Delete(uri);
}
using (PdfWriter pdfwriter = PdfWriter.GetInstance(pdf, new FileStream(uri, FileMode.Create)))
{
pdf.Open();
imgJpg.SetDpi(300, 300);
imgJpg.ScaleToFit(100f, 100f);
pdf.Add(imgJpg);
pdf.Close();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadLine();
}

I also have good experience with iTextSharp rendering very sharp and clear images. I tried both adding the image directly to the document and adding it to a paragraph first. Both give very clear results.
Dim document As Document = New Document(pSize, 20, 20, 20, 20)
PdfWriter.GetInstance(document, New FileStream(myPath & "Test.pdf", FileMode.Create))
document.Open()
Dim png As Image = Image.GetInstance(myPath & "myImageFile.png")
document.Add(png)
Dim pgr As New Paragraph
pgr.Add(png)
document.Add(pgr)
document.Close()
I normally use .png images, but I have had the same success with jpeg, gif, etc.
Are you certain that when you retrieve the image in iTextSharp it is the exact same image that you retrieve when you are in Acrobat? I ask because it is unclear what exaclty is happening in your code:
Dim imageFile As String=String.Format(.....
EDIT
Also, to make sure that the image is displaying at the size you are expecting, save your images at 72dpi. 72 dpi is what iTextSharp uses for everything (images, margins, etc..).
That way, a 100px x 100px image will show up as 100x100 on your pdf document. You won't have to worry about scaling or re-sizing then. Any time that you scale an image (up or down) you run the risk of introducing aliasing artifacts (blurriness).

To make the rendering clear, try to make the image 3 times the original image, then you can apply ScalePercent or ScaleToFit to resize to certain size.
Sample:
Image logo = Image.GetInstance(pdfReportData.CompanyLogoPath);
logo.ScaleToFit(175f, 108f);
document.Add(logo);

The trick is to use larger images and scale them down. If the scale is not set and the image has its natural size, it will be poor quality. If the scale is set down and the image is drawn smaller than its natural size, the quality will be better.
Example of scaling down to 7 percent size (high quality):
var logo = Image.GetInstance(RImages.logo_600_icon, BaseColor.WHITE);
logo.ScalePercent(7);
var cell = new PdfPCell(logo);
cell.Border = 0;
table.AddCell(cell);

That's strange. I get super-crisp images in my pdf files. There are few differences between what I do and what you have. For example I create the image like this:
Image instance = Image.GetInstance(System.Drawing.Image.FromFile(pathToImage), Color.WHITE);
Furthermore, since my image is too big to fit I call:
instance.ScalePercent(90f);
Another difference is that I add the image directly to the Document and not to a Paragraph, although I doubt that that's it.
Edit:
And finally, my images are jpegs.
Hope it helps.

I ran into the same problem. I was able to fix it by turning off compression. My pdf files I'm generating aren't very large so the file size hit wasn't too expensive.
var writer = iTextSharp.text.pdf.PdfWriter.GetInstance(document, stream);
writer.SetPdfVersion(iTextSharp.text.pdf.PdfWriter.PDF_VERSION_1_7);
writer.CompressionLevel = PdfStream.NO_COMPRESSION;

On my side it ended up being a printer setting!
Changing the graphics to Raster (from Vector) made the images as crisp as they should be, but slowed the system down tremendously.
The second solution (thanks to the FD) was to change the graphics back to Vector, but to set the "Image Processing" to Best.
We are using a RICOH Aficio MP C2050 PCL 6.

Use bigger png images and than with iTextSharp change the size.
logoImage.ScalePercent(24f);

Related

Is it possible to adjust position of an inserted image with openxlsx?

I've created an excel template for reporting. In the excel file, there will be some images. I'm able to insert the images by using openxlsx package.
test.fpath <-'Templates/CB.xlsx'
wb <- openxlsx::loadWorkbook(test.fpath)
insertImage(wb, sheet = 1, file = "tm_player_image.png",startRow = 8, startCol = 3, width = 1.1, height = 1.73, units = "in")
saveWorkbook(wb, file = "createWorkbookExample.xlsx", overwrite = TRUE)
openxlsx package allows you to set specific value for starting row and column. When I run the script, excel file is saved like the following image.
First position of the image
However, I don't want the image start row = 8 and col = 3. I should able to drag the image where ever I want and define top-left position values. Is there any way to achieve this?
Adjusted position of the image
I need to define position of the image like this.
Left (Sol): 13,64''
Top (Üst): 0,74''
Thanks for your help.
It is possible, but there is no function to do this and AFAIK Excel positions are always relative to the screen and OS one is using. Therefore you have to use a bit try and error to get the correct positions.
Have a look at wb$drawings[[1]][[1]]. The content is an XML string. You are looking for the xdr:from part (as seen below). You have to adjust xdr:colOff and xdr:rowOff like in the example below. I had to insert a fairly high value to see any impact.
<xdr:from xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">\n
<xdr:col xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">2</xdr:col>\n
<xdr:colOff xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">50000</xdr:colOff>\n
<xdr:row xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">4</xdr:row>\n
<xdr:rowOff xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">40000</xdr:rowOff>\n
</xdr:from>

Custom decoders for PNG files

I've donwloaded an image from user manual (see attachment) and need to transform it. When I tried to load it via following code, I got the exception: "Image cannot be loaded. Available decoders:\r\n - JPEG : JpegDecoder\r\n - PNG : PngDecoder\r\n - GIF : GifDecoder\r\n - BMP : BmpDecoder\r\n".
Is it possible to apply custom decoder and where can I found them?
using (var originalImage = new MemoryStream(...))
using (var image = Image.Load<Rgba32>(originalImage))
{
}
The linked image can be decoded using ImageSharp. As #tocsoft says in the comments it likely you forgot to reset your input stream position.
Here's the two images. The second we've loaded and flipped vertically using the following code:
using (var image = Image.Load(Path.Combine(inPath, "-7bH2hfA.png")))
{
image.Mutate(x => x.Flip(FlipMode.Vertical));
image.Save(Path.Combine(outPath, "-7bH2hfA-flipped.png"));
}
Your input image:
Our flipped output image:
EDIT
When I originally tested the image I used r-click save which gave me a valid png. I have since used the direct download from Dropbox which yields the original file.
It's not a png! It is, in fact, a webp file.

Custom page size in PDFsharp

Using PDFsharp .NET library, I need to set the page size in the PDF document same as that of the images.
Example, image no. 1 measures 152px x 1775px.
Image no. 2 measures 100px x 1582px
The resulting PDF should have varying page size inside.
Please help.
With the following code, I am able to set the size of the images, the problem is now setting the page size.
PdfDocument doc = new PdfDocument();
//doc.Pages.Add(new PdfPage());
PdfPage page = doc.AddPage();
XGraphics gfx = XGraphics.FromPdfPage(doc.Pages[0]);
XImage xImage = XImage.FromFile(source);
gfx.DrawImage(xImage, 0, 0, xImage.PixelWidth, xImage.PixelHeight);
doc.Save(destinaton);
doc.Close();
//
PDF pages do not have pixels, it's a vector format.
This code should do the trick:
page.Width = xImage.PixelWidth;
page.Height = xImage.PixelHeight;
IMHO the user experience will be better if all pages have the same size and images are scaled for "best fit". That's my preference, your mileage may vary.

Resizing gif image causes loss of quality

I'm using Graphics.DrawImage() to resize images in my ASP.NET application.
This is working fine with all image formats, except gif.
Here is my original image:
When I resize to 300px it returns:
The code I'm using is:
Dim postedFile as new Bitmap("flower.gif")
Dim bmpOut As System.Drawing.Bitmap
Dim Format As ImageFormat = postedFile.RawFormat
bmpOut = New Bitmap(width, height)
Dim g As Graphics = Graphics.FromImage(bmpOut)
g.InterpolationMode = InterpolationMode.High
g.DrawImage(postedFile, 0, 0, width, height)
postedFile.Dispose()
Return bmpOut
bmpOut.Dispose()
I've also tried using all of the InterpolationMode's available, including InterpolationMode.HighQualityBicubic, but the image quality is still just as poor.
Why is this happening, and how can I prevent the image quality loss?
The problem is not in the resizing code you posted. I ran using the large image you posted and the result looks great. Your problem arises when you save your newly created 24 bits-per-pixel image to a new gif - with is 8bpp. You have basically two options:
Implement code to produce an optimized color palette for the new gif
(or maybe just use the palette from the original image)
Save to .png instead - which is a completely superior format
If you are saving the resized picture as .gif, I see no reason why this can't happen in the saved .gif. .gif's are limited to 256 colors (unless some hacks are done) and your resized imaged after all the manipulations may have well more than 256. Also, I wouldn't be surprised to find out that whatever routine you're using to convert images to .gif's isn't very concerned about quality.
This is not about interpolation, it is because ColorPalette is not set for target image. You have to quantize. See example at http://glennjones.net/2005/10/high-quality-dynamically-resized-images-with-dot-net/

Working with Bitmap? Giving error?

In web application, i am using Bitmap for finding the width and hight of the image. When i write the code it is giving error: Parameter is not a valid.
Bitmap bmp = new Bitmap(Server.MapPath("./Images/" + ds.Tables[0].Rows[0]["image"].ToString()));
I am getting error can you help me. Thank you.
Error says that the image you are saving has invalid image data (state) or the filename which is used to save image is already is in used.
Probably you just need to use this
System.Drawing.Image bmp = System.Drawing.Image.FromFile(Server.MapPath("YourPathHere"));

Resources