How to make the Bitmap Constructor take a string - c#

I know this question has been asked before, but i couldnt find an answer for my specific situation. Im trying to create new bitmap from a resource image.
private void button1_Click(object sender, EventArgs e)
{
string test = "meridian_am";
string resources = "Resources.Properties.Resources." + test;
var master = new Bitmap(Resources.Properties.Resources.master);
var meridian_am = new Bitmap(resources);
using (Graphics g = Graphics.FromImage(master))
{
g.DrawImageUnscaled(meridian_am, 114, 332);
}
}
for some reason, for the *var meridian_am = new Bitmap(resources)* im getting an invalid parameter error.. Ultimately, i would rather do a string concatenation on the fly, as in var meridian_am = new Bitmap(Resources.Properties.Resources. + test), but for some reason that wont work... Any ideas?

I'm no expert in C#, but... for var master = ... you're passing a resource that might well be an Image or something like that, while for var meridian = ... you're passing a string as the parameter, which should be the path to an accessible file.
Hope that helps.
EDIT:
I'm talking this constructor versus this one.

Does Resources.Properties.Resources.master contain image bytes or string (path to file name)? In any case you can't pass raw string "Resources.Properties.Resources.meridian_am" to Bitmap constructor. It treats it as path to file, not your resource.
You should load data from resources by this name before. Something like that (if your resource contain image bytes):
var assembly = System.Reflection.Assembly.GetEntryAssembly();
var resources = assembly.GetManifestResourceStream("Resources.Properties.Resources." + test);

Related

C# - How can I have a dynamic Image / BitmapSource accessible from XAML?

In my C# project I have a list of images which are resources compiled in the exe:
/Pics/Image1.png
/Pics/Image2.png
/Pics/Image3.png
...
In my code I process the images to match them to the theme of the application. The issue I am having is that I am trying to figure out an easy way to access these processed images in the XAML syntax.
This is how I typically access a resource image (pre-processed):
<Image Source="/Pics/Image1.png" />
So I would really like to access these processed images a similar way.
I tried a static dictionary like this:
<Image Source="{x:Static local:Theme.Images.ImageDictionary[/Pics/Image1.png]}" />
But this threw an error because it doesn't like the ".png", I haven't been able to get this working with dictionary keys. Not to mention this looks really ugly.
Ideally I would love to be able to "replace" the resource references, or create a resource at runtime (e.g. PicsProcessed/Image1.png) but haven't been able to figure a way to add or modify resources in a running C# application programmatically.
Any suggestions are really appreciated - thank you!
Have you tried creating a Bitmap then setting it as the image source? I think this should be easy. Give your image a name, say theImage. You can't possibly reference the image without giving it a name.
Try the following:
string path="/Pics/Image3.png";//path to the image
var bitmapImage=new Bitmap(new Uri(path));
theImage.source=bitmapImage;//set the bitmap as the source.
There are other ways you can achieve this though. Hope this helps?
It took a couple of days but I figured out a solution!
I moved all my images into another C# Project in the same solution, set to compile as a Class Libary DLL file called DynamicResources.dll (assembly name in the Project settings is "DynamicResources"). This project is added as a reference to the main project. As such I can access images in the XAML - clean and tidy:
<Image Source="/DynamicResources;component/pics/image1.png" />
Then in the post-build event for the main project, I rename the compiled .dll so it doesn't get loaded by the main .exe binary at launch:
copy "$(TargetDir)DynamicResources.dll" "$(TargetDir)DynamicResources.temp"
del "$(TargetDir)DynamicResources.dll"
Then I used a third-party library called Mono.Cecil to load the DynamicResources.temp file (DLL format), replace the resources, write it back to memory, then tell the application to load it:
public static void UpdateAssembly()
{
string dllFile = "DynamicResources.temp";
string dllNamespace = "DynamicResources";
var asm = AssemblyDefinition.ReadAssembly(dllFile);
var module = asm.Modules.FirstOrDefault();
var resources = module.Resources;
var dllResource = (EmbeddedResource)(resources.FirstOrDefault());
var dllResourceReader = new ResourceReader(dllResource.GetResourceStream());
var newResourceOutputStream = new MemoryStream();
var newResourceWriter = new ResourceWriter(newResourceOutputStream);
foreach (DictionaryEntry dllResourceEntry in dllResourceReader)
{
var image = (BitmapSource)new ImageSourceConverter().ConvertFrom(dllResourceEntry.Value);
Color foreground = (Color)ColorConverter.ConvertFromString("#FFFFFF");
var processed = (WriteableBitmap)ColorizeImage(image, foreground); // Your image processing function ?
newResourceWriter.AddResource(dllResourceEntry.Key.ToString(), BitmapToByte(processed));
}
newResourceWriter.Close();
var newResource = new EmbeddedResource(dllResource.Name, dllResource.Attributes, newResourceOutputStream.ToArray());
module.Resources.Remove(dllResource);
module.Resources.Add(newResource);
var woutput = new MemoryStream();
asm.Write(woutput);
var doutput = woutput.ToArray();
Assembly assembly = Assembly.Load(doutput);
}
public static MemoryStream BitmapToByte(BitmapSource bitmapSource)
{
var encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
var frame = System.Windows.Media.Imaging.BitmapFrame.Create(bitmapSource);
encoder.Frames.Add(frame);
var stream = new MemoryStream();
encoder.Save(stream);
return stream;
}
public static void AttachAssembly(string myAsmFileName)
{
Assembly assembly = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + myAsmFileName); // LoadFrom
AppDomain.CurrentDomain.Load(assembly.GetName());
}
Important note: When iterating through resources, they become lowercase, so you must use lowercase file and folder names.

load an image from resources in Visual C#, using a string?

If I have some resources, eg card1.png, card2.png, etc,
I want to them load them into a picBox, but only load the correct image
eg, something like
int cardNum = rn.Next(0,cardMax);
picCard.Image = Properties.Resources."card"+cardNum+".png";
Obviously that doesn't work, but how would I do what I am trying to do (load the correct resource after building the resource name into a string)
Instead of the generated properties in the Resources class use the ResourceManager directly:
string resName = $"card{cardNum}.png"; // Check the correct name in the .resx file. By using the wizards the extension is omitted, for example.
picCard.Image = (Image)Properties.Resources.ResourceManager.GetObject(resName);
Try using:
var rm = new System.Resources.ResourceManager(((System.Reflection.Assembly)System.Reflection.Assembly.GetExecutingAssembly()).GetName().Name + ".Properties.Resources", ((System.Reflection.Assembly)System.Reflection.Assembly.GetExecutingAssembly()));
Image img = (Bitmap)rm.GetObject("resourcesimagename.jpg");

ImageResizer - not resaving image if it's smaller than requested size

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" />

Randomly mapping an image in C# ASP.NET

Quite a bit of looking at this one.
I have an aspx web page with an Image control on it, and I want to load images from my web directory at random to diplay in the image control. The below is the code and how far I have got.
Seems a simple task to request an image file at random and display this in a web page, all I am receiving however is a local filepath (which appears to be no use to the Image Control) and no image on the webpage.
AppSettings.imageUrl returns: "~/Images"
Any suggestions would be appreciated.
protected void Page_Load(object sender, EventArgs e)
{
GetImage();
}
private void GetImage()
{
imgMain.ImageUrl = ResolveClientUrl(RandomImage());
}
private string RandomImage()
{
string mapPath = Request.MapPath(AppSettings.imageUrl);
var rand = new Random();
var files = Directory.GetFiles(mapPath);
return files[rand.Next(files.Length)];
Your RandomImage() method possibly doesn't return file path relative to current page. Either return
string fileName = Path.GetFileName(file[rand.Next(files.Length)]);
return AppSettings.imageUrl + fileName;
and then resolve it or resolve it right away
string fileName = Path.GetFileName(file[rand.Next(files.Length)]);
return Request.MapPath(AppSettings.imageUrl + fileName);
Do a View Source on the resulting page and see if the <img src="..."> is getting set to a sensible value.
On further investigation it seems that ResolveClientUrl takes a relative URL, not an absolute file system path. Therefore RandomImage should return something like:
return AppSettings.imageUrl + "/" + Path.GetFileName(files[rand.Next(files.Length)]);
You're getting the file names. The Directory.GetFiles could also be used in non-web application and therefore it would make no sense to treat the files as relative to your website root.
What you can do is get the local path for root of your site like this:
string root = Request.MapPath("~/");
and then remove that substring from the file you selected:
files[rand.Next(files.Length)].Replace(root, string.Empty);
That's all you need.

Creating Images from an Embedded Resource

This has been driving me crazy for the past 2 days, and anything close that I find just does not seem to work in my situation, perhaps someone can point out what I'm doing wrong.
I have a WPF project to which I've include a fairly large number of images(80ish). I've added them to the project into a folder called "Images". They are currently set to be embedded resources(though I've tried regular resources as well) but nothing seems to work.
I am attempting to create and load an ArrayList of type Image using these files as the source, but I'm failing pretty bad.
private void addPicture(string name)
{
string filePath = "pack://MyApp_WPF:,,,/Images/" + name + ".png";
Stream imageStream = assembly.GetManifestResourceStream(filePath);
Image curImage = new Image();
BitmapImage bmpImage = new BitmapImage();
bmpImage.BeginInit();
bmpImage.UriSource = new Uri(filePath, UriKind.Relative);
bmpImage.EndInit();
curImage.Height = 60;
curImage.Stretch = Stretch.Uniform;
curImage.Source = bmpImage;
curImage.Margin = new Thickness(5);
imageList.Add(curImage);
}
It was much easier to do in my windows form application, but I just cant figure it out with WPF... Any help besides links to resources would be nice, because chances are at this point I've already read them.
First thing to note is that there is an DownloadError event that you ought to subscribe to, this might explain what is happening and why (though sometimes the error message is rather generic); the next is that you might not need the pack:// URI construct with images build actions of Resource:
var bmpImage = new BitmapImage(new Uri(
string.Format("/Images/{0}.png", name", UriKind.Relative));
The Pack URI is wrong, where you name your assembly you should place an authority, in this case application, i.e.
string filePath = "pack://application:,,,/Images/" + name + ".png";

Categories

Resources