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.
Related
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.
anyone could tell me why this generate a black only animated gif?
the code also output each in memory generated gif to show that they are different
public static void Test()
{
Image<Rgba32> img = null;
Image<Rgba32> gif = null;
TextGraphicsOptions textGraphicsOptions = new TextGraphicsOptions(true);
SolidBrush<Rgba32> brushYellow = new SolidBrush<Rgba32>(Rgba32.Yellow);
FontCollection fonts = new FontCollection();
fonts.Install(fontLocation);
Font font = fonts.CreateFont("Liberation Mono", PngFontHeight, FontStyle.Regular);
gif = new Image<Rgba32>(400, 400);
for (int i = 0; i < 10;++i)
{
img = new Image<Rgba32>(400, 400);
img.Mutate(x => x.Fill(Rgba32.Black));
img.Mutate(x => x.DrawText(textGraphicsOptions, i.ToString(), font, brushYellow, new PointF(1,1)));
gif.Frames.AddFrame(img.Frames[0]);
using (FileStream fs = File.Create(Path.Join(Program.workingDirectory, string.Format("Test-{0}.gif", i))))
{
img.SaveAsGif(fs);
}
img.Dispose();
}
using (FileStream fs = File.Create(Path.Join(Program.workingDirectory, "Test.gif")))
{
gif.SaveAsGif(fs);
}
}
if I code it to load each individual physical file using this code it make the animated gif as expected.
I want to create the animated gif in memory only.
When you create an Image<>...
gif = new Image<Rgba32>(400, 400);
...gif.Frames[0] is a "transparent black" frame (each pixel's RGBA value is #00000000). The additional frames you create in your for loop and add with...
gif.Frames.AddFrame(img.Frames[0]);
...become gif.Frames[1] through gif.Frames[10], for a total of 11 frames.
The GIF encoder uses GifColorTableMode to decide if a color table is generated for each frame or the color table for the first frame is used for all frames. The combination of the default value, GifColorTableMode.Global, plus that first transparent frame results in an 11-frame .gif file with only one color, that same "transparent black". This is why your yellow text doesn't appear and every frame looks the same.
To solve this, at some point before you save the file you need to remove that initial transparent frame so it doesn't influence color table calculations and because it's not part of your animation, anyways...
gif.Frames.RemoveFrame(0);
You may also want to change to GifColorTableMode.Local so your .gif file contains color tables reflecting all of the colors rendered...
gif.MetaData.GetFormatMetaData(GifFormat.Instance).ColorTableMode = GifColorTableMode.Local;
...although your 10 frames each use almost the same set of colors so if file size is a greater concern than color representation you might leave that property alone. Generating your 400 × 400 animation with GifColorTableMode.Global produces a 9,835-byte file whereas GifColorTableMode.Local produces a 16,703-byte file; 70% bigger but I can't tell the difference between them.
Related issue on GitHub
By the way, since I found this along the way, if you wanted to change the duration of the animated frames you would do so using another GetFormatMetaData() method similar to the one shown above...
GifFrameMetaData frameMetaData = img.MetaData.GetFormatMetaData(GifFormat.Instance);
frameMetaData.FrameDelay = 100;// 1 second
Does anybody know of any ways to use an image as a mask for another image in UWP, the only masking function I can see is CompositionMaskBrush which I don't believe can achieve what I want.
An example of what I'm looking to achieve is the following.
I have a solid black PNG in the shape of a mobile phone case, the user adds their own image which is then clipped and masked to the dimensions of the solid black PNG - Resulting in the image below.
Any help whatsoever would be greatly appreciated. I've spent quite a while browsing for a solution.
Example Image Here
Just posting for anybody else who needs and answer to this, but I finally managed to find a solution using Win2D and an Imageloader.
Here is a link to the ImageLoader. Note that I had to roll back a few versions in order make it work how the documentation states. The link below is to the version that I'm using. Anything later than this version will not work with the sample code I'm going to post.
https://www.nuget.org/packages/Robmikh.Util.CompositionImageLoader/0.4.0-alpha
private Compositor _compositor;
private IImageLoader _imageLoader;
private CompositionEffectFactory _effectFactory;
private async void InitMask()
{
// Store our Compositor and create our ImageLoader.
_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
_imageLoader = ImageLoaderFactory.CreateImageLoader(_compositor);
// Setup our effect definition. First is the CompositeEffect that will take
// our sources and produce the intersection of the images (because we selected
// the DestinationIn mode for the effect). Next we take our CompositeEffect
// and make it the source of our next effect, the InvertEffect. This will take
// the intersection image and invert the colors. Finally we take that combined
// effect and put it through a HueRotationEffect, were we can adjust the colors
// using the Angle property (which we will animate below).
IGraphicsEffect graphicsEffect = new HueRotationEffect
{
Name = "hueEffect",
Angle = 0.0f,
Source = new InvertEffect
{
Source = new CompositeEffect
{
Mode = CanvasComposite.DestinationIn,
Sources =
{
new CompositionEffectSourceParameter("image"),
new CompositionEffectSourceParameter("mask")
}
}
}
};
// Create our effect factory using the effect definition and mark the Angle
// property as adjustable/animatable.
_effectFactory = _compositor.CreateEffectFactory(graphicsEffect, new string[] { "hueEffect.Angle" });
// Create MangedSurfaces for both our base image and the mask we'll be using.
// The mask is a transparent image with a white circle in the middle. This is
// important since the CompositeEffect will use just the circle for the
// intersectionsince the rest is transparent.
var managedImageSurface = await _imageLoader.CreateManagedSurfaceFromUriAsync(new Uri("http://sendus.pics/uploads/" + ImagePass + "/0.png", UriKind.Absolute));
//var managedImageSurface = await _imageLoader.CreateManagedSurfaceFromUriAsync(new Uri("ms-appx:///Assets/colour.jpg", UriKind.Absolute));
var managedMaskSurface = await _imageLoader.CreateManagedSurfaceFromUriAsync(new Uri("ms-appx:///" + MaskImage, UriKind.Absolute));
// Create brushes from our surfaces.
var imageBrush = _compositor.CreateSurfaceBrush(managedImageSurface.Surface);
var maskBrush = _compositor.CreateSurfaceBrush(managedMaskSurface.Surface);
// Create an setup our effect brush.Assign both the base image and mask image
// brushes as source parameters in the effect (with the same names we used in
// the effect definition). If we wanted, we could create many effect brushes
// and use different images in all of them.
var effectBrush = _effectFactory.CreateBrush();
effectBrush.SetSourceParameter("image", imageBrush);
effectBrush.SetSourceParameter("mask", maskBrush);
// All that's left is to create a visual, assign the effect brush to the Brush
// property, and attach it into the tree...
var visual = _compositor.CreateSpriteVisual();
visual.Size = new Vector2(MaskH, MaskW);
visual.Offset = new Vector3(0, 300, 0);
visual.Brush = effectBrush;
ElementCompositionPreview.SetElementChildVisual(this, visual);
}
I am using MagickNet for image manipulation in my ASP.NET C# project. My issue is that I am uploading a PNG image with transparency and when I convert it to JPEG, I get a black background with some white spots instead of a white background for the transparent part.
Stream su = upload.FileContent;
MagickNet.Image testimage = new MagickNet.Image(su);
testimage.Filter = FilterType.LanczosFilter;
testimage.Compression = CompressionType.JPEGCompression;
testimage.QuantizeDither = false;
testimage.BackgroundColor = new Color(System.Drawing.Color.White);
testimage.Resize( new System.Drawing.Size(Convert.ToInt32(testimage.Size.Width * 0.4), Convert.ToInt32(testimage.Size.Height * 0.4)));
testimage.Write(System.Web.HttpContext.Current.Server.MapPath(".") + "\\temp\\" + DateTime.Now.Hour + "-" +DateTime.Now.Minute + "-" + DateTime.Now.Second + ".jpg");
su.Close();
su.Dispose();
testimage.Dispose();
Magick.Term();
I played with it and always get the wrong result that I am after. Sometimes I get a transparent background but some parts of the image at the outer region have white dots. I also resize the image to be smaller than what it is. I think the re-sizing it causing the issue.
update: this is caused because of the resizing for some reason. Without resizing it works. Having said that, I need to resize, so I need it to work with it.
Thanks.
Try to composite onto a white background image.
Image bg = new Image(testimage.Size, new ColorRGB(255, 255, 255));
testimage = bg.Composite(testimage, 0, 0);
First of all, it is better to create your MagickImage object with the desirable size the speed of reading the file/stream with the required size can in some situation 100 times faster. You may not have that error.
using(var testimage = new MagickImage(yourstream/yourFileAddress, width, height)
{
....
}
But if you convert the MagickImage to Bitmap and then save the bitmap as jpg you can see that the image has a white background
using (var testBitmap = testimage.ToBitmap())
{
testBitmap.Save(#"d:\temp.jpg");
}
also using is much better that calling dispose member function. Because if your code throw exception before it reaches the dispose call your object will remain in the memory. But with using, if program jump out of the block the object will be disposed.
I'm trying to print image from Silverlight application. I have pretty good quality scans (TIFF) with resolution 1696x2200
When I print - I get PrintableArea from PrintDocument and it's 816x1056
What I do - I resize bitmap to Printable area (to fit document to page) and result I get is blurry image. I understand this is scaling problem (most likely), but how do I scale properly so it looks good? When I display document inside Image and just set image size - it looks good.
For resizing I'm using WriteableBitmapEx extensions and tried both types of resize (Nearest neighbor and bilinear)
Code:
var printDocument = new PrintDocument();
printDocument.PrintPage += (s, ea) =>
{
var printableArea = ea.PrintableArea;
var bitmap = this.currentPreviewPage.FullBitmap.Resize((int)printableArea.Width, (int)printableArea.Height, WriteableBitmapExtensions.Interpolation.Bilinear);
var image = new Image { Source = bitmap };
var canvas = new Canvas { Width = bitmap.PixelWidth, Height = bitmap.PixelHeight };
canvas.Children.Add(image);
ea.PageVisual = canvas;
ea.HasMorePages = false;
};
printDocument.PrintBitmap("Silverlight Bitmap Print");
How document looks on screen (inside Image)
And this is printed:
Rather than using the WriteableBitmapEx extensions, when declaring your Image element, try setting the Stretch property so that it stretches based on your maximum specified dimensions:
var image = new Image { Source = bitmap, Stretch = Stretch.UniformToFill };
Blilinear filter tends to blur images.You may want to try WriteableBitmapExtensions.Interpolation.NearestNeighbor instead to see if you get better results
In my case it was enough to set UseLayoutRounding="True".