Bad parameter when using save() on Image - c#

I am having a bit of trouble with saving an Image, it says "Bad paremeter" on the line where I try and save the image.
I'm not sure if it's how I am creating the image or if it's just saving that's the problem.
public static void Fullscreen()
{
string fileName = Helper.RandomStr(10) + ".png";
try
{
var image = ScreenCapture.CaptureFullscreen();
image.Save(fileName, ImageFormat.Png);
System.Diagnostics.Process.Start(fileName);
}
catch (Exception ex)
{
MessageBox.Show("Unable to capture fullscreen because: " + ex.ToString() + "\r\n\r\nFile: " + fileName);
}
}
Edit:
Here is the method that gets the Bitmap
public static Bitmap CaptureFullscreen()
{
using (Bitmap bmp = new Bitmap(ScreenDimensions.Width, ScreenDimensions.Height))
{
using (Graphics g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(Point.Empty, Point.Empty, bmp.Size);
}
return bmp;
}
}

Bad parameter is the way GDI+ tells that there was some problem.
Its a shame that the errors are not very much descriptive.
First try to wrap image parameter to Bitmap constructor like:
image = new Bitmap(image);
This forces to process the bitmap immediately.
It was even simpler, remove using on the bitmap.

Try using a known path and see if starts working. If so then you might want a new random string generator that makes valid paths or a different way of naming the file.

Related

Working with images of different file types [duplicate]

I am working on reading text from an image through OCR. It only supports TIFF format images.
So, I need to convert other formats to TIFF format. Can it be done? Please help by providing some references.
If you create an Image object in .NET, you can save it as a TIFF. It is one of the many ImageFormat choices at your disposal.
Example:
var png = Image.FromFile("some.png");
png.Save("a.tiff", ImageFormat.Tiff);
You'll need to include the System.Drawing assembly in your project. That assembly will give you a lot of image manipulation capabilities. Hope that helps.
Intro Note:
This answer cover the Bounty Question; which is: How do we
convert multiple files into 1 tiff? For example, let's say have pdfs,
jpegs, pngs, and I'd like to create 1 tiff out of them?
In this answer I use .net implementation of https://imagemagick.org/index.php for image manipulation and and Ghostscript for helping read an AI/EPS/PDF/PS file so we can translate it to image files both are credible and official source.
After I answered this question I got some extra question in my email asking other merging options, I have therefore extended my answer.
IMO there are 2 steps to your goal:
Install required tools for pdf conversion
Take all images including pdf formatted files from source and merge them together
in one tiff file.
1. Install tools that helps Pdf to Image conversion:
Step 1 is only required if you intend to convert AI/EPS/PDF/PS file formats. Otherwise just jump to step2.
To make it possible converting pdf to any image format, we need a library that can read pdf files and we need a tool to convert it to image type. For this purpose, we will need to install Ghostscript (GNU Affero General Public License).
Here after, we need to install ImageMagick.net for .net in Visual Studio, nuget link.
So far so good.
2. Code part
Second and Last step is we need to read files (png, jpg, bmp, pdf etc) from folder location and add each file to MagickImageCollection, then we have several options to merge use AppendHorizontally, AppendVertically, Montage or Multiple page Tiff. ImageMagick has tons of features, like resizing, resolution etc, this is just example to demonstrate merging features:
public static void MergeImage(string src, string dest, MergeType type = MergeType.MultiplePage)
{
var files = new DirectoryInfo(src).GetFiles();
using (var images = new MagickImageCollection())
{
foreach (var file in files)
{
var image = new MagickImage(file)
{
Format = MagickFormat.Tif,
Depth = 8,
};
images.Add(image);
}
switch (type)
{
case MergeType.Vertical:
using (var result = images.AppendVertically())
{
result.AdaptiveResize(new MagickGeometry(){Height = 600, Width = 800});
result.Write(dest);
}
break;
case MergeType.Horizontal:
using (var result = images.AppendHorizontally())
{
result.AdaptiveResize(new MagickGeometry(){Height = 600, Width = 800});
result.Write(dest);
}
break;
case MergeType.Montage:
var settings = new MontageSettings
{
BackgroundColor = new MagickColor("#FFF"),
Geometry = new MagickGeometry("1x1<")
};
using (var result = images.Montage(settings))
{
result.Write(dest);
}
break;
case MergeType.MultiplePage:
images.Write(dest);
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, "Un-support choice");
}
images.Dispose();
}
}
public enum MergeType
{
MultiplePage,
Vertical,
Horizontal,
Montage
}
To run the code
public static void Main(string[] args)
{
var src = #"C:\temp\Images";
var dest1 = #"C:\temp\Output\MultiplePage.tiff";
var dest2 = #"C:\temp\Output\Vertical.tiff";
var dest3 = #"C:\temp\Output\Horizontal.tiff";
var dest4 = #"C:\temp\Output\Montage.tiff";
MergeImage(src, dest1);
MergeImage(src, dest2, MergeType.Vertical);
MergeImage(src, dest3, MergeType.Horizontal);
MergeImage(src, dest4, MergeType.Montage);
}
Here is 4 input files in C:\temp\Images:
After running the code, we get 4 new files under C:\temp\Output looks like this:
4 page Multiple Page Tiff
4 image Vertical Merge
4 image Horizontal Merge
4 image Montage Merge
Final note:
it is possible to merge multiple images to tiff using System.Drawing; and using System.Drawing.Imaging; with out using ImageMagick, but pdf does require a third party conversion library or tool, therefore I use Ghostscript and ImageMagick for C#.
ImageMagick has many features, so you can change the resolution, size of output file etc. it is well recognized library.
Disclaimer: A part of this answer is taken from my my personal web site https://itbackyard.com/how-to-convert-ai-eps-pdf-ps-to-image-file/ with source code to github.
To be covert the image in tif format.In the below example to be convert the image and set to a text box.to be see the image in text box is (.tif formate).This sources code is working.
private void btn_Convert(object sender, EventArgs e)
{
string newName = System.IO.Path.GetFileNameWithoutExtension(CurrentFile);
newName = newName + ".tif";
try
{
img.Save(newName, ImageFormat.Tiff);
}
catch (Exception ex)
{
string error = ee.Message.ToString();
MessageBox.Show(MessageBoxIcon.Error);
}
textBox2.Text = System.IO.Path.GetFullPath(newName.ToString());
}
I tested this with jpg, bmp, png, and gif. Works for single and multipage creation of tiffs. Pass it a full pathname to the file. Hope it helps someone. (extracted from MSDN)
public static string[] ConvertJpegToTiff(string[] fileNames, bool isMultipage)
{
EncoderParameters encoderParams = new EncoderParameters(1);
ImageCodecInfo tiffCodecInfo = ImageCodecInfo.GetImageEncoders()
.First(ie => ie.MimeType == "image/tiff");
string[] tiffPaths = null;
if (isMultipage)
{
tiffPaths = new string[1];
System.Drawing.Image tiffImg = null;
try
{
for (int i = 0; i < fileNames.Length; i++)
{
if (i == 0)
{
tiffPaths[i] = String.Format("{0}\\{1}.tif",
Path.GetDirectoryName(fileNames[i]),
Path.GetFileNameWithoutExtension(fileNames[i]));
// Initialize the first frame of multipage tiff.
tiffImg = System.Drawing.Image.FromFile(fileNames[i]);
encoderParams.Param[0] = new EncoderParameter(
System.Drawing.Imaging.Encoder.SaveFlag, (long)EncoderValue.MultiFrame);
tiffImg.Save(tiffPaths[i], tiffCodecInfo, encoderParams);
}
else
{
// Add additional frames.
encoderParams.Param[0] = new EncoderParameter(
System.Drawing.Imaging.Encoder.SaveFlag, (long)EncoderValue.FrameDimensionPage);
using (System.Drawing.Image frame = System.Drawing.Image.FromFile(fileNames[i]))
{
tiffImg.SaveAdd(frame, encoderParams);
}
}
if (i == fileNames.Length - 1)
{
// When it is the last frame, flush the resources and closing.
encoderParams.Param[0] = new EncoderParameter(
System.Drawing.Imaging.Encoder.SaveFlag, (long)EncoderValue.Flush);
tiffImg.SaveAdd(encoderParams);
}
}
}
finally
{
if (tiffImg != null)
{
tiffImg.Dispose();
tiffImg = null;
}
}
}
else
{
tiffPaths = new string[fileNames.Length];
for (int i = 0; i < fileNames.Length; i++)
{
tiffPaths[i] = String.Format("{0}\\{1}.tif",
Path.GetDirectoryName(fileNames[i]),
Path.GetFileNameWithoutExtension(fileNames[i]));
// Save as individual tiff files.
using (System.Drawing.Image tiffImg = System.Drawing.Image.FromFile(fileNames[i]))
{
tiffImg.Save(tiffPaths[i], ImageFormat.Tiff);
}
}
}
return tiffPaths;
}
ImageMagick command line can do that easily. It is supplied on most Linux systems and is available for Mac or Windows also. See https://imagemagick.org/script/download.php
convert image.suffix -compress XXX image.tiff
or you can process a whole folder of files using
mogrify -format tiff -path path/to/output_directory *
ImageMagick supports combining multiple images into a multi-page TIFF. And the images can be of mixed types even including PDF.
convert image1.suffix1 image2.suffix2 ... -compress XXX imageN.suffixN output.tiff
You can choose from a number of compression formats or no compression.
See
https://imagemagick.org/script/command-line-processing.php
https://imagemagick.org/Usage/basics/
https://imagemagick.org/Usage/basics/#mogrify
https://imagemagick.org/script/command-line-options.php#compress
Or you can use Magick.Net for a C# interface. See https://github.com/dlemstra/Magick.NET
Main ImageMagick page is at https://imagemagick.org.
Supported formats are listed at https://imagemagick.org/script/formats.php
You can easily process your images to resize them, convert to grayscale, filter (sharpen), threshold, etc, all in the same command line.
See
https://imagemagick.org/Usage/
https://imagemagick.org/Usage/reference.html
This is how I convert images that are uploaded to a website. Changed it so it outputs Tiff files. The method input and outputs a byte array so it can easily be used in a variety of ways. But you can easily modify it.
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
public byte[] ConvertImageToTiff(byte[] SourceImage)
{
//create a new byte array
byte[] bin = new byte[0];
//check if there is data
if (SourceImage == null || SourceImage.Length == 0)
{
return bin;
}
//convert the byte array to a bitmap
Bitmap NewImage;
using (MemoryStream ms = new MemoryStream(SourceImage))
{
NewImage = new Bitmap(ms);
}
//set some properties
Bitmap TempImage = new Bitmap(NewImage.Width, NewImage.Height);
using (Graphics g = Graphics.FromImage(TempImage))
{
g.CompositingMode = CompositingMode.SourceCopy;
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(NewImage, 0, 0, NewImage.Width, NewImage.Height);
}
NewImage = TempImage;
//save the image to a stream
using (MemoryStream ms = new MemoryStream())
{
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 80L);
NewImage.Save(ms, GetEncoderInfo("image/tiff"), encoderParameters);
bin = ms.ToArray();
}
//cleanup
NewImage.Dispose();
TempImage.Dispose();
//return data
return bin;
}
//get the correct encoder info
public ImageCodecInfo GetEncoderInfo(string MimeType)
{
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
for (int j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType.ToLower() == MimeType.ToLower())
return encoders[j];
}
return null;
}
To test
var oldImage = File.ReadAllBytes(Server.MapPath("OldImage.jpg"));
var newImage = ConvertImageToTiff(oldImage);
File.WriteAllBytes(Server.MapPath("NewImage.tiff"), newImage);

A generic error occurred in GDI+. Occurs only on production environment. (WebAPI)

I have a function that accepts a work-id string and generates a QRcode using the ZXing library and saves the image to to disk via Bitmap.save() method.The problem is non existent in my local machine and everything works fine but the GDI exception is thrown on production environment which works fine for a while but after some hours or sometimes after a day and an empty file is generated and the exception resolved only by recycling application pool. I have tried everything i can find from checking permissions to file path to memory analysis disposing the the bitmap but nothing seems to work.
public QRCodeModel GenerateQRCode(QRCodeModel obj, UserProfile profile)
{
try
{
string base64Image = "";
var writer = new BarcodeWriter();
writer.Format = BarcodeFormat.QR_CODE;
writer.Options.Height = 70;
writer.Options.Width = 70;
writer.Options.Margin = 0;
var result = writer.Write(obj.WORK_ID.ToString());
if (!Directory.Exists(obj.AbsolutePath))
{
Directory.CreateDirectory(obj.AbsolutePath);
}
using (var bitmap = new Bitmap(result))
{
//bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
//base64Image = Convert.ToBase64String(ms.GetBuffer()); //Get Base64
string curtime=obj.AbsolutePath+obj.WORK_ID+ DateTime.Now.Ticks.ToString() + ".png";
bitmap.Save(curtime, System.Drawing.Imaging.ImageFormat.Png);
base64Image = Convert.ToBase64String(File.ReadAllBytes(curtime)); //Get Base64
}
//}
string src = "data:image/png;base64," + base64Image;
string encodedString = HttpUtility.UrlEncode(src);
obj.ENCODED_IMAGE_BYTES = encodedString;
return obj;
}
catch (Exception ex)
{
throw ex;
}
}

Deleting file throws file in use exception

I have a file upload control that allows users to upload an image file. Rather then forcing them to use a specific size image, I am trying to resize it, save it the resized version to a folder and then delete the original.
When I try to delete the file, I keep getting "file in use" exception. I have searched and tried all suggestions to no avail.
This is the latest try, at which point I decided to seek help. I pass the source path (where original file is in, a destination path where resized file is to end up in, file name and width to which it should be resized, keeping aspect ratio):
public static void CreateResizedCopy(String sourcePath, String destinationPath, String filename, int width)
{
if (!File.Exists(destinationPath + filename))
{
System.Drawing.Image image = System.Drawing.Image.FromFile(sourcePath + filename);
float AspectRatio = (float)image.Size.Width / (float)image.Size.Height;
int newHeight = Convert.ToInt32(width / AspectRatio);
Bitmap thumbnailBitmap = new Bitmap(width, newHeight);
Graphics thumbnailGraph = Graphics.FromImage(thumbnailBitmap);
thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
var imageRectangle = new Rectangle(0, 0, width, newHeight);
thumbnailGraph.DrawImage(image, imageRectangle);
thumbnailBitmap.Save(destinationPath + filename, ImageFormat.Jpeg);
thumbnailGraph.Dispose();
thumbnailBitmap.Dispose();
image.Dispose();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
if (!FileInUse(sourcePath + filename))
{
File.Delete(sourcePath + filename);
}
else
{
// Error here: file is in use
using (FileStream fs = new FileStream(sourcePath + filename, FileMode.OpenOrCreate))
fs.Dispose();
}
}
}
public static bool FileInUse(string path)
{
try
{
using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
{
return false;
}
}
catch (IOException ex)
{
return true;
}
}
UPDATE
This is the AJAX AsynFileUpload's upload completed event handler. It saves the file to a "Resize" folder. If image needs to be resized, it calls the method to resize it and then moves it to its final resting place. If not, no resizing is done, it just moves the file. It then "attempts" to delete the file in resize folder and it chokes!
protected void fuNewsImage_UploadedComplete_Resize(object sender, AsyncFileUploadEventArgs e)
{
if (fuNewsImage.HasFile)
{
HttpPostedFile file = fuNewsImage.PostedFile;
string sFileName = fuNewsImage.FileName;
string sFileSize = e.FileSize;
string sSaveFolder = ImageFilePath.TEMP_FOLDER_EA_TEST + "\\";
string sResizeFolder = ImageFilePath.TEMP_FOLDER_EA_TEST + "\\Resized\\";
fuNewsImage.SaveAs(Server.MapPath(sResizeFolder + sFileName));
System.Drawing.Image img = System.Drawing.Image.FromFile(Server.MapPath(sResizeFolder) + sFileName);
int iImgWidth = img.Width;
int iImgHeight = img.Height;
if (iImgWidth > ImageInfo.MAX_WIDTH)
{
// sSaveFolder is the efinal resting place of the uploaded image
// If image width is more than max allowed, resize it, save it in sSaveFolder
Utils.CreateResizedCopy(Server.MapPath(sResizeFolder), Server.MapPath(sSaveFolder), sFileName, 600);
System.Threading.Thread.Sleep(1000);
File.Delete(Server.MapPath(sSaveFolder + sFileName));
}
else // just move it t sSaveFolder
{
File.Move(Server.MapPath(sResizeFolder) + sFileName, Server.MapPath(sSaveFolder) + sFileName);
}
// --- Chokes here ---
Array.ForEach(Directory.GetFiles(Server.MapPath(sResizeFolder)), File.Delete);
}
}

Picture appears only after restart the device

I have an Android-App that takes pictures and saves them in an external storage ("DCIM/Cameras"). But the pictures appear only after restarting my handy.
Is there some kind of Update or a way around this?
My source-code from saving my image:
var dir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim);
var pictures = dir.AbsolutePath + "/Camera";
string name = System.DateTime.Now.ToString("yyyyMMdd_HHmmssfff") + ".jpg";
string filePath = System.IO.Path.Combine(pictures, name);
FileStream output;
Bitmap bitmap = BitmapFactory.DecodeByteArray(imageData, 0, imageData.Length);
try
{
output = new FileStream(filePath, FileMode.Create);
bitmap.Compress(Bitmap.CompressFormat.Jpeg, 100, output);
output.Close();
//Static Class that contains an methode for MediaScannerConnection.ScanFile
MediaGalleryHelper.AddFileToGallery(name);
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex.ToString());
}
You have to let the photo gallery know that a new photo has been added. You can use below code for that:
this.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + filePath)));
Where 'this' is an activity.

Scanning using nTwain

I do perform a scan using nTwain lib from NuGet.
I catch the DataTransferred event to save the result image.
What I have in a result is some ImageInfo and null byte[] massive of information.
Is anyone aware of this library and can tell me if I am doing something wrong?
void session_DataTransferred(object sender, NTwain.DataTransferredEventArgs e)
{
Image img = ImageFromBytes(e.MemoryData);
myDS.Close();
session.Close();
}
But the e comes only with ImageInfo.
Update
Argument screenshot if useful ...
For NTwain, you should have more than just ImageInfo for that event. Specifically, e should have ImageInfo, MemData, and NativeData as you are showing in the screenshot.
I haven't done a whole lot with it but what I do in a console utility is to check if e.NativeData != IntPtr.Zero and pull a bitmap from the DIB pointer (Windows, it is a TIFF for Linux) . For this purpose, I am using another dependency CommonWin32.dll. I believe this is a similar method to the examples included in NTwain's starting solution package (look under Tests for a sample Console, WinForm, and WPF project).
If I want to save out a different file type, I do a encoding at that point. You can save a System.Drawing.Image with a given encoding. Obviously, that could be alot better (set the type and compression to make the transfer smaller) but it is a working example.
if (e.NativeData != IntPtr.Zero)
{
Bitmap img = null;
if (this._commands.CheckForDebug())
{
Console.WriteLine("Image data transferred.");
}
//Need to save out the data.
img = e.NativeData.GetDrawingBitmap();
if (img != null)
{
string fileName = "RandomFileName.";
string fileType = this._commands.GetFileType();
switch (fileType)
{
case "png":
fileName += "png";
ImageExtensions.SavePNG(img, fileName, 50L);
break;
case "jpeg":
fileName += "jpeg";
ImageExtensions.SaveJPEG(img, fileName, 50L);
break;
default:
fileName += "png";
ImageExtensions.SavePNG(img, fileName, 50L);
break;
}
}
}
public static void SaveJPEG(Image img, string filePath, long quality)
{
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
img.Save(filePath, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}

Categories