How to convert a System.Drawing.Bitmap to a UnityEngine.Texture? - c#

Texture2D tex = new Texture2D(200, 300, TextureFormat.RGB24, false);
Rectangle screenSize = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
Bitmap target = new Bitmap(screenSize.Width, screenSize.Height);
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(target))
{
g.CopyFromScreen(0, 0, 0, 0, new Size(screenSize.Width, screenSize.Height));
}
m_Renderer.enabled = true;
m_Renderer.material.SetTexture("_MainTex", target);
I'm trying to set a bitmap as a texture in Unity, but I get the error
cannot convert from 'System.Drawing.Bitmap' to 'UnityEngine.Texture'
Any ideas how I can convert the bitmap to a texture?

You could try converting Bitmap to byte[] (as shown here). After that you can call Texture2D.LoadRawTextureData(byte[]) or Texture2D.LoadImage(byte[]).

Related

Screenshot conversion into grayscale doesn't work. What causes this?

I have a Windows Forms application that takes a screenshot of a specific portion of the screen, then displays it in a picture box (pictureBox1). It works when I don't try to convert it, but I want to convert the image to grayscale or black and white. The problem is when I convert it to grayscale, it still shows the original picture in the picture box.
Here is the code when it works, without the conversion:
private void button1_Click(object sender, EventArgs e)
{
Rectangle rectangle = new Rectangle(660, 200, 600, 100);
pictureBox1.Height = rectangle.Height;
pictureBox1.Width = rectangle.Width;
imageUploader(rectangle);
}
public void imageUploader(Rectangle rectangle)
{
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(rectangle.Left, rectangle.Top, 0, 0, bitmap.Size, CopyPixelOperation.SourceCopy);
bitmap.Save("proba.jpeg", ImageFormat.Jpeg);
pictureBox1.Image = bitmap;
}
Here is the conversion method, which I tried out:
public void toGrayscale(Bitmap bitmap)
{
Color c;
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
c = bitmap.GetPixel(x,y);
Color newColor = Color.FromArgb(c.R,0,0);
bitmap.SetPixel(x,y,newColor);
}
}
}
After I used this conversion (see below) the image showed up in the picture box, but it wasn't grayscale.
Here is the modified imageUploader void with the conversion:
public void imageUploader(Rectangle rectangle)
{
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppArgb);
toGrayscale(bitmap);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(rectangle.Left, rectangle.Top, 0, 0, bitmap.Size, CopyPixelOperation.SourceCopy);
bitmap.Save("proba.jpeg", ImageFormat.Jpeg);
pictureBox1.Image = bitmap;
}
It appears that your issue is here:
public void imageUploader(Rectangle rectangle)
{
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppArgb);
toGrayscale(bitmap);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(rectangle.Left, rectangle.Top, 0, 0, bitmap.Size, CopyPixelOperation.SourceCopy);
bitmap.Save("proba.jpeg", ImageFormat.Jpeg);
pictureBox1.Image = bitmap;
}
You're converting each pixel of the bitmap to greyscale (oddly it looks like you're only grabbing the red channel) then copying from the screen, which overwrites your conversion. To fix it, all you should need to do is move the toGreyscale after you copy from the screen, like this:
public void imageUploader(Rectangle rectangle)
{
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(rectangle.Left, rectangle.Top, 0, 0, bitmap.Size, CopyPixelOperation.SourceCopy);
toGrayscale(bitmap); # Moved after the copy from screen
bitmap.Save("proba.jpeg", ImageFormat.Jpeg);
pictureBox1.Image = bitmap;
}
This should fix the issue.
You are converting an empty Bitmap to greyscale, then copying over the (nominally) greyscaled Bitmap with an image from the screen. Here is your code, annotated to describe what it is doing:
// This line creates an empty Bitmap.
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppArgb);
// This line converts the empty Bitmap to grayscale.
toGrayscale(bitmap);
// This line creates a Graphics drawing surface from your bitmap.
Graphics graphics = Graphics.FromImage(bitmap);
// This line overwrites the image data from your bitmap with an image from the screen.
graphics.CopyFromScreen(rectangle.Left, rectangle.Top, 0, 0, bitmap.Size, CopyPixelOperation.SourceCopy);
You need to find some way to take the data you got from the screen and make it greyscale. You have not done this. You have made a greyscale image, but then you have thrown it away by writing other data on top of it. It happens that that replacement data is not greyscale.

How to Tile a Shape with Image and Texture Mask?

How i can apply a FillRectangle with texture Brush to source image via using Texture Mask?
Something like that... but how to use a texture mask?
Bitmap textile = new Bitmap("textile.png");
TextureBrush textileBrush = new TextureBrush(textile);
Bitmap outfit = new Bitmap("outfit.png");
Bitmap masksource = new Bitmap("mask.png");
Color bodyColorKey = Color.FromArgb(0, 255, 0);
//what i should to do next and how to apply FillRectangle?
using (Graphics g = Graphics.FromImage(outfit))
{
g.FillRectangle(textileBrush, new Rectangle(0, 0, ???, ???));
}
Outfit:
And his mask:
Textile texture:
And how it should looks after, on output:
Any ideas how it should looks for System.Drawing?
using the mask image, make transparent for the given colours and combine the images as follows.
Bitmap textile = new Bitmap("textile.png");
TextureBrush textileBrush = new TextureBrush(textile);
Bitmap outfit = new Bitmap("outfit.png");
Bitmap masksource = new Bitmap("mask.png");
Bitmap transparentImage = new Bitmap(outfit.Width, outfit.Height);
masksource.MakeTransparent(Color.FromArgb(255, 0, 255, 0));
using (Graphics g = Graphics.FromImage(transparentImage))
{
g.DrawImage(outfit, new Point(0, 0));
//g.DrawImage(textile, new Point(0, 0)); // use texture image
g.FillRectangle(textileBrush, g.ClipBounds); // use texture image as Tile mode
g.DrawImage(masksource, new Point(0, 0));
transparentImage.MakeTransparent(Color.FromArgb(255, 255, 0, 0));
transparentImage.MakeTransparent(Color.FromArgb(255, 0, 0, 255));
}
Bitmap outputImage = new Bitmap(outfit.Width, outfit.Height);
using (Graphics g = Graphics.FromImage(outputImage))
{
g.DrawImage(outfit, new Point(0, 0));
g.DrawImage(transparentImage, new Point(0, 0));
}
Only you need to fill the rectangle with texture image
//what i should to do next and how to apply FillRectangle?
using (Graphics g = Graphics.FromImage(outfit))
{
g.FillRectangle(textileBrush,g.ClipBounds);
}

Merging 2 images using C#

I want to merge two pictures in my C# program.
the first one is any picture in grayscale mode, and the second one is like in this picture:
Both of the pictures/images have the same size, and this is my code:
Bitmap first = new Bitmap (picturebox1.image);
Bitmap second = new Bitmap (picturebox2.image);
Bitmap result = new Bitmap (first.width, first.height);
Graphics g = Graphics.FromImage(result);
g.DrawImageUnscaled(first, 0, 0);
g.Flush();
g.DrawImageUnscaled(second, 0, 0);
g.Flush();
picturebox3.image = result;
I can join those picture, but the result has smaller size than the two originals (both pictures have same size). Could anyone give me some suggestions?
Additionally, I want the result picture has condition like this :
if the edge pixel in 2nd picture dropped to the bright side at the 1st one, it will be dark, otherwise when the edge dropped to the dark side, it will be bright (seem glow).
so the text will be semi transparent.
Here's an example of the results I want.
Could anyone give some suggestions please?
It was for joining
Bitmap first = new Bitmap (picturebox1.Image);
Bitmap second = new Bitmap (picturebox2.Image);
Bitmap result = new Bitmap (first.Width+first.Width, first.Height);
Graphics g = Graphics.FromImage(result);
g.DrawImageUnscaled(first, 0, 0);
g.DrawImageUnscaled(second,first.Width, 0);
Try this for merging one on top another . set alpha by yourself ( red: U can use BitMap.MakeTransParent if u not want alpha)
public Bitmap SetImageOpacity(Image image, float opacity)
{
try
{
//create a Bitmap the size of the image provided
Bitmap bmp = new Bitmap(image.Width, image.Height);
//create a graphics object from the image
using (Graphics gfx = Graphics.FromImage(bmp))
{
//create a color matrix object
ColorMatrix matrix = new ColorMatrix();
//set the opacity
matrix.Matrix33 = opacity;
//create image attributes
ImageAttributes attributes = new ImageAttributes();
//set the color(opacity) of the image
attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
//now draw the image
gfx.DrawImage(image, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes);
}
return bmp;
}
catch (Exception ex)
{
return null;
}
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap first = new Bitmap(pictureBox1.Image);
Bitmap second = SetImageOpacity(pictureBox2.Image, 0.5f);
//Bitmap result = new Bitmap(first.Width, first.Height);
//fix :
Bitmap result = new Bitmap(Math.Max(first.Width,second.Width), Math.Max(first.Height,second.Height));
Console.WriteLine(first.Width);
Graphics g = Graphics.FromImage(result);
g.DrawImageUnscaled(first, 0, 0);
g.DrawImageUnscaled(second, 0, 0);
pictureBox3.Image = result;
result.Save("result.jpg" );
}
}
}
And Coming For watermark why not you want to use Drawstring with alpha
here is article for all these http://www.codeproject.com/Articles/5034/How-to-implement-Alpha-blending
You need to include the System.Drawing.Imaging namespace to make this code work.
Go through following code:
private void CombineImages(FileInfo[] files)
{
//change the location to store the final image.
string finalImage = #"C:\\MyImages\\FinalImage.jpg";
List imageHeights = new List();
int nIndex = 0;
int width = 0;
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
imageHeights.Add(img.Height);
width += img.Width;
img.Dispose();
}
imageHeights.Sort();
int height = imageHeights[imageHeights.Count - 1];
Bitmap img3 = new Bitmap(width, height);
Graphics g = Graphics.FromImage(img3);
g.Clear(SystemColors.AppWorkspace);
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
if (nIndex == 0)
{
g.DrawImage(img, new Point(0, 0));
nIndex++;
width = img.Width;
}
else
{
g.DrawImage(img, new Point(width, 0));
width += img.Width;
}
img.Dispose();
}
g.Dispose();
img3.Save(finalImage, System.Drawing.Imaging.ImageFormat.Jpeg);
img3.Dispose();
imageLocation.Image = Image.FromFile(finalImage);
}
Follow Link:
http://www.niteshluharuka.com/2012/08/combine-several-images-to-form-a-single-image-using-c/
This codeproject article shows how to watermark an image with text as well as another image.
In summary, what you have to do is draw your watermark image over the image with the desired transparency.

The image is shifted when convert 8bpp to 24bpp

When i used following code to convert a bitmap from 8bpp to 24bpp, the resulted image is shifted but i can't figure out the reason of that, can anyone help?
private static Bitmap ConvertTo24(Bitmap bmpIn)
{
bmpIn.Save(#"F:\sara1.bmp");
Bitmap converted = new Bitmap(bmpIn.Width, bmpIn.Height, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(converted))
{
// Prevent DPI conversion
g.PageUnit = GraphicsUnit.Pixel;
// Draw the image
g.DrawImageUnscaled(bmpIn, 0, 0);
// g.DrawImage(bmpIn, 0, 0);
}
converted.Save(#"F:\sara2.bmp");
}
The following code worked for me:
private static Bitmap ConvertTo24(Bitmap bmpIn)
{
bmpIn.Save(#"F:\sara1.bmp");
Bitmap converted = new Bitmap(bmpIn.Width, bmpIn.Height, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(converted))
{
// Prevent DPI conversion
g.PageUnit = GraphicsUnit.Pixel;
// Draw the image
// g.DrawImageUnscaled(bmpIn, 0, 0);
g.DrawImage(bmpIn, 0, 0, converted.Width, converted.Height);
}
converted.Save(#"F:\sara2.bmp");
}
Providing the width and height rescales the image.
You could have problem in bmpIn before receiving it in your function.
You can test following (better) code after putting your 8bpp image in f:\sara1.bmp (just to ensure that you have 8bpp image not shifted before conversion).
private static Bitmap ConvertTo24(Bitmap bmpIn)
{
//Bitmap bmpIn;
bmpIn = new Bitmap(#"f:\sara1.bmp");
Bitmap converted = new Bitmap(bmpIn.Width, bmpIn.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(converted))
{
g.PageUnit = GraphicsUnit.Pixel;
Rectangle rng = new Rectangle(new Point(0, 0), bmpIn.Size);
g.DrawImage(bmpIn, rng); // use this instead of following
}
converted.Save(#"F:\sara2.bmp");
}
Hope it works fine 4 u. I used DrawImage(Image img, Rectangle rng) as you are already told in comments
Answer is complete. Following is explanation. Your code (edited. Use it as it is and follow the comment)
private static Bitmap ConvertTo24(Bitmap bmpIn)
{
bmpIn.Save(#"F:\sara1.bmp");
return;
// After you have called this function. Go open your image f:\sara1.bmp from
//hrad disk-- I doubt you would find it shifted here even before conversion
Bitmap converted = new Bitmap(bmpIn.Width, bmpIn.Height, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(converted))
{
// Prevent DPI conversion
g.PageUnit = GraphicsUnit.Pixel;
// Draw the image
g.DrawImageUnscaled(bmpIn, 0, 0);
// g.DrawImage(bmpIn, 0, 0);
}
converted.Save(#"F:\sara2.bmp");
}
Again Your code ( I just ignored your received 8bpp Bitmap and fetched it directly from f drive, supposing that you would put it before running the application or at least before calling this function)
Following code also worked fine for me.
private static Bitmap ConvertTo24(Bitmap bmpIn)
{
Bitmap bmpIn = new Bitmap(#"f:\sara1.bmp");
Bitmap converted = new Bitmap(bmpIn.Width, bmpIn.Height, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(converted))
{
// Prevent DPI conversion
g.PageUnit = GraphicsUnit.Pixel;
// Draw the image
g.DrawImageUnscaled(bmpIn, 0, 0);
// g.DrawImage(bmpIn, 0, 0);
}
converted.Save(#"F:\sara2.bmp");
}

Convert RenderTargetBitmap into System.Drawing.Image

I have 3D WPF visual that I want to pass into an Excel cell (via clipboard buffer).
With "normal" BMP images it works but I do not know how to convert a RenderTargetBitmap.
My code looks like this:
System.Windows.Media.Imaging.RenderTargetBitmap renderTarget = myParent.GetViewPortAsImage(DiagramSizeX, DiagramSizeY);
System.Windows.Controls.Image myImage = new System.Windows.Controls.Image();
myImage.Source = renderTarget;
System.Drawing.Bitmap pg = new System.Drawing.Bitmap(DiagramSizeX, DiagramSizeY);
System.Drawing.Graphics gr = System.Drawing.Graphics.FromImage(pg);
gr.DrawImage(myImage, 0, 0);
System.Windows.Forms.Clipboard.SetDataObject(pg, true);
sheet.Paste(range);
My problem is that gr.DrawImage does not accept a System.Windows.Controls.Image or a System.Windows.Media.Imaging.RenderTargetBitmap; only a System.Drawing.Image.
How do I convert the Controls.Image.Imaging.RenderTargetBitmap into an Image, or are there any easier ways?
You can copy the pixels from the RenderTargetBitmap directly into the pixel buffer of a new Bitmap. Note that I've assumed that your RenderTargetBitmap uses PixelFormats.Pbrga32, as use of any other pixel format will throw an exception from the constructor of RenderTargetBitmap.
var bitmap = new Bitmap(renderTarget.PixelWidth, renderTarget.PixelHeight,
PixelFormat.Format32bppPArgb);
var bitmapData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size),
ImageLockMode.WriteOnly, bitmap.PixelFormat);
renderTarget.CopyPixels(Int32Rect.Empty, bitmapData.Scan0,
bitmapData.Stride*bitmapData.Height, bitmapData.Stride);
bitmap.UnlockBits(bitmapData);
This was the solution I came up with
System.Windows.Media.Imaging.RenderTargetBitmap renderTarget = myParent.GetViewPortAsImage(DiagramSizeX, DiagramSizeY);
System.Windows.Media.Imaging.BitmapEncoder encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
MemoryStream myStream = new MemoryStream();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(renderTarget));
encoder.Save(myStream);
//
System.Drawing.Bitmap pg = new System.Drawing.Bitmap(DiagramSizeX, DiagramSizeY);
System.Drawing.Graphics gr = System.Drawing.Graphics.FromImage(pg);
//
// Background
//
gr.FillRectangle(new System.Drawing.SolidBrush(BKGC), 0, 0, DiagramSizeX, DiagramSizeY);
//
gr.DrawImage(System.Drawing.Bitmap.FromStream(myStream), 0, 0);
System.Windows.Forms.Clipboard.SetDataObject(pg, true);
sheet.Paste(range);
Maybe I don't understand the question right, but you want to copy a RenderTargetBitmap to the clipboard, couldn't you just call SetImage ?:
Dim iRT As RenderTargetBitmap = makeImage() //this is what you do to get the rendertargetbitmap
If iRT Is Nothing Then Exit Sub
Clipboard.SetImage(iRT)

Categories