ExternalException: A generic error occurred in GDI+ - c#

I am using Selenium WebDriver in C# and
I am trying to dynamically create a folder and save screenshots of failing tests to it.
Here I am running the group of test cases (Test Suite of 66 test cases).
After running the test suite I found few failed tests with GDI+ error and were not captured as a screenshot.
But when I run them individually most of the failed cases (GDI+ error) were passing except few.
Here is the code for creating a folder:
TestExecutionStartTime = DateTime.Now;
baseDirectory = AppDomain.CurrentDomain.BaseDirectory + #"\" + ConfigurationManager.AppSettings.GetValues("failedTests")[0];
Browser = ConfigurationManager.AppSettings["WebDriver"];
DirectoryInfo directory = new DirectoryInfo(baseDirectory);
DirectoryInfo[] subdirs = directory.GetDirectories();
if (System.IO.Directory.GetDirectories(baseDirectory).Length == 0)
{
screenshotDirectory = baseDirectory + #"\" + (DateTime.Now.ToString("yyyy_MM_dd_hh_mm") + "_" + Browser);
Directory.CreateDirectory(screenshotDirectory);
}
Here is the code for taking screenshot:
public void takeScreenshot(string filename)
{
string fname = filename + ".jpg";
string screenshot = screenshotDirectory + #"\" + fname;
Screenshot ss = ((ITakesScreenshot)WebDriver).GetScreenshot();
byte[] image = ss.AsByteArray;
using (MemoryStream ms = new MemoryStream(image))
{
Image i = Image.FromStream(ms);
i.Save(screenshot);
}
I assume that the error is at this i.Save(screenshot) call, but I was not able to resolve it.

I have reason to believe (from experience) that your issue comes about as a result of the stream being destroyed while it is being saved (the using statement).
Things to be aware of:
Write permissions wherever you are saving the image
Make sure the path is correct - this will throw a GDI+ exception and is very misleading, verify your path, try a temporary directory instead of creating your custom image directory to rule this one out.
Make sure the height of the image is not bigger than (65534px)
You can verify this by looking at the size:
var bitmapTemp = new Bitmap(stream);
Console.WriteLine(bitmapTemp.Height);
Here's some code that destroys the stream only after the image is saved:
public static Screenshot GetScreenshot(ChromeDriver driver)
{
Screenshot ss = ((ITakesScreenshot)driver).GetScreenshot();
return ss;
}
public static void SaveScreenshot(byte[] byteArray, string location)
{
var stream = new MemoryStream(byteArray);
var img = Image.FromStream(stream);
img.Save(location);
stream.Dispose();
}
And use the functions like so:
var path = AppDomain.CurrentDomain.BaseDirectory;
var ss = GetScreenshot(driver);
SaveScreenshot(ss.AsByteArray, path + "imagename.jpg");

Thanks for your inputs AntonB.
I have considered your points and tried differently and got the solution.
i have used [SetUpFixture], [OneTimeSetUp] and [OneTimeTearDown] to create folder only once and it solved the problem.
Here is the code:
[SetUpFixture]
public class Config
{
public Config()
{
}
public string baseDirectory;
public static string screenshotDirectory;
[OneTimeSetUp]
public void SetUp()
{
Console.WriteLine("Creating a folder to capture failed scenarios");
baseDirectory = AppDomain.CurrentDomain.BaseDirectory + #"\" + ConfigurationManager.AppSettings.GetValues("failedTests")[0];
string Browser = ConfigurationManager.AppSettings["WebDriver"];
screenshotDirectory = baseDirectory + #"\" + (DateTime.Now.ToString("yyyy_MM_dd_hh_mm") + "_" + Browser);
Directory.CreateDirectory(screenshotDirectory);
}
[OneTimeTearDown]
public void TearDown()
{
}
}

Related

Core mvc: Files not getting saved in wwwroot folder but creating files with "wwwroot.....jpg" name in the root

The image uploading is working perfectly in the development server in the windows environment but when I run the code in the Remote Linux server, the files get uploaded but in the root folder and for which the files can not be accessed by the website.
public async Task<IActionResult> Index(IList<IFormFile> files,Type type)
{
Startup.Progress = 0;
foreach (IFormFile source in files)
{
if (isFileImage(source))
{
string filename = ContentDispositionHeaderValue.Parse(source.ContentDisposition).FileName.ToString().Trim('"');
filename = this.EnsureCorrectFilename(filename);
string serverFilePath = this.GetPathAndFilename(filename);
try
{
await source.CopyToAsync(new FileStream(serverFilePath,FileMode.Create));
}
catch (Exception e)
{
}
finally
{
}
}
}
return Content("Success");
}
private string GetPathAndFilename(string filename)
{
string path = Path.Combine(Directory.GetCurrentDirectory(),#"wwwroot\images\materials", filename);
return path;
}
This is the code responsible for uploading an image. In the development windows environment, it works perfectly as the files get saved in the "wwwroot\images\materials" folder.
But when the code is run the Remote Linux serves the files get uploaded but are saved in the root folder with "wwwroot\images\materials*.jpg" name. Even when running the code in development mode in the Remote server this problem occurs.
Since you're using Path.Combine I would suggest passing each part of the path as a parameter. So instead of #"wwwroot\images\materials" as one parameter, you would pass them separately "wwwroot", "images", "materials".
Try this simple. In this you have to inject _hostingEnvironment so you can get ContentRootPath
string folderName = "Upload/Profile/" + user.Id;
string webRootPath = _hostingEnvironment.ContentRootPath;
string newPath = Path.Combine(webRootPath, folderName);
if (!Directory.Exists(newPath))
{
Directory.CreateDirectory(newPath);
}
string extention = file.ContentType.Split("/")[1];
string fileName = user.Id + ".jpg";
string fullPath = Path.Combine(newPath, fileName);
string envpath = folderName + "/" + fileName;
using (var stream = new FileStream(fullPath, FileMode.Create))
{
file.CopyTo(stream);
}

Saving bitmap to gallery in Android

I thought that should be simple, yet I can't figure it out.
I keep getting the error: System.IO.DirectoryNotFoundException: Could not find a part of the path "/storage/emulated/0/Pictures/Screenshots/name.jpg".
The code:
string root = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).Path;
File myDir = new File(root + "/Screenshots");
myDir.Mkdirs();
string timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").Format(new Date());
string fname = CommunicationHandler.GetNickname() + "|" + timeStamp + ".jpg";
File file = new File(myDir, fname);
if (file.Exists())
file.Delete();
try
{
using (System.IO.Stream outStream = System.IO.File.Create(file.Path))
{
finalBitmap.Compress(Bitmap.CompressFormat.Jpeg, 100, outStream);
outStream.Flush();
outStream.Close();
}
}
catch (Exception e)
{
Toast.MakeText(Activity, e.ToString(), ToastLength.Long).Show();
}
Also, I can't access manually to /storage/emulated/0..
Why can't I manage to save the bitmap to my phone gallery? What's the problem in the code above?
If you want to create a new directory, you can use System.IO.Directory.CreateDirectory(root); to create it.
//create a directory called MyCamera
string root = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDcim).ToString() + "/MyCamera/";
//create the Directory
System.IO.Directory.CreateDirectory(root);
As taken from here:
MediaScannerConnection.scanFile(this, new String[]{file.toString()}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
}
Also, note that you could just add an image to the gallery via a simple line:
MediaStore.Images.Media.insertImage(applicationContext.getContentResolver(), IMAGE ,"nameofimage" , "description");

A generic error occured in GDI+ while saving image

I have to save an image in post request in byte64String format
when i save that image i get A generic error occurred in GDI+
here is my code
byte[] ix = Convert.FromBase64String(obj.Image);
var ID = obj.Id;
using (var mStream = new MemoryStream(ix))
{
var img = Image.FromStream(mStream);
var image = obj.ImageName + ".jpg";
string path = HostingEnvironment.MapPath("/Images/" + ImageType + "/" + ID + "/" + image);
System.IO.Directory.CreateDirectory(path);
try
{
img.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch (Exception e)
{
var d = e;
}
}
also
this is not a permission issue as i am able to create text files in the same directory
Quite simply you are confusing paths and filenames.
The problem if could hazzard a guess, you probably have a folder that is your filename, and you are trying to save a file with that same name, which windows forbids
Your code tweaked
var image = $"{obj.ImageName }.jpg";
// get the path, and only the path
string path = HostingEnvironment.MapPath($"/Images/{ImageType}/{ID}/");
// Create directory if needed (from that path)
Directory.CreateDirectory(path,image);
...
// now create the correct full path
var fullPath = Path.Combine(path,fileName);
// save
img.Save(fullPath, ImageFormat.Jpeg);

Extracting JPG Image From MP4 Video

I am using the below method to extract an image from a uploaded video and placing the image into a folder.
private string GeneratePreviewImageMP4(string FileName, HttpPostedFile file, string ProperPath)
{
string inputfile = System.IO.Path.Combine(Server.MapPath(ProperPath), file.FileName);
string ext = System.IO.Path.GetExtension(FileName);
string thumbpath = AppDomain.CurrentDomain.BaseDirectory + "Reports\\TrainingLibrary\\Videothumbnails\\";
string thumbname = thumbpath + FileName.Replace(ext, "") + ".jpg";
string thumbargs = "-i " + inputfile + " -ss 00:00:25.435 -qscale:v 2 -vframes 1 " + thumbname;
Process thumbproc = new Process();
thumbproc.StartInfo.FileName = "C:\\FFMPEG\\Bin\\ffmpeg.exe";
thumbproc.StartInfo.Arguments = thumbargs;
thumbproc.StartInfo.UseShellExecute = false;
thumbproc.StartInfo.CreateNoWindow = false;
thumbproc.StartInfo.RedirectStandardOutput = false;
try
{
thumbproc.Start();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
thumbproc.WaitForExit();
thumbproc.Close();
return FileName.Replace(ext, ".jpg");
}
The issue, is that once the image is extracted, I get locked out of the folder. No body has admin rights to that folder. We have to restart the Server just to restore access to that folder.
This is only at certain times, most of the time it works great, but one out of ten times there will be an issue.
Anyone now why this is happening? Does it play the video to extract the image, but does not stop the video?
Try calling Dispose on thumbproc after you are done using it
Try using a lock:
lock (_aStaticObject)
{
//All the code above
}
A word of warning, it can be bad for performance to use a lock inside of a http request (thou shall not mess with thy server's threads), which is why this type of thing belongs in a job.

saving text to a file

I have a question that's driving me nuts. I have a program that saves error messages to a string in an object, then writes the string to a file in the unloadContent() thing. For some reason I keep getting Not Supported Exceptions. Here is the code in unloadContent():
if (debug.getContent().Length > 0)
{
saveErrors save = new saveErrors();
if (Directory.Exists(System.IO.Directory.GetCurrentDirectory() + "\\Errors")) ;
Directory.CreateDirectory(System.IO.Directory.GetCurrentDirectory() + "\\Errors");
save.save(System.IO.Directory.GetCurrentDirectory().ToString() + "\\Errors\\errorLog_" + (System.DateTime.Now.ToString().Replace("/", "_")).Replace(" ","") + ".txt");
}
and here's the code in class save errors:
public class saveErrors
{
private string mess = debug.getContent();
public void save(string fileName)
{
Debug.WriteLine(fileName);
using (StreamWriter sw = new StreamWriter(fileName))
{
sw.Write(mess);
sw.Close();
}
}
}
I'm still a bit new to C#, so any help would be greatly appreciated!
Thanks!
Try this:
[Test]
public void SaveTextTest()
{
string relativePath=#"Errors\errorLog_";
string directoryPath = System.IO.Path.Combine( System.IO.Directory.GetCurrentDirectory() , relativePath);
var directoryInfo = new DirectoryInfo(directoryPath);
if(directoryInfo.Exists==false)
directoryInfo.Create();
string fileName = System.DateTime.Now.ToString("yyyy-MM-dd_hh-mm-ss") + ".txt";
string path = System.IO.Path.Combine(directoryPath, fileName);
string textToSave = "This will be saved";
File.WriteAllText(path, textToSave);
}
To get the DateTime.ToString() in the desired format you can pass a formatstring
save.save(System.IO.Directory.GetCurrentDirectory().ToString() + "\\Errors\\errorLog_" + (System.DateTime.Now.ToString().Replace("/", "_")).Replace(" ", "").Replace(":", "") + ".txt");
Change it to that. You need a .Replace(":", "") because : Is included in the date part of the code, but is invalid in a file name, so you must either remove it or replace it with something else.
As an alternative you could format the date as so:
save.save(System.IO.Directory.GetCurrentDirectory().ToString() + "\\Errors\\errorLog_" + System.DateTime.Now.ToString("yyyy-MM-dd_hh-mm-ss"));

Categories

Resources