XNA.Texture2D to System.Drawing.Bitmap I am sure this answered my question but it linked an external site and is no longer available.
I am using a windows form in an xna game. I want to use a background image for one of my panels. It is easy enough to do the loading from file, but when the game is deployed to another system obviously the file location will be different.
Bitmap bmp = new Bitmap(#"c:\myImage.png");
In the above mentioned question, someone had suggested usign Texture2d.saveToPng then open the bitmap from the memory stream. This sounds great, if someone could steer me in that direction. Any other ideas?
This works for me. If there are problems with it please let me know.
public static Image Texture2Image(Texture2D texture)
{
Image img;
using (MemoryStream MS = new MemoryStream())
{
texture.SaveAsPng(MS, texture.Width, texture.Height);
//Go To the beginning of the stream.
MS.Seek(0, SeekOrigin.Begin);
//Create the image based on the stream.
img = Bitmap.FromStream(MS);
}
return img;
}
You can use two methods that allow you to create a Bitmap, use Texture2D.SaveAsJpeg() or Texture2D.SaveAsPng().
MemoryStream memoryStream = new MemoryStream();
Texture2D texture = Content.Load<Texture2D>( "Images\\test" );
texture.SaveAsJpeg( memoryStream, texture.Width, texture.Height ); //Or SaveAsPng( memoryStream, texture.Width, texture.Height )
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap( memoryStream );
Related
I'm in a scenario where I'm manipulating bitmaps using AForge.net in Unity. However, a Bitmap can't be applied to a texture in Unity, so I visibly can see my output, so how is this done?
I believe I have to use the MemoryStream, but in what fashion is unknown to me.
I managed to achieve this by using a memorystream, i.e.:
MemoryStream msFinger = new MemoryStream();
bitmapCurrentframeRed.Save(msFinger, bitmapCurrentframeRed.RawFormat);
redCamera.LoadImage(msFinger.ToArray());
redFilter.GetComponent<Renderer>().material.mainTexture = redCamera;
With bitmapCurrentframeRed being a Bitmap,
redCamera being a texture2D and redFilter being a GameObject(plane) used to view my output.
you can try these line to convert System.Drawing.Bitmap to UnityEngine.Texture2D
Bitmap bmp = new Bitmap;
MemoryStream ms= new MemoryStream();
bmp.Save(ms,ImageFormat.PNG);
var buffer = new byte[ms.Length];
ms.position = 0;
ms.Read(buffer,0,buffer.Length);
Texture2D t = new Texture2D(1,1);
t.LoadImage(buffer);
I've a set of images that I'm programmatically drawing a simple watermark on them using System.Windows and System.Windows.Media.Imaging (yes, not with GDI+) by following a tutorial in here.
Most of the images are not more than 500Kb, but after applying a simple watermark, which is a text with a transparent background, the image size is drastically increasing.
For example, a 440Kb image is becoming 8.33MB after applying the watermark with the below method, and that is shocking me.
private static BitmapFrame ApplyWatermark(BitmapFrame image, string waterMarkText) {
const int x = 5;
var y = image.Height - 20;
var targetVisual = new DrawingVisual();
var targetContext = targetVisual.RenderOpen();
var brush = (SolidColorBrush)(new BrushConverter().ConvertFrom("#FFFFFF"));
brush.Opacity = 0.5;
targetContext.DrawImage(image, new Rect(0, 0, image.Width, image.Height));
targetContext.DrawRectangle(brush, new Pen(), new Rect(0, y, image.Width, 20));
targetContext.DrawText(new FormattedText(waterMarkText, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
new Typeface("Batang"), 13, Brushes.Black), new Point(x, y));
targetContext.Close();
var target = new RenderTargetBitmap((int)image.Width, (int)image.Height, 96, 96, PixelFormats.Default);
target.Render(targetVisual);
var targetFrame = BitmapFrame.Create(target);
return targetFrame;
}
I've noticed that the image quality is improved compared than the original image. The image is more smoother and colors are more lighter. But, you know I don't really want this. I want the image to be as it is, but include the watermark. No quality increases, and of course no drastic changes in image size.
Is there any settings that I'm missing in here to tell my program to keep the quality as same as source image? How can I prevent the significant change of the image size after the changes in my ApplyWatermark method?
Edit
1. This is how I convert BitmapFrame to Stream. Then I use that Stream to save the image to AmazonS3
private Stream EncodeBitmap(BitmapFrame image) {
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(image));
var memoryStream = new MemoryStream();
enc.Save(memoryStream);
return memoryStream;
}
2. This is how I get the BitmapFrame from Stream
private static BitmapFrame ReadBitmapFrame(Stream stream) {
var photoDecoder = BitmapDecoder.Create(
stream,
BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.None);
return photoDecoder.Frames[0];
}
3. This is how I read the file from local directory
public Stream FindFileInLocalImageDir() {
try {
var path = #"D:\Some\Path\Image.png";
return !File.Exists(path) ? null : File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
} catch (Exception) {
return null;
}
}
The problem is that when you edit the image, the compression is gone. A 730x1108 JPG with 433kB disc size with 32bit (you mentioned transparency, so ARGB) will need at least 730 * 1108 * 4 = 3,09MB on disc. Of course you can compress it afterwards again (for disc, network stream of what else).
This is the reason why image software always needs much memory even when working with compressed data.
Conclusion: You will need the free memory to work with the image. Not possible to have it otherwise completly at hand.
The reason I asked my question in the comments earlier, is because I noticed there were several different encoders available. A bitmap usually has a significantly larger file size, due to the amount of information it's storing about your image.
I haven't tested this myself, but have you tried a different encoder?
var pngEncoder = new PngBitmapEncoder();
pngEncoder.Frames.Add(ApplyWatermark(null, null));
MemoryStream stm = File.Create(image);
pngEncoder.Save(stm);
return stm;
Is it possible to get something drawn with default .net paint methods (System.Drawing methods) to a SharpDX Texture2D object so that i can display it as a texture?
Preferably with the SharpDX Toolkit.
If yes, how?
edit: what i am trying so far:
Bitmap b = new Bitmap(100,100);
MemoryStream ms = new MemoryStream();
b.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
Texture2D tex = Texture2D.Load(g.device, ms); // crashing here
ms.Close();
b.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
Texture2D tex = Texture2D.Load(g.device, ms);
The Save() call leaves the memory stream positioned at the end of the stream. Which will confuzzle the Load() method, it can't read any data from the stream. You'll have to rewind the stream explicitly. Insert this statement between the two lines of code:
ms.Position = 0;
I am using .NET4.5, Windows Forms and C#.
I am loading an image onto a button using:
theButton.BackgroundImage = Image.FromFile("file.png");
The issue is that my button is 128x128 and the image is 4000x8000. The line above consumes very large amounts of memory because file.png is so large.
Does anyone know of a technique I can use to reduce this memory footprint? I am thinking of some function like this:
Image.FromFile(file,width,height);
Any pointers? Thanks.
Yes it works. It's quite simple to resize the image and then display it on button.
But, I don't think that the above code maintains the aspect ratio of the image.
It's quite simple to resize the image with aspect ratio; and then display it on button.
Below is the sample code helps you to resize the image by maintaining the aspect ratio.
You can define a new class or implement the "ResizeImage" method in an existing class. Whichever is comfortable to you.
public class ImageManipulation
{
public static Bitmap ResizeImage(Bitmap originalBitmap, int newWidth, int maxHeight, bool onlyResizeIfWider)
{
if (onlyResizeIfWider)
{
if (originalBitmap.Width <= newWidth)
{
newWidth = originalBitmap.Width;
}
}
int newHeight = originalBitmap.Height * newWidth / originalBitmap.Width;
if (newHeight > maxHeight)
{
// Resize with height instead
newWidth = originalBitmap.Width * maxHeight / originalBitmap.Height;
newHeight = maxHeight;
}
var alteredImage = new Bitmap(originalBitmap, new Size(newWidth, newHeight));
alteredImage.SetResolution(72, 72);
return alteredImage;
}
}
USAGE:
private void DisplayPhoto()
{
// make sure the file is JPEG or GIF
System.IO.FileInfo testFile = new System.IO.FileInfo(myFile);
// Create a new stream to load this photo into
FileStream myFileStream = new FileStream(myFile, FileMode.Open, FileAccess.Read);
// Create a buffer to hold the stream of bytes
photo = new byte[myFileStream.Length];
// Read the bytes from this stream and put it into the image buffer
myStream.Read(photo, 0, (int)myFileStream.Length);
// Close the stream
myFileStream.Close();
// Create a new MemoryStream and write all the information from
// the byte array into the stream
MemoryStream myStream = new MemoryStream(photo, true);
myStream.Write(photo, 0, photo.Length);
// Use the MemoryStream to create the new BitMap object
Bitmap FinalImage = new Bitmap(myStream);
upicPhoto.Image = ImageManipulation.ResizeImage(
FinalImage,
upicPhoto.Width,
upicPhoto.Height,
true);
// Close the stream
myStream.Close();
}
I think your best path here is to just resize the image, to 128x128.
An image that large is always going to take up a lot of memory, no matter what you do with it.
This will also allow you to make the image something that will look good at that size.
This is quite a general problem, AFAIK you have few possibilities
Compress image before uploading , in real world this will not work.
Put a check on size and dimensions of image, in real world it works, even linkedin, facebook they won't allow us to upload images above there specified dimensions.
Use buffering, this is cleanest way you can do in .net
Use some third party plugins or development enviornment, I have done it in Silverlight
I need to convert PNG file to BMP file on runtime.
I can't do it like
Image dummy = Image.FromFile("image.png");
dummy.Save("image.bmp", ImageFormat.Bmp);
because i can't save the bmp image on the local disk as a file.
Thanks for any help.
You can save to stream
using(MemoryStream stream = new MemoryStream())
{
Dummy.Save(stream, ImageFormat.Bmp);
}
Precise answer given here.
Image Dummy = Image.FromFile("image.png");
Dummy.Save("image.bmp", ImageFormat.Bmp);
Since you don't want to follow this method, you can do it the way Stecya answered.
Just do it this way.
Stream stream;
Dummy.save(stream, ImageFormat.Bmp)