I am trying to use the .net ImageResizer to save an image to a specified size. I am unable to save a smaller image to larger dimensions with the current code I am using. For example, I upload an image that is 200x200, the _thumb version will be saved as 100x100 but the _medium and _large versions will still be 200x200.
How can I save the uploaded image to the specified larger images? Such as versions.Add("_extraLarge", "width=2000&height=2000&crop=auto&format=jpg"); or versions.Add("_XXL", "width=auto&height=3000&crop=auto&format=jpg");
//GenerateVersions(FileUpload1.PostedFile.FileName);
Dictionary<string, string> versions = new Dictionary<string, string>();
//Define the versions to generate
versions.Add("_thumb", "width=100&height=100&crop=auto&format=jpg"); //Crop to square thumbnail
versions.Add("_medium", "maxwidth=400&maxheight=400&format=jpg"); //Fit inside 400x400 area, jpeg
versions.Add("_large", "maxwidth=1900&maxheight=1900&format=jpg"); //Fit inside 1900x1200 area
//Loop through each uploaded file
foreach (string fileKey in HttpContext.Current.Request.Files.Keys)
{
HttpPostedFile file = HttpContext.Current.Request.Files[fileKey];
if (file.ContentLength <= 0) continue; //Skip unused file controls.
//Get the physical path for the uploads folder and make sure it exists
string uploadFolder = MapPath("~/uploadsAIM");
if (!Directory.Exists(uploadFolder)) Directory.CreateDirectory(uploadFolder);
//Generate each version
foreach (string suffix in versions.Keys)
{
////Generate a filename (GUIDs are best).
//string fileName = Path.Combine(uploadFolder, System.Guid.NewGuid().ToString() + suffix);
string fileName = Path.Combine(uploadFolder, file.FileName + suffix);
//Let the image builder add the correct extension based on the output file type
//fileName = ImageBuilder.Current.Build(file, fileName, new ResizeSettings(versions[suffix]), false, true); //deprecated fileName
fileName = ImageBuilder.Current.Build(new ImageJob(file, fileName, new Instructions(versions[suffix]), false, true)).FinalPath;
}
}
By default the scaling mode is set to DownscaleOnly. Set the Scale on the instructions to either up or both depending on your need.
Just note that upscaling an image tends to create blurry images.
Related
I'm unsure about the right method to define some rules for a specific image in one of my user resource folders.
I allow one image in this folder with a specific name, but this single image can be a PNG / JPEG / BMP.
What could be a suitable route for loading the image as BackgroundImage, when the current code setup for loading the image would be something like this:
private void Form1_DragDrop(object sender, DragEventArgs e)
{
var data = e.Data.GetData(DataFormats.FileDrop);
if (data != null)
{
var fileNames = data as string[];
if (fileNames.Length > 0)
BackgroundImage = Image.FromFile(fileNames[0]);
BackgroundImage = Image.FromFile(#"image_default\image_default.jpg");
}
If I understand the question correctly you will have an array of filenames without extensions and you want to find that file in the directory?
You could get an Array of the files in that directory, then find the matching filename (without extension) and load from that.
var dir = System.IO.Directory.GetFiles(#"image_default\");
var imageFile = string.Empty;
foreach (string file in dir) {
if (System.IO.Path.GetFileName(file).Equals(fileNames[0]))
imageFile = file;
}
if (imageFile != null)
BackgroundImage = Image.FromFile(imageFile);
else
//some error or handle
There might be some more clever way of searching the directory without iterating through the array, but you get the idea...
I'm trying to pass an image as a parameter to an Image in a RDLC Report. I tried using the following:
string imgPath = new Uri("pack://application:,,,/Resources/default_product_img.png").AbsoluteUri;
string imgPath = new Uri(AppDomain.CurrentDomain.BaseDirectory + "pack://application:,,,/Resources/default_product_img.png").AbsoluteUri;
string imgPath = new Uri("/Resources/default_product_img.png").AbsoluteUri;
string imgPath = new Uri(AppDomain.CurrentDomain.BaseDirectory + "/Resources/default_product_img.png").AbsoluteUri;
string imgPath = new Uri("pack://application:,,,/Resources/default_product_img.png", UriKind.Absolute).AbsoluteUri;
string imgPath = new Uri(HttpContext.Current.Server.MapPath("~/Resources/default_product_img.png")).AbsoluteUri;
string imgPath = new Uri(HostingEnvironment.MapPath("~/Resources/default_product_img.png")).AbsoluteUri;
but the display always show the red X when I run it. I managed to make this work, but the source of the image is in the same level as the .exe and not inside it.
I also tried creating a BitmapImage, but ReportParameter() only accepts strings.
Is there a way for this to work? Or should I just copy it beside the .exe file?
Things to Note:
The image source is set as External
default_product_img.png is inside Resources folder and has a Build Action of Resource
The parameter name is set as the value in Use this image:
Take the image as a bitmap and save it to a memory stream then convert the memory stream into a base64 string. Pass this string into the parameter and use that parameter as the image. In the RDLC set the image source to be database and make sure the mime type is a correct match for how you saved the bitmap to the memory stream.
string paramValue;
using (var b = new Bitmap("file path or new properties for bitmap")) {
using (var ms = new MemoryStream()) {
b.save(ms, ImageFormat.Png);
paramValue = ConvertToBase64String(ms.ToArray());
}
}
Or if you want to keep it as an external file set the image source to be external in the rdlc and pass the path to the image as file://c:\site\resources\default_product_img.png it will need to be an absolute path and you can use Server.MapPath to convert the web relative path to an absolute local path then just make sure you have file:// at the beginning of the path so the report engine knows it's a local path.
I am trying to load in a bunch of images from my resource file but I am getting the FileNotFoundException for some reason. the Image names are like so:
"image01.png", "image02.png", ... , "image10.png", image11.png"
In the end I want to be able to display all of the images on the screen.
Here is what I have:
String imgName;
int row = 0, col = 0;
for (int i = 1; i <= 15; i++)
{
//get the name of the current image
if (i < 10)
imgName = "image0" + i + ".png";
else
imgName = "image" + i + ".png";
Image img = null;
try {
img = Image.FromFile(imgName);//read the image from the resource file
}
catch (Exception e) { Console.WriteLine("ERROR!!!" + e); }
}
Here is a sample error output that I am getting:
ERROR!!!System.IO.FileNotFoundException: tile01.png
at System.Drawing.Image.FromFile(String filename, Boolean useEmbeddedColorManagement)
at System.Drawing.Image.FromFile(String filename)
Screenshot:
I have also fixed a type on line 56 from: "PictureForm.PuzzleForm." to "PicturePuzzle." but still no luck.
You are not specifying a path to load the file from. They will be loaded from where the assembly is running.
Note that Image.FromFile does not load an embedded resource, but rather the .png from disk. I assume this is what you intend.
Check the properties for the images in Visual Studio and ensure that Copy to Output Directory is Copy if Newer or Copy Always. Here's a screenshot (in my case it's a cursor resource, but same idea for an image).
UPDATE
If you have embedded your images in your EXE or another file, you can use code similar to
System.Reflection.Assembly thisExe;
thisExe = System.Reflection.Assembly.GetExecutingAssembly();
System.IO.Stream file =
thisExe.GetManifestResourceStream("AssemblyName.ImageFile.jpg");
this.pictureBox1.Image = Image.FromStream(file);
(Source)
NOTE
You can either embed your images in a binary file (commonly your .exe) by setting the property Build Action to Embedded Resource, or leave them as separate files by setting Build Action to Content. If you leave as content, set Copy to Output Directory to True.
There's nothing in your code to say where the files are located so it's defaulting to somewhere the files aren't. If the files sit in the same location as your exe then try something like
imgNmae = "./image0" + i + ".png";
adjusting the relative path to account for where the files actually sit.
Working on a project that does (or will eventually do) the following:
Access all images in a folder (for test phase using a folder in AppData called 'Test Images')
Place them in a new folder, where the image name is used to place it in or create a sub-folder using an algorithm
Save images in a 'List' so that when they have been saved, they can be displayed in a picturebox on the application - where they can be cycled through using prev/next buttons
The first two steps work fine, and I have checked that the images (only using two image files for the test phase) have been placed in subfolders.
I initialised an array of strings using the Directory.GetAllFiles() function in order to do this, meaning this array contains the paths of all the files that are being copied and manipulated. As a part of this process, I added each file path to the List<Bitmap> so they were able to be displayed in the picturebox.
However, whenever I try to run the function to display the image in the picturebox, the whole application crashes. No exception thrown or anything, just the whole thing stops working. I have no idea what is going on.
I've tried this using picbox.Image = to the element on the List<Bitmap> or using picbox.ImageLocation = to it's file path, but neither has been successful.
The code that should make this happen is shown below:
public void saveLatestImages()
{
//specific path for My Pictures only
string testImagesPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Test Images";
//if there is a Pictures folder
if (Directory.Exists(testImagesPath))
{
//get number of files in folder
int fileCount = Directory.GetFiles(testImagesPath).Count();
//more than one file in folder
if (fileCount > 0)
{
//create data structures to store file info
//filePaths holds path of each file represented as a string
string[] filePaths = Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Test Images");
//for each file in Pictures...
for (int index = 0; index < fileCount; ++index)
{
//get name of image at current index
imageName = filePaths[index];
//separate the part relating to the patient name (everything before (DD/MM/YYYY))
string subSpecifier = imageName.Split('\\').Last();
subSpecifier = subSpecifier.Split('_')[0];
//add to root directory to form subfolder name
subDirectory = Path.Combine(rootDirectory, subSpecifier);
//subdirectory name formulated, check for pre-existing
//subfolder does not exist
if(!Directory.Exists(subDirectory))
{
//create it
Directory.CreateDirectory(subDirectory);
}
//otherwise, file will be added to existing directory
//take everything from end and folder\file division to get unique filename
string fileName = imageName.Split('\\').Last();
//add this to the existing subDirectory
fileName = Path.Combine(subDirectory, fileName);
//copy the image into the subfolder using this unique filename
File.Copy(imageName, fileName, true); //true gives instruction to overwrite any existing file with the same path
//add full filename to list of bitmap images
images.Add(new Bitmap(fileName));
//update the shortcut to the file in the image storage shortcut folder
shortcutDirectory = getShortcut(subSpecifier, fileName);
}
}
}
}
public void displayLatestImages()
{
//there are images in list
if (images.Count > 0)
{
//picbox defaults to first image
picboxImage.ImageLocation = Path.GetFileName(images.First().ToString());
}
//check for images before or after current image to enable buttons
checkFirstLast();
}
This shows everything that saves the images to their new file location, and should then allow the first image added to the List to be displayed.
Any advice on how to correct this would be greatly appreciated!
Thanks,
Mark
OK, I am trying to use ImageResizer component in my web app. I have following code:
var versions = new Dictionary<string, string>();
//Define the versions to generate
versions.Add("_001", "maxwidth=300&maxheight=300&format=jpg");
versions.Add("_002", "maxwidth=600&maxheight=600&format=jpg");
versions.Add("_003", "maxwidth=1920&maxheight=1080&format=jpg&process=no"); // I expect it not to resave the image if original is smaller
string uploadFolder = "...my folder path...";
if (!Directory.Exists(uploadFolder))
Directory.CreateDirectory(uploadFolder);
//Generate each version
foreach (string suffix in versions.Keys)
{
//Generate a filename (GUIDs are best).
string fileName = Path.Combine(uploadFolder, DEFAULT_IMAGE_NAME + suffix);
//Let the image builder add the correct extension based on the output file type
fileName = ImageBuilder.Current.Build(file, fileName, new ResizeSettings(versions[suffix]), false, true);
}
file.SaveAs(uploadFolder + DEFAULT_IMAGE_NAME + "_000.jpg");
As you can tell I am saving 3 versions of one image + original image. However, I only want image to be re-encoded and re-saved if resizing is required. So if I upload 1000x1000 image I would expect that main_000.jpg and main_003.jpg are the same. However, that's not the case (ImageResizer resizes that image also, and often saved file size is bigger than main_000.jpg).
I tried adding process=no as parameter but it's not working. Anyone knows if this scenario is supported and which parameter I need to add?
//it may need to be improved
Dictionary<string, SavingSettings> SaveVersions = new Dictionary<string, SavingSettings>();
public void page_load(object sender, EventArgs e) {
//set versions:
SaveVersions.Add("xxl", new SavingSettings("xxl", new ImageResizer.ResizeSettings())); //original size
SaveVersions.Add("600px", new SavingSettings("600px", new ImageResizer.ResizeSettings(600, 600, ImageResizer.FitMode.Max, "jpg"))); //big
SaveVersions.Add("80px", new SavingSettings("80px", new ImageResizer.ResizeSettings(80, 80, ImageResizer.FitMode.Max, "jpg"))); //80 px thumb
SaveVersions.Add("260w", new SavingSettings("260w", new ImageResizer.ResizeSettings(260, 0, ImageResizer.FitMode.Max, "jpg"))); //260 px width thumb
}
public void SaveIt(string SourceFile,string TargetFileName) {
using(System.Drawing.Bitmap bmp = ImageResizer.ImageBuilder.Current.LoadImage(SourceFile, new ImageResizer.ResizeSettings())) {
foreach(System.Collections.Generic.KeyValuePair<string, SavingSettings> k in SaveVersions) {
string TargetFilePath = Server.MapPath("../img/" + k.Value.VersionName + "/" + TargetFileName + ".jpg");
string TargetFolder = Server.MapPath("../img/" + k.Value.VersionName);
if(!System.IO.Directory.Exists(TargetFolder)) System.IO.Directory.CreateDirectory(TargetFolder);
if(bmp.Width > k.Value.ResizeSetting.Width || bmp.Height > k.Value.ResizeSetting.Height) {
//you may need to resize
ImageResizer.ImageBuilder.Current.Build(bmp, TargetFilePath, k.Value.ResizeSetting, false);
} else {
//just copy it
//or in your example you can save uploaded file
System.IO.File.Copy(SourceFile, TargetFilePath);
}
}
}
}
struct SavingSettings {
public string VersionName;
public ImageResizer.ResizeSettings ResizeSetting;
public SavingSettings(string VersionName, ImageResizer.ResizeSettings ResizeSetting) {
this.VersionName = VersionName;
this.ResizeSetting = ResizeSetting;
}
}
You need to use the URL API, not the Managed API, to perform dynamic image resizing.
Just get rid of the pre-resizing code, and save the upload to disk (make sure you sanitize the filename or use a GUID instead, however).
Then, use the URL API like this:
<img src="/uploads/original.jpg?maxwidth=300&maxheight=300&format=jpg" />