Resizing gif image causes loss of quality - asp.net

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/

Related

How do I convert a Color Image to Black and White using ImageMagick?

Background: I performed an Indexed conversion in Gimp of a color image and the result was a nice B&W version of the source Image.
I have tried numerous options in ImageMagick to no avail. I can get close but never quite as clear and crisp as what gimp seems to do effortlessly.
Here is my source:
var bmp = new MagickImage(sourceImage);
bmp.Threshold(new ImageMagick.Percentage(60));
bmp.Resample(200, 200);
bmp.ColorType = ColorType.Bilevel;
bmp.BitDepth(1);
bmp.Settings.Compression = CompressionMethod.Group4;
bmp.Strip();
bmp.Format = MagickFormat.Tiff;
I have been adjusting the Threshold call and have tried various suggestions I have seen online with varying amounts of success.
magickimage has a feature called -monochrome but I have not found how that is achieved in the .net library.
I am sure this is possible but what is the best way to achieve a nice B&W conversion.
With ImageMagick 7, you can do Otsu thresholding.
Input:
magick check.png -alpha off -auto-threshold otsu x.png
Result:
There is no built-in equivalent in ImageMagick 6. However I have a script, otsuthresh that will do that At my web site
So in ImageMagick 6, you just have to do simple thresholding.
convert check.png -alpha off -threshold 50% y.png
Result:
I note that your input image has an opaque alpha channel which needs to be removed to get proper results.
This is possibly the simplest way you can use Greyscale in Magick.NET.
MagickImage image = new MagickImage(imagePath);
image.Grayscale();
string fileName = image.FileName + "_grey.png";
image.Write(fileName);
Instead of image.FileName you can also directly use the image path if you have it.
Optionally you can add a PixelIntensityMethod in Greyscale for eventually better results.
Don't forget to call image.RePage() when you want to crop the image.
Otsu's method will perform better when dealing with texts over a background with slightly gradient colors:
How do I convert a Color Image to Black and White using ImageMagick?
According to #fmw42 's comparison on multiple threshold methods:
the Local Adaptive(its equivalent in imagemagick is -lat) algorithm might work best on texts over background:
Also try to combine with connected components processing that was introduced in another answer made by #fmw42 to remove unnecessary edges/dots which might get confused by any further OCR process.

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.

It seems like GDI+ TextureBrush Bug

before mention, I Cant Speak Enginlish That very well
Recently I make Windows Desktop Application(On Windows7) using GDI+
I think Gdiplus::TextureBrush has a bug. I hope anyone found this bug like me.
that bug is like below
step1.
there is a image that has 500dpi, 6250 * 7819 size
step2
Loading the image by using Gdiplus::Image::FromStream()
the image name is "image1"
step3.
Creating Graphics graphics(HDC);
step3.
Creating Gdiplus::TextureBrush brush = Gdiplus::TextureBrush(image1);
step4
graphics.FillPath(brush);
currently everything is ok, you can see the right image on screen
step5
creating another Graphics from a bitmap
Graphics::Bitmap* bitmap = new Graphics::Bitmap(size.CX, size.CY), PixelFormat32bppARG);
Graphics* anotherGraphics = Gdiplus::Graphics::FromImage(bitmap);
step6 (Here Bug Occur)
anotherGraphics.DrawImage(image1);
and then detach the new image from anotherGraphics.
but new image is weird, new image like filled entirely by one pixel from the origin image
but next time, it never happens again..
only one time during the app life time
what is wrong....
Bitmap::FromStream method has second arg that is useEmbededColorManagement (not sure that is correct name anyway) I did put the True in it and then its working well. The arg looks like not related this bug.
I still don't know why its working but I solved this problem.

iTextSharp renders image with poor quality in PDF

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);

Resources