When I show a specific image in a PictureBox (or Cyotek's ImageBox in my case, doesn't matter), the color gets a little washed out. Most images displays correctly but some few images gets washed out.
Here's what it looks like:
The original image
Opened in Windows Photo Viewer
Opened in my application
I tried loading the image in 3 different ways, but same result:
Image image = GetImage(OPEN);
imgBox.Image = image;
public Image GetImage(string path)
{
Image image = null;
//image = Image.FromFile(#"D:\Visual Studio\pictures\pokemon.jpg"); // washed out colors
try
{
using (FileStream file_stream = new FileStream(path, FileMode.Open, FileAccess.Read)) // washed out colors
{
MemoryStream memory_stream = new MemoryStream();
file_stream.CopyTo(memory_stream);
image = Image.FromStream(memory_stream, false, false);
file_stream.Dispose();
}
}
catch
{
try
{
FIBITMAP picture = FreeImage.LoadEx(path); // washed out colors
Bitmap bitmap = FreeImage.GetBitmap(picture);
image = bitmap;
FreeImage.Unload(picture);
}
catch { }
}
return image;
}
Anyone know why this is? Maybe some specific tag in this image that Windows and PictureBox handles differently?
You should use Image.FromStream() and pass true for the useEmbeddedColorManagement argument to ensure that any metadata for color management is used.
Related
I am trying to convert png image to gif and jpg format. I am using the code that I've found at Microsoft documentation.
I've created git-hub example by modifying this code into this:
public static void Main(string[] args)
{
// Load the image.
using (Image png = Image.FromFile("test-image.png"))
{
var withBackground = SetWhiteBackground(png);
// Save the image in JPEG format.
withBackground.Save("test-image.jpg");
// Save the image in GIF format.
withBackground.Save("test-image.gif");
withBackground.Dispose();
}
}
private static Image SetWhiteBackground(Image img)
{
Bitmap imgWithBackground = new Bitmap(img.Width, img.Height);
Rectangle rect = new Rectangle(Point.Empty, img.Size);
using (Graphics g = Graphics.FromImage(imgWithBackground))
{
g.Clear(Color.White);
g.DrawImageUnscaledAndClipped(img, rect);
}
return imgWithBackground;
}
Original image (fictional data) is this:
And when I convert it to gif I get this:
So my question:
is there a way to get gif format out of png that would look the same?
Edit:
Hans Passant pointed out that the root problem was transparent background.
After some digging I found answer here.
I used code snipped mentioned in the link to set background to white:
private Image SetWhiteBackground(Image img)
{
Bitmap imgWithBackground = new Bitmap(img.Width, img.Height);
Rectangle rect = new Rectangle(Point.Empty, img.Size);
using (Graphics g = Graphics.FromImage(imgWithBackground))
{
g.Clear(Color.White);
g.DrawImageUnscaledAndClipped(img, rect);
}
return imgWithBackground;
}
So now the gif looks like this:
Something like (https://docs.sixlabors.com/articles/imagesharp/gettingstarted.html):
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
// Open the file and detect the file type and decode it.
// Our image is now in an uncompressed, file format agnostic, structure in-memory as a series of pixels.
using (Image image = Image.Load("test-image.png"))
{
// The library automatically picks an encoder based on the file extensions then encodes and write the data to disk.
image.Save("test.gif");
}
I have a C# WPF application which cuts a image to the size I need it. The WPF window is used to put in a user ID to save the image into a database. When I test my application it works sometimes and sometimes i get a error in gdi+ on the line I save the image to the file system.
Here is my code:
public static void CutImage(Image image)
{
//create new image
Bitmap source = new Bitmap(image);
//cut image
Bitmap cuttedImage = source.Clone(new System.Drawing.Rectangle(250, 0, 5550, 4000), source.PixelFormat);
//copy bitmap to avoid "general error in gdi+"
Bitmap copyImage = new Bitmap(cuttedImage.Width, cuttedImage.Height, PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(copyImage);
g.DrawImageUnscaled(cuttedImage, 0, 0);
//dispose graphics object
g.Dispose();
//dispose image
cuttedImage.Dispose();
//save image to filesystem
copyImage.Save(#"path\tmp.jpg", ImageFormat.Jpeg);
}
//get image
Image i = Image.FromFile(path\image.jpg);
//cut image
CutImage(i);
I searched for a solution and somebody said I have to create a copy of the image I got from Image.FromFile(). But the error still happens sometimes. I tried it a few times and it seems to be random when it happens. The error is always on the Image.Save() line.
Does somebody know how to solve this problem or is there a alternative to Image.Save()?
Thanks for your help!
You're creating so many bitmaps and you're not disposing them. Every single IDisposable must be explicitly disposed when you're finished with them.
Try this and see if the error goes away:
public static void CutImage(Image image)
{
using (Bitmap source = new Bitmap(image))
{
using (Bitmap cuttedImage = source.Clone(new System.Drawing.Rectangle(250, 0, 5550, 4000), source.PixelFormat))
{
using (Bitmap copyImage = new Bitmap(cuttedImage.Width, cuttedImage.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
{
using (Graphics g = Graphics.FromImage(copyImage))
{
g.DrawImageUnscaled(cuttedImage, 0, 0);
copyImage.Save(#"path\tmp.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
}
}
}
I must delete an image file if it already exists (overwriting it) while a PictureBox is showing the same.
However If I try to delete the file it's blocked by PictureBox.
So I write the following code:
if (File.Exists(file))
{
Image _tmp = (Image)current_pic.Image.Clone();
current_pic.Image.Dispose();
current_pic.Dispose();
File.Delete(path);
current_pic.Image = _tmp;
current_pic.Image.Save(file, ImageFormat.Jpeg);
}
else
current_pic.Image.Save(file, ImageFormat.Jpeg);
and the Image on filesystem is deleted thanks to pic.Dispose() but the Image is not
more showed inside the PictureBox.
Maybe does Dispose() method invalidate PictureBox?
You can read a image into the picture box without locking it as shown below
Image img;
string file = #"d:\a.jpg";
using (Bitmap bmp = new Bitmap(file))
{
img = new Bitmap(bmp);
current_pic.Image = img;
}
if (File.Exists(file))
{
File.Delete(file);
current_pic.Image.Save(file, ImageFormat.Jpeg);
}
else
current_pic.Image.Save(file, ImageFormat.Jpeg);
I have updated the code to even support the save operation.
While the previous code supported the delete even after linking the images. The stream was closed and this while saving resulted in a GDI+ error.
The newly updated code meets all your requirements as follows
Allowing a delete of the file while the images is linked
Save of the Image using the Image property in the Picturebox control
I am generating a tile from within my application and when its displayed the background image that its using as the basis fro the the tile has lost its transparency (and therefore its not picking up the theme color.
The background image has an icon on it and is transparent - when I use it as the standard Tile (i.e. not generate an image with it ) thens its fine and the transparency is all good..
But when I use it as the background image and add my own container over it then its not transparent the background is showing as black.
The relevant code is as follows:
// [...]
var container = new Grid();
if (isWide)
{
container = CreateContainerWide(tileInfo);
}
else
{
container = CreateContainerMedium(tileInfo);
}
// Add the background
container.Background = new ImageBrush
{
ImageSource = background,
Opacity = opacity
};
// Force the container to render itself
container.Arrange(new Rect(0, 0, width, height));
// Write the image to disk and return the filename
return WriteShellTileUIElementToDisk(container, baseFileName);
}
static string WriteShellTileUIElementToDisk(UIElement element, string baseFileName)
{
var wb = new WriteableBitmap(element, null);
// All content must be in this sub-folder of IsoStore
string fileName = SharedImagePath + baseFileName + ImageExtension;
var stream = new IsolatedStorageFileStream(fileName, System.IO.FileMode.Create, Isf);
// Write the JPEG using the standard tile size
// Sometimes the bitmap has (0,0) size and this fails for unknown reasons with an argument exception
if (wb.PixelHeight > 0)
wb.SaveJpeg(stream, wb.PixelWidth, wb.PixelHeight, 0, JpegQuality);
else
{
Debug.WriteLine("Can't write out file because bitmap had 0,0 size; not sure why");
// indicate that there is an issue
fileName = null;
}
stream.Close();
// Return the filename
return fileName;
}
Doesn't seem to make any difference as to what I set the Opacity of the ImageBrush to.
If I used a solid color rataher than a transparent layer then its all fine. Somehow the creation of the png is losing the transparency.
Any Ideas?
thanks
This answer might be helpful. Instead of saving a JPG you can save the image as a PNG which does support transparency. The library mentioned in the answer is quite useful.
I have two questions:
1) I have a PictureBox and its Dock is set to Fill. When I resize the Form I cannot create a Graphic on the part of the PictureBox that is extended. What is the problem?
2) I want to convert the Graphic that is created on the PictureBox to Bitmap and save it as
*.JPG or *.bmp. How can I do this?
you can use the handle device to get the bitmap out of the picture box
Graphics g = pictureBox1.CreateGraphics();
Bitmap bitMap = Bitmap.FromHbitmap(g.GetHdc());
bitMap.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);
or even better, if the pictureBox does`nt modify the image, you can directly get the image from the pictureBox control
pictureBox1.Image.Save("path", System.Drawing.Imaging.ImageFormat.Jpeg);
Try this, works fine for me...
private void SaveControlImage(Control ctr)
{
try
{
var imagePath = #"C:\Image.png";
Image bmp = new Bitmap(ctr.Width, ctr.Height);
var gg = Graphics.FromImage(bmp);
var rect = ctr.RectangleToScreen(ctr.ClientRectangle);
gg.CopyFromScreen(rect.Location, Point.Empty, ctr.Size);
bmp.Save(imagePath);
Process.Start(imagePath);
}
catch (Exception)
{
//
}
}
1) Your description is very vague. Do you get an exception? Does it display wrong results? What is happening?
2) You need to get the Image from the PictureBox and use its Save method.
When the Picturebox gets resized to fill the form, it seems it's Image property stays the same.
So what you need to do is handle the PictureBox.OnSizeChanged Event, and then use the following code to resize the image:
private void pictureBox1_SizeChanged(object sender, EventArgs e)
{
if ((pictureBox1.Image != null))
{
pictureBox1.Image = new Bitmap(pictureBox1.Image, pictureBox1.Size);
}
}
To save the image use:
pictureBox1.Image.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg);
Hope that helps!