Convert PDF to Image Byte array to save to database - c#

What I am trying to accomplish is allowing my user to upload a PDF. I will then convert that to an Image and get the Images byte array. Below is what I have so far.
PdfDocumentProcessor pdfDocumentProcessor = new PdfDocumentProcessor();
using (MemoryStream ms = new MemoryStream(e.UploadedFile.FileBytes))
{
pdfDocumentProcessor.LoadDocument(ms);
for (int i = 1; i <= pdfDocumentProcessor.Document.Pages.Count; i++)
{
Bitmap image = pdfDocumentProcessor.CreateBitmap(i, 1000);
try
{
image.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
}
catch (Exception error)
{
string message = error.Message;
}
}
When I try to save the Image to the memory stream I am getting the error "A generic error occurred in GDI+" I believe this has something to do with me not specifying a path for the image to be saved to, but I could be mistaken.
I want to convert the PDF to and Image, then get the byte array of the image, and save that to the database. I really don't want to save the image to a specified path.
PDFDocumentProcessor is a DevExpress class that pulls in the PDF and also will give me the PDF's byte array, but I just can't seem to find a way past the save error to retrieve an Image byte array
Any help is appreciated thank you

The issue is likely caused by you trying to re-use the same MemoryStream that is holding the input file bytes. You should create a new memory stream to save to.
I don't have access to devexpress but I grabbed another Nuget package that i am associated with https://www.nuget.org/packages/Leadtools.Pdf/ and tested it and this code works to save the PDF to a PNG memorystream:
using (var ms = new MemoryStream(fileBytes))
using (var codecs = new RasterCodecs())
{
codecs.Options.Load.AllPages = true;
using (var rasterImage = codecs.Load(ms))
using (var outputStream = new MemoryStream())
codecs.Save(rasterImage, outputStream, RasterImageFormat.Png, 0);
}

Related

Getting error from the inkcanvase base 64 string

Hello we are using InkCanvas control on the wpf page. And we are saving Base64String string in the database. See code
private void submitButtonsCommand_Event(object sender)
{
byte[] sigByte;
InkCanvas icSignature = sender as InkCanvas;
using (var memoryStream = new MemoryStream())
{
icSignature.Strokes.Save(memoryStream);
sigByte = memoryStream.ToArray();
}
ServiceCallReportSignatureModel.SigCustomerSignature = Convert.ToBase64String(sigByte);
UpdateRecord();
}
And when we are retrieving data from the database and converting into the FromBase64String and after that when we creating image then we are getting the error.
public Image LoadImage(base64string)
{
//data:image/gif;base64,
//this image is a single pixel (black)
byte[] bytes = Convert.FromBase64String(base64string);
Image image;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = Image.FromStream(ms);
}
return image;
}
I don't know why this is occurring. Please help me find out the error.
Our base64 string is : "AIwBAwxIEEWfARsCAAb/RjURAACAPx8JEQAAAAAAAPA/Cmwsh/EgR4kP+Etw/ojDWG7NZ8OZQxBN5otEzmU1mk04I7DnATcLHomzzUbxw/h3Dtp16yhlTQ2UsoTQh+uE64XgjsN6Js2UZpAZmFpmaZTKzzKZ4ctFmw3Mlmm0Bw9h/DtpTPKu79CYgm+VJqA="
Actually we are taking signature from the ink canvas control and we want to display in the pdf when we need. So we want create image from the base 64 data but we are getting the error.
The StrokeCollection.Save(Stream) method does not save a bitmap. Instead,
The Save method saves the StrokeCollection as Ink Serialized Format (ISF).
You can restore the saved StrokeCollection by passing a Stream with the saved data to the StrokeCollection(Stream) constructor.

byte array to image save throws an error like "Parameter not valid" in C#

i could see this question is asked many many times but none seems to be straight forward answer. so am posting this question.
I am reading BLOB from oracle database into photoByteArray[] array.
Now i just want to save this byte[] into file systems as anyFileName.jpeg (or any format), but i get the "Parameter not vaid" exception.
What i tried is
using (var ms = new System.IO.MemoryStream(photoByteArray))
{
using (var img = Image.FromStream(ms)) // error thrown here as 'parameter is not valid'
{
img.Save("D:\\anyFileName.jpg", ImageFormat.Jpeg);
}
}
My bytes
Few are suggesting that some header gets added in the byte array, but how and howmuch to remove that kind of header is not straight forward way.
What am i doing wrong ?
When I use something like this:
Image img = Image.FromFile(#"C:\a.png");
byte[] arr;
using (MemoryStream ms = new MemoryStream())
{
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
arr = ms.ToArray();
}
using (var ms = new System.IO.MemoryStream(arr))
{
using (var img1 = Image.FromStream(ms,false,true)) // error thrown here as 'parameter is not valid'
{
img1.Save("D:\\anyFileName.png", ImageFormat.Png);
}
}
which convert an image file to byte and with your method convert that byte array to image it works properly.
but when I change some byte of that byteArray to 0 (zero)(for example first 15 bytes) I get your error.
so It is concluded that your byte array really isn't in correct format, some probabilities are:
you are saving your byte array to your database with mistakes(for
example datatype of your column is not appropriate).
while getting byte array from DB you make some mistakes.
some other reasons which I don't know.

Create a VSTO shape from byte array

I have an image that is encoded in a byte array and I would like to add it as a shape in an excel document but unfortunetly the only available function I see to do this requires me to save the image to the drive and then read it. As you see this is a really slow operation and I would like to simply read the image from the byte stream and decode it into a bitmap.
I have encoded it like this :
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.QualityLevel = 100;
byte[] bit = null;
using (var ms = new MemoryStream())
{
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(ms);
bit = ms.ToArray();
}
Now, how to add it to the worksheet ?
The method Shapes.AddPicture accepts only a filename and cannot read from a stream.
The Excel object model doesn't provide any method for reading a byte array and then add it as a shape. So, the only possible solution is to save the byte array as a file on the disk and then add it as a shape as you stated earlier:
to save the image to the drive and then read it.

C#: Getting Error: "A generic error occurred in GDI+" When trying to copy imagebox.Image into memory stream. This stream is not being saved to file.

I am getting an odd error with Image.save(Stream, Format).
I tried looking around on here for a solution but everyone seems to think the error is from file permissions. That can't be it in my case case the Stream isn't going into a file. My code is below:
MemoryStream Stream = new MemoryStream();
this.Image_Box_1.Image.Save(Stream, System.Drawing.Imaging.ImageFormat.Jpeg);
TI.AlbumCover = Stream.ToArray();
Stream.Close();
TI.AlbumCover is a byte[].
Does anyone have any ideas on what the problem might be?
EDIT:
Ok, so I worked it out. The original file could sometimes come from a jpg file, sometimes from a byte array (part of an id3 tag). The problem was that when the image came from the file, I was closing the stream after creating the image box image. While the image remained visible, the data was no longer available.
Since I also later needed to overwrite that jpg file, I could not simply leave the filestream for it open so I left the rest of my code the same and changed the code to read from the jpg to the following:
FileStream FS = new FileStream(File, FileMode.Open, FileAccess.Read);//Read in the jpg file
Image IMG = Image.FromStream(FS);//Create an image from the file data
MemoryStream MS = new MemoryStream();
IMG.Save(MS, System.Drawing.Imaging.ImageFormat.Jpeg);//Save the image data to a memory stream
byte[] temp = MS.ToArray();//Copy the image data to a byte array
//close the streams
MS.Close();
FS.Close();
return temp; //was originally returning an image
Then after executing this code I change the code that placed the image into the image box to:
try
{
if (this.m_V2Tag.AlbumCover != null)
this.Image_Box_1.Image = Image.FromStream(new MemoryStream(this.m_V2Tag.AlbumCover));
//changed code
else
{
MemoryStream temp = new MemoryStream(this.getFolderJpg()); //create a memory stream from the byte[]. This stream can safely be left open.
this.Image_Box_1.Image = Image.FromStream(temp); // create image and assign it to the image box
}
}
catch
{
this.Image_Box_1.Image = null;
}

Image.Save(..) throws a GDI+ exception because the memory stream is closed

i've got some binary data which i want to save as an image. When i try to save the image, it throws an exception if the memory stream used to create the image, was closed before the save. The reason i do this is because i'm dynamically creating images and as such .. i need to use a memory stream.
this is the code:
[TestMethod]
public void TestMethod1()
{
// Grab the binary data.
byte[] data = File.ReadAllBytes("Chick.jpg");
// Read in the data but do not close, before using the stream.
Stream originalBinaryDataStream = new MemoryStream(data);
Bitmap image = new Bitmap(originalBinaryDataStream);
image.Save(#"c:\test.jpg");
originalBinaryDataStream.Dispose();
// Now lets use a nice dispose, etc...
Bitmap2 image2;
using (Stream originalBinaryDataStream2 = new MemoryStream(data))
{
image2 = new Bitmap(originalBinaryDataStream2);
}
image2.Save(#"C:\temp\pewpew.jpg"); // This throws the GDI+ exception.
}
Does anyone have any suggestions to how i could save an image with the stream closed? I cannot rely on the developers to remember to close the stream after the image is saved. In fact, the developer would have NO IDEA that the image was generated using a memory stream (because it happens in some other code, elsewhere).
I'm really confused :(
As it's a MemoryStream, you really don't need to close the stream - nothing bad will happen if you don't, although obviously it's good practice to dispose anything that's disposable anyway. (See this question for more on this.)
However, you should be disposing the Bitmap - and that will close the stream for you. Basically once you give the Bitmap constructor a stream, it "owns" the stream and you shouldn't close it. As the docs for that constructor say:
You must keep the stream open for the
lifetime of the Bitmap.
I can't find any docs promising to close the stream when you dispose the bitmap, but you should be able to verify that fairly easily.
A generic error occurred in GDI+.
May also result from incorrect save path!
Took me half a day to notice that.
So make sure that you have double checked the path to save the image as well.
Perhaps it is worth mentioning that if the C:\Temp directory does not exist, it will also throw this exception even if your stream is still existent.
Copy the Bitmap. You have to keep the stream open for the lifetime of the bitmap.
When drawing an image: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI
public static Image ToImage(this byte[] bytes)
{
using (var stream = new MemoryStream(bytes))
using (var image = Image.FromStream(stream, false, true))
{
return new Bitmap(image);
}
}
[Test]
public void ShouldCreateImageThatCanBeSavedWithoutOpenStream()
{
var imageBytes = File.ReadAllBytes("bitmap.bmp");
var image = imageBytes.ToImage();
image.Save("output.bmp");
}
I had the same problem but actually the cause was that the application didn't have permission to save files on C. When I changed to "D:\.." the picture has been saved.
You can try to create another copy of bitmap:
using (var memoryStream = new MemoryStream())
{
// write to memory stream here
memoryStream.Position = 0;
using (var bitmap = new Bitmap(memoryStream))
{
var bitmap2 = new Bitmap(bitmap);
return bitmap2;
}
}
This error occurred to me when I was trying from Citrix. The image folder was set to C:\ in the server, for which I do not have privilege. Once the image folder was moved to a shared drive, the error was gone.
A generic error occurred in GDI+. It can occur because of image storing paths issues,I got this error because my storing path is too long, I fixed this by first storing the image in a shortest path and move it to the correct location with long path handling techniques.
I was getting this error, because the automated test I was executing, was trying to store snapshots into a folder that didn't exist. After I created the folder, the error resolved
One strange solution which made my code to work.
Open the image in paint and save it as a new file with same format(.jpg). Now try with this new file and it works. It clearly explains you that the file might be corrupted in someway.
This can help only if your code has every other bugs fixed
It has also appeared with me when I was trying to save an image into path
C:\Program Files (x86)\some_directory
and the .exe wasn't executed to run as administrator, I hope this may help someone who has same issue too.
For me the code below crashed with A generic error occurred in GDI+on the line which Saves to a MemoryStream. The code was running on a web server and I resolved it by stopping and starting the Application Pool that was running the site.
Must have been some internal error in GDI+
private static string GetThumbnailImageAsBase64String(string path)
{
if (path == null || !File.Exists(path))
{
var log = ContainerResolver.Container.GetInstance<ILog>();
log.Info($"No file was found at path: {path}");
return null;
}
var width = LibraryItemFileSettings.Instance.ThumbnailImageWidth;
using (var image = Image.FromFile(path))
{
using (var thumbnail = image.GetThumbnailImage(width, width * image.Height / image.Width, null, IntPtr.Zero))
{
using (var memoryStream = new MemoryStream())
{
thumbnail.Save(memoryStream, ImageFormat.Png); // <= crash here
var bytes = new byte[memoryStream.Length];
memoryStream.Position = 0;
memoryStream.Read(bytes, 0, bytes.Length);
return Convert.ToBase64String(bytes, 0, bytes.Length);
}
}
}
}
I came across this error when I was trying a simple image editing in a WPF app.
Setting an Image element's Source to the bitmap prevents file saving.
Even setting Source=null doesn't seem to release the file.
Now I just never use the image as the Source of Image element, so I can overwrite after editing!
EDIT
After hearing about the CacheOption property(Thanks to #Nyerguds) I found the solution:
So instead of using the Bitmap constructor I must set the Uri after setting CacheOption BitmapCacheOption.OnLoad.(Image1 below is the Wpf Image element)
Instead of
Image1.Source = new BitmapImage(new Uri(filepath));
Use:
var image = new BitmapImage();
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(filepath);
image.EndInit();
Image1.Source = image;
See this: WPF Image Caching
Try this code:
static void Main(string[] args)
{
byte[] data = null;
string fullPath = #"c:\testimage.jpg";
using (MemoryStream ms = new MemoryStream())
using (Bitmap tmp = (Bitmap)Bitmap.FromFile(fullPath))
using (Bitmap bm = new Bitmap(tmp))
{
bm.SetResolution(96, 96);
using (EncoderParameters eps = new EncoderParameters(1))
{
eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bm.Save(ms, GetEncoderInfo("image/jpeg"), eps);
}
data = ms.ToArray();
}
File.WriteAllBytes(fullPath, data);
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
for (int j = 0; j < encoders.Length; ++j)
{
if (String.Equals(encoders[j].MimeType, mimeType, StringComparison.InvariantCultureIgnoreCase))
return encoders[j];
}
return null;
}
I used imageprocessor to resize images and one day I got "A generic error occurred in GDI+" exception.
After looked up a while I tried to recycle the application pool and bingo it works. So I note it here, hope it help ;)
Cheers
I was getting this error today on a server when the same code worked fine locally and on our DEV server but not on PRODUCTION. Rebooting the server resolved it.
public static byte[] SetImageToByte(Image img)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
}
public static Bitmap SetByteToImage(byte[] blob)
{
MemoryStream mStream = new MemoryStream();
byte[] pData = blob;
mStream.Write(pData, 0, Convert.ToInt32(pData.Length));
Bitmap bm = new Bitmap(mStream, false);
mStream.Dispose();
return bm;
}

Categories

Resources