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);
}
}
Related
I'm taking a screenshot in a Unity application using
ScreenCapture.CaptureScreenshot ("screenshot.png", 2);
But the AR background being rendered by ARKit ends up being completely black with other GameObjects rendering correctly (floating in black space).
Have others encountered this issue?
Is there a known workaround?
There are too many bugs with ScreenCapture.CaptureScreenshot. Do not use this function to preform any screenshot in Unity at this moment. It's not just on iOS, there are also bug on with this function in the Editor.
Here is a remake of that function that can take screenshot in png, jpeg or exr format.
IEnumerator CaptureScreenshot(string filename, ScreenshotFormat screenshotFormat)
{
//Wait for end of frame
yield return new WaitForEndOfFrame();
Texture2D screenImage = new Texture2D(Screen.width, Screen.height);
//Get Image from screen
screenImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
screenImage.Apply();
string filePath = Path.Combine(Application.persistentDataPath, "images");
byte[] imageBytes = null;
//Convert to png/jpeg/exr
if (screenshotFormat == ScreenshotFormat.PNG)
{
filePath = Path.Combine(filePath, filename + ".png");
createDir(filePath);
imageBytes = screenImage.EncodeToPNG();
}
else if (screenshotFormat == ScreenshotFormat.JPEG)
{
filePath = Path.Combine(filePath, filename + ".jpeg");
createDir(filePath);
imageBytes = screenImage.EncodeToJPG();
}
else if (screenshotFormat == ScreenshotFormat.EXR)
{
filePath = Path.Combine(filePath, filename + ".exr");
createDir(filePath);
imageBytes = screenImage.EncodeToEXR();
}
//Save image to file
System.IO.File.WriteAllBytes(filePath, imageBytes);
Debug.Log("Saved Data to: " + filePath.Replace("/", "\\"));
}
void createDir(string dir)
{
//Create Directory if it does not exist
if (!Directory.Exists(Path.GetDirectoryName(dir)))
{
Directory.CreateDirectory(Path.GetDirectoryName(dir));
}
}
public enum ScreenshotFormat
{
PNG, JPEG, EXR
}
USAGE:
void Start()
{
StartCoroutine(CaptureScreenshot("screenshot", ScreenshotFormat.PNG));
}
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.
I want to watermark files in a folder with another image. However, am getting the error
'Parameter Not Valid'
when invoking the code
img.Save(filepath, System.Drawing.Imaging.ImageFormat.Jpeg);
I have the following code;
public static string WatermarkImagesInFolder(string url)
{
if (url == null)
throw new Exception("URL must be provided");
string path = HttpContext.Current.Server.MapPath(url);
if (!Directory.Exists(path))
throw new DirectoryNotFoundException();
Directory.CreateDirectory(String.Format(#"{0}\watermarked", path));
List<string> urls = GetJpgFilesFromFolder(path);
foreach (string imageUrl in urls)
{
Image img = WatermarkImage(imageUrl);
string filename = Path.GetFileName(imageUrl);
string filepath = String.Format(#"{0}\watermarked\{1}", path, filename);
img.Save(filepath, System.Drawing.Imaging.ImageFormat.Jpeg);
}
return "complete";
}
and
public static Image WatermarkImage(string filename)
{
using (Image image = Image.FromFile(filename))
using (Image watermarkImage = Image.FromFile(HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["WatermarkImageUrl"])))
using (Graphics imageGraphics = Graphics.FromImage(image))
using (TextureBrush watermarkBrush = new TextureBrush(watermarkImage))
{
int x = (image.Width / 2 - watermarkImage.Width / 2);
int y = (image.Height / 2 - watermarkImage.Height / 2);
watermarkBrush.TranslateTransform(x, y);
imageGraphics.FillRectangle(watermarkBrush, new Rectangle(new Point(x, y), new Size(watermarkImage.Width + 1, watermarkImage.Height)));
return image;
}
}
as an example of input for img.save;
img.save("C:\\IMAGES\\wateremarked\\IMAGE (1).jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
any ideas on what could be causing the error here please?
In your WatermarkImage you have the image object in a using statement. As soon as that goes out of scope, Dispose is invoked on the image. You would need to return a copy of the image - or not use the using statement & ensure you dispose properly later.
See : Exception: Parameter is not valid (on passing new image to pictureBox)
public static string WatermarkImagesInFolder(string url)
{
if (url == null)
throw new Exception("URL must be provided");
string path = HttpContext.Current.Server.MapPath(url);
if (!Directory.Exists(path))
throw new DirectoryNotFoundException();
Directory.CreateDirectory(String.Format(#"{0}\watermarked", path));
List<string> urls = GetJpgFilesFromFolder(path);
foreach (string imageUrl in urls)
{
using(Image img = WatermarkImage(imageUrl))
{
string filename = Path.GetFileName(imageUrl);
string filepath = String.Format(#"{0}\watermarked\{1}", path, filename);
img.Save(filepath, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
return "complete";
}
public static Image WatermarkImage(string filename)
{
Image image = Image.FromFile(filename);
using (Image watermarkImage = Image.FromFile(HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["WatermarkImageUrl"])))
using (Graphics imageGraphics = Graphics.FromImage(image))
using (TextureBrush watermarkBrush = new TextureBrush(watermarkImage))
{
int x = (image.Width / 2 - watermarkImage.Width / 2);
int y = (image.Height / 2 - watermarkImage.Height / 2);
watermarkBrush.TranslateTransform(x, y);
imageGraphics.FillRectangle(watermarkBrush, new Rectangle(new Point(x, y), new Size(watermarkImage.Width + 1, watermarkImage.Height)));
return image;
}
}
Here is my alternative solution, which gives the ability to use picture stream, but not it's location as it's currently browsed from Kendo Control as in my example and it still have not physical location yet.
public static Image ApplyWatermark(HttpPostedFileBase img, string appDataPath)
{
Image resultImage = null;
using (Image image = Image.FromStream(img.InputStream))
{
using (Image watermarkImage = Image.FromFile(appDataPath + "\\Watermark\\sample-watermark.png"))
{
using (Graphics imageGraphics = Graphics.FromImage(image))
{
using (Brush watermarkBrush = new TextureBrush(watermarkImage))
{
imageGraphics.FillRectangle(watermarkBrush, new Rectangle(new Point(0, 0), image.Size));
resultImage = (Image)image.Clone();
}
}
}
}
return resultImage;
}
private void SaveImagesOnDisk(IEnumerable<HttpPostedFileBase> images, int rentalPropertyId)
{
if (images != null)
{
foreach (var file in images)
{
// Some browsers send file names with full path. This needs to be stripped.
var fileName = Path.GetFileName(file.FileName);
var appDataPath = this.Server.MapPath("~/App_Data/");
var newPath = Path.Combine(appDataPath, rentalPropertyId.ToString());
if (!Directory.Exists(newPath))
{
DirectoryInfo di = Directory.CreateDirectory(newPath);
}
var physicalPath = Path.Combine(newPath, fileName);
System.Drawing.Image markedImage = Helper.ApplyWatermark(file, appDataPath);
markedImage.Save(physicalPath, System.Drawing.Imaging.ImageFormat.Png);
}
}
//return this.Json(new { status = "OK" }, "text/plain");
}
I'm implementing "copy map to clip" as an image.
what I do is I create an image an save it to certain directory and copy it to clipboard.
but before I do that I delete every file that exist in the directory, but now I cant since, the image is being used by clipboard.
here's my code.
public override void OnClick()
{
//base.OnClick();
DeleteOldCopiedJPG();
System.Windows.Forms.Clipboard.Clear();
string fileName = System.Windows.Forms.Application.ExecutablePath.Substring(0, System.Windows.Forms.Application.ExecutablePath.LastIndexOf("\\") + 1) + Guid.NewGuid() + ".jpg";
//System.Windows.Forms.Cursor.Current = Cursors.Wait;
//if (System.IO.File.Exists(fileName))
// System.IO.File.Delete(fileName);
IExport objExport = (IExport)new ExportJPEG();
objExport.ExportFileName = fileName;
#if Debug || Release
ESRI.ArcGIS.Display.tagRECT objExportRECT = default( ESRI.ArcGIS.Display.tagRECT);
#else
tagRECT objExportRECT = default(tagRECT);
#endif
var _with1 = objExportRECT;
_with1.left = mapControl.ActiveView.ExportFrame.left;
_with1.top = mapControl.ActiveView.ExportFrame.top;
_with1.right = mapControl.ActiveView.ExportFrame.right;
_with1.bottom = mapControl.ActiveView.ExportFrame.bottom;
IEnvelope envelope = new EnvelopeClass();
envelope.PutCoords(mapControl.ActiveView.ExportFrame.left, mapControl.ActiveView.ExportFrame.top,
mapControl.ActiveView.ExportFrame.right, mapControl.ActiveView.ExportFrame.bottom);
objExport.PixelBounds = envelope;
System.Int32 intHDC = objExport.StartExporting();
mapControl.ActiveView.Output(intHDC, Convert.ToInt16(objExport.Resolution), objExportRECT, null, null);
objExport.FinishExporting();
objExport.Cleanup();
System.Drawing.Image objImage = System.Drawing.Bitmap.FromFile(fileName);
System.Windows.Forms.Clipboard.SetImage(objImage);
//RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32);
//renderTargetBitmap.Render((Visual)mapControl.ActiveView.ScreenDisplay);
//Clipboard.SetImage(renderTargetBitmap);
}
private void DeleteOldCopiedJPG(string Path)
{
string[] filePaths = Directory.GetFiles(System.Windows.Forms.Application.ExecutablePath.Substring(0, System.Windows.Forms.Application.ExecutablePath.LastIndexOf("\\") + 1));
foreach (string filepath in filePaths)
if (filepath.Substring(filepath.Length - 4) == ".jpg")
try{ File.Delete(filepath); } catch {}
}
You need to dispose the image after inserting it into the clipboard:
using (System.Drawing.Image objImage = System.Drawing.Bitmap.FromFile(fileName))
{
System.Windows.Forms.Clipboard.SetImage(objImage);
}
Otherwise it will remain open until the garbage collector calls the finalizer for objImage.
Imagename = objUser.UserID + filename;
Imagepath = "D:\\Shop\\ShopMonkey\\Images" + Imagename;
FileUpload.SaveAs(Path.Combine(#"D:\ShopMonkey_Web_21-6-12\ShopMonkey\Images", Imagename));
objUser.UploadImagePath = Imagepath;
objUser.UploadImagename = Imagename;
System.Drawing.Image img1 = System.Drawing.Image.FromFile(Imagepath);
System.Drawing.Image bmp1 = img1.GetThumbnailImage(50, 50, null, IntPtr.Zero);
ThumbNailPath = "D:\\ShopMonkey_Web_21-6-12\\ShopMonkey\\ThumbNails" + Imagename;
bmp1.Save(Path.Combine(#"D:\ShopMonkey_Web_21-6-12\ShopMonkey\ThumbNails", Imagename));
objUser.UploadThumbnailPath = ThumbNailPath;
How to delete the image and thumbnail in other function? (Is it necessary to close that first or not?)
I'm guessing that you're trying to delete a file on disk if it already exists for this user upon asp.net upload of an image by that same user again.
This method will delete both image and thumbnail if they exist.
Keep your image creation activities separate from your image clean up activities to keep your intent clear and your code maintainable.
// replace with an entry loaded from a config file
const string ImageRoot = #"D:\ShopMonkey_Web_21-6-12\ShopMonkey";
// replace this is your user instance
object user = new object();
string Imagename = objUser.UserID + filename;
string uploadImagePath = Path.Combine(ImageRoot, "Images", Imagename);
string thumbnailPath = Path.Combine(ImageRoot, "ThumbNails", Imagename);
objUser.UploadImagePath = uploadImagePath;
objUser.UploadImagename = Imagename;
objUser.UploadThumbnailPath = thumbnailPath;
// delete both if they exist
if (File.Exists(uploadImagePath))
File.Delete(uploadImagePath);
if (File.Exists(thumbnailPath))
File.Delete(thumbnailPath);
// replace this with your uploaded file details
object fileInfo = new object();
using (System.Drawing.Image img1 = System.Drawing.Image.FromFile(uploadImagePath)) {
img1.Save(uploadImagePath);
using (System.Drawing.Image bmp1 = img1.GetThumbnailImage(50, 50, null, IntPtr.Zero)) {
bmp1.Save(thumbnailPath);
}
FileUpload.SaveAs(uploadImagePath);
}