I'm trying to save a file using GDI+, but I just get a "A generic error occurred in GDI+" exception. The code works fine for almost every photo but this one (we handle thousands a day for years and this is the first I've heard of it). I think it might have something to do with exif data or perhaps something else odd from the photographers camera or editor.
Here's the photo in question
And here is code to reproduce the error with this photo:
class Program
{
static void Main(string[] args)
{
using (var img = Image.FromFile("Err.jpg"))
using (var ms = new MemoryStream())
{
img.Save(ms, ImageFormat.Jpeg);
}
}
}
How am I supposed to handle this in GDI+? Is there a way to strip out the extra stuff that is causing the problem?
It seems that converting the image to a bmp first solves the problem. It would be nice to find a method that is more efficient (doesn't require multiple images to be created and loaded into memory), but this is the best I've found so far.
static void Main(string[] args)
{
var path = #"gdi_err.jpg";
using (var img1 = Image.FromFile(path))
using (var ms1 = new MemoryStream())
{
img1.Save(ms1, ImageFormat.Bmp);
ms1.Position = 0;
using (var img2 = Image.FromStream(ms1))
using (var ms2 = new MemoryStream())
{
img2.Save(ms2, ImageFormat.Jpeg);
}
}
}
The exif profile of your image seems to be the problem. When I remove it I can save the image to the memorystream. I used Magick.NET to remove the exif profile.
using (MagickImage magickImage = new MagickImage())
{
using (var magickStream = new MemoryStream())
{
magickImage.Read(#"gdi_err.jpg");
magickImage.Strip();
magickImage.Write(magickStream);
magickStream.Position = 0;
// This part is just here to demonstrate that saving the image works.
// You don't need it because magickStream already contains the data you want.
using (Image image = Image.FromStream(magickStream))
{
using (var ms = new MemoryStream())
{
image.Save(ms, ImageFormat.Jpeg);
}
}
}
}
Related
I am using PDFiumSharp to generate JPGs from PDF file. Here is my code:
using (WebClient client = new WebClient())
{
byte[] pdfData = await client.DownloadDataTaskAsync(pdfUrl);
using (var doc = new PdfDocument(pdfData))
{
int i = 0;
foreach (var page in doc.Pages)
{
using (var bitmap = new PDFiumBitmap((int)page.Width, (int)page.Height, true))
using (var stream = new MemoryStream())
{
page.Render(bitmap);
bitmap.Save(stream);
...
i++;
}
}
}
}
The codes work very well, images are generated accurately. However, each JPG is about 2mb. With multi-page PDF, the overall image size adds up quickly. Is there any way to reduce the JPG file size? I only need the JPG for preview purposes, not for printing. So lower resolution or quality is fine.
When you call bitmap.Save(...), the resulting byte[] that gets put into the MemoryStream stream represents a BMP. You should convert it into JPG yourself.
public static byte[] Render(PdfDocument pdfDocument, int pageNumber, (int width, int height) outputSize)
{
var page = pdfDocument.Pages[pageNumber];
using var thumb = new PDFiumBitmap((int)page.Width, (int)page.Height, false);
page.Render(thumb);
using MemoryStream memoryStreamBMP = new();
thumb.Save(memoryStreamBMP);
using Image imageBmp = Image.FromStream(memoryStreamBMP);
using MemoryStream memoryStreamJPG = new();
imageBmp.Save(memoryStreamJPG, ImageFormat.Jpeg);
return memoryStreamJPG.ToArray();
}
let's assume I let the user choose an image from the computer. I load the file to a picture box. here is the conversion method:
public static Image LoadImageFromFile(string fileName)
{
Image result = null;
if (!File.Exists(fileName))
return result;
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
try
{
using (Image image = Image.FromStream(fs))
{
ImageManipulation.RotateImageByExifOrientationData(image);
result =(Image) image.Clone();
image.Dispose();
}
}
finally
{
fs.Close();
}
return result;
}
then, when the user clicks on the Save button, I convert the image into a byte array and save it into the database. here is the conversion code:
public static byte[] ImageToByteArray(Image image)
{
if (image == null)
return null;
using (var ms = new MemoryStream())
{
ImageFormat imageFormat = image.RawFormat;
ImageCodecInfo codec = ImageCodecInfo.GetImageDecoders().FirstOrDefault(c => c.FormatID == imageFormat.Guid);
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
if (codec != null)
image.Save(ms, codec, encoderParameters);
else
image.Save(ms, ImageFormat.Jpeg);
return ms.ToArray();
}
}
but the problem:
I have a jpg file on the disk. I can load it into my picture box without any problem. the picture is perfectly visible in it. but when I save it, the code gives me "A generic error occurred in GDI+." Error at 'image.Save(ms, codec,encoderParameters)' line.
more odd incident: I don't get this error all the time. it is happening with specific images. for example, I downloaded an image from the internet and crop it in "Paint" and saved it as jpg. error happened. open it in Paint again and save it as png. no error!!!! that is why I am really confused . and Yes I already have tried to don't dispose the image. not helping
I know it might be a stupid question but I am desperately stuck here :)
Thank you in Advanced
I didn't find out why my code is not working but I just substitute my loading method with the code below. it is releasing the file and at the same time works as it should.
public static Image LoadImageFromFile(string fileName)
{
using (Bitmap bmb = new Bitmap(fileName))
{
MemoryStream m = new MemoryStream();
bmb.Save(m, ImageFormat.Bmp);
return Image.FromStream(m);
}
}
I wrote this code for analyzing the numbers included in picture. It does not give any error while starting but it can not read the numbers. When I start program, it shows an empty MessageBox.
I want to read pictures like this:
The code:
private string FotoAnaliz()
{
FileStream fs = new FileStream("D:\\program_goruntusu.jpg", FileMode.OpenOrCreate);
//string fotopath = #"D:\\program_goruntusu.jpg";
Bitmap images = new Bitmap(fs);
using (var engine = new TesseractEngine(#"./tessdata", "eng"))
{
engine.SetVariable("tessedit_char_whitelist", "0123456789");
// have to load Pix via a bitmap since Pix doesn't support loading a stream.
using (var image = new Bitmap(images))
{
using (var pix = PixConverter.ToPix(image))
{
using (var page = engine.Process(pix))
{
sayı = page.GetText();
MessageBox.Show(sayı);
fs.Close();
}
}
}
}
return sayı;
}
Try PSM 10: Treat the image as a single character.
https://github.com/tesseract-ocr/tesseract/blob/master/doc/tesseract.1.asc
My aim is to convert a base64 string into an image and save it to the disk. I have the following code (mostly from this SO answer) -
namespace ImageSaver
{
using System;
static class Program
{
public static void LoadImage()
{
//get a temp image from bytes, instead of loading from disk
//data:image/gif;base64,
//this image is a single pixel (black)
byte[] bytes = Convert.FromBase64String("R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==");
Image image;
Bitmap bimage;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = Image.FromStream(ms);
}
bimage = new Bitmap(image);
bimage.Save("c:\\img.gif", System.Drawing.Imaging.ImageFormat.Gif);
}
static void Main(string[] args)
{
ImageSaver.Program.LoadImage();
}
}
}
I ran it on MS Visual Studio 2010 Ultimate (Windows 8.1 Pro x64), without errors, but I could not find the image file in C drive. Where did I go wrong?
Try to save your file in this way:
File.WriteAllBytes(#"c:\img.gif", bytes);
EDIT
Anyway put your code under try'n'catch to better understand why you file is not being saved.
Try updating LoadImage to this to find out what the error is, and set a debug point on the MessageBox to examine the full details of what's happening;
public static void LoadImage()
{
try
{
//get a temp image from bytes, instead of loading from disk
//data:image/gif;base64,
//this image is a single pixel (black)
byte[] bytes = Convert.FromBase64String("R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==");
Image image;
Bitmap bimage;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = Image.FromStream(ms);
}
bimage = new Bitmap(image);
bimage.Save("c:\\img.gif", System.Drawing.Imaging.ImageFormat.Gif);
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
I am trying to save a PNG image that has been copied to the clipboard, but it is either turning out as a solid black, or black around the areas that should be transparent.
Here is the code I am using to capture and save the Image
var clipboardImage = (InteropBitmap)Clipboard.GetImage();
Image.SaveImage(clipboardImage, Path.Combine(Config.App.ApplicationDataImagesPath, string.Format("{0}.{1}", imageId, "png")));
public static void SaveImage(BitmapSource bitmapImage, string filename)
{
using (var fileStream = new FileStream(filename, FileMode.Create))
{
var pngBitmapEncoder = new PngBitmapEncoder();
pngBitmapEncoder.Frames.Add(BitmapFrame.Create(bitmapImage));
pngBitmapEncoder.Save(fileStream);
fileStream.Close();
fileStream.Dispose();
}
}
Does anyone have any ideas why it won't persrve the alpha channels of a PNG?
Thanks
Dan
Edit: I should of mentioned that black images were happening when copying an image from Internet Explorer 9. Works perfectly when copying an image from either Chrome or Firefox. Any workarounds for IE9 issue?
What happens if just do this:
Clipboard.GetImage().Save ("XXX.png", System.Drawing.Imaging.ImageFormat.Png);
EDIT - for WPF try this:
public static void SaveClipboardImageToFile(string filePath)
{
var image = Clipboard.GetImage();
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(fileStream);
}
}