Can I get the Height and Width of an Image, if it has been Stretched by UniformToFill?
I tried Width and Height properties but they are always NaN.
If you want to know the dimensions of the image control, this is the way:
double theHeight = this.ActualHeight - img.Margin.Top - img.Margin.Bottom;
double theWidth = this.ActualWidth - img.Margin.Left - img.Margin.Right;
(img is the image control name in the code above, and in the codes below)
And if you want to know actual size of image (before it being stretched) you may try this:
BitmapSource SourceData = (BitmapSource)img.Source;
double imgWidth = SourceData.PixelWidth;
double imgHeight = SourceData.PixelHeight;
(I've Found this here)
Also this will get you the dimensions of image after resizing (But before uniforming):
double actWidth = img.ActualWidth;
double actHeight = img.ActualHeight;
So, one of those variables (actWidth or actHeight) must be equal to image control dimension, and the other will be higher than it.
Please note that the second and the third codes are not working if you call them in Window_Loaded event, since images are not loaded at that moment. You should use it after everything is loaded.
Related
I've searched a bit around the discussions\forums/StackOverflow/Official documentation, but i couldn't find much information about how to achieve what i'm trying. Most of the official documentation covers the command-line version of ImageMagick.
I'll describe what i'm trying to do:
I have a image loaded that i would like to paste into a larger one.
Ex: the image i loaded has 9920 width, 7085 height. I would like to place it in the middle of a larger one (10594 width, 7387 height). I do have all border calculation ready ([larger width - original width / 2] , same goes for height).
But i don't know how to do it using MagickImage. Here's the max i got:
private void drawInkzone(MagickImage loadedImage, List<string>inkzoneAreaInformation, string filePath)
{
unitConversion converter = new unitConversion();
List<double> inkZoneInfo = inkZoneListFill(inkzoneAreaInformation);
float DPI = getImageDPI(filePath);
double zoneAreaWidth_Pixels = converter.mmToPixel(inkZoneInfo.ElementAt(4), DPI);
double zoneAreaHeight_Pixels = converter.mmToPixel(inkZoneInfo.ElementAt(5), DPI);
using (MagickImage image = new MagickImage(MagickColor.FromRgb(255, 255, 255), Convert.ToInt32(zoneAreaWidth_Pixels), Convert.ToInt32(zoneAreaHeight_Pixels)))
{
//first: defining the larger image, with a white background (must be transparent, but for now its okay)
using (MagickImage original = loadedImage.Clone())
{
//Cloned the original image (already passed as parameter)
}
}
Here's the max i got. In order to achieve this, i used the following post:
How to process only one part of image by ImageMagick?
And i'm not using GDI+ because i'll be always working with larger TIFF files (big resolutions), and GDI+ tends to throw exceptions (Parameter not valid, out of memory) when it can't handle everything (i loaded three images with an resolution like that, and got out of memory).
Any help will be kindly appreciate, thanks.
Pablo.
You could either Composite the image on top of a new image with the required background or you could Clone and Extent if with the required background. In the answer from #Pablo Costa there is an example for Compositing the image so here is an example on how you could extent the image:
private void drawInkzone(MagickImage loadedImage, List<string> inkzoneAreaInformation, string filePath)
{
unitConversion converter = new unitConversion();
List<double> inkZoneInfo = inkZoneListFill(inkzoneAreaInformation);
float DPI = getImageDPI(filePath);
double zoneAreaWidth_Pixels = converter.mmToPixel(inkZoneInfo.ElementAt(4), DPI);
double zoneAreaHeight_Pixels = converter.mmToPixel(inkZoneInfo.ElementAt(5), DPI);
using (MagickImage image = loadedImage.Clone())
{
MagickColor background = MagickColors.Black;
int width = (int)zoneAreaWidth_Pixels;
int height = (int)zoneAreaHeight_Pixels;
image.Extent(width, height, Gravity.Center, background);
image.Write(#"C:\DI_PLOT\whatever.png");
}
}
I managed to accomplish what i needed.
Cool that i didn't had to calculate borders.
Here's the code:
private void drawInkzone(MagickImage loadedImage, List<string>inkzoneAreaInformation, string filePath)
{
unitConversion converter = new unitConversion();
List<double> inkZoneInfo = inkZoneListFill(inkzoneAreaInformation); //Larger image information
float DPI = getImageDPI(filePath);
double zoneAreaWidth_Pixels = converter.mmToPixel(inkZoneInfo.ElementAt(4), DPI); //Width and height for the larger image are in mm , converted them to pixel
double zoneAreaHeight_Pixels = converter.mmToPixel(inkZoneInfo.ElementAt(5), DPI);//Formula (is: mm * imageDPI) / 25.4
using (MagickImage image = new MagickImage(MagickColor.FromRgb(0, 0, 0), Convert.ToInt32(zoneAreaWidth_Pixels), Convert.ToInt32(zoneAreaHeight_Pixels)))
{
//first: defining the larger image, with a white background (must be transparent, but for now its okay)
using (MagickImage original = loadedImage.Clone())
{
//Cloned the original image (already passed as parameter)
image.Composite(loadedImage, Gravity.Center);
image.Write(#"C:\DI_PLOT\whatever.png");
}
}
Hope this helps someone :)
Here's what I have:
var rand = new Random();
var files = Directory.GetFiles("C:/Projects/MOMENTUM/MOMENTUM/pics/", "*.jpg");
Image bgimage = new Bitmap(files[rand.Next(files.Length)]);
BackgroundImage = bgimage;
Rectangle UsedScreen = Screen.FromControl(this).Bounds;
if (UsedScreen.Height / UsedScreen.Width > bgimage.Height / bgimage.Width)
{
//SET IMAGE HEIGHT TO SCREEN HEIGHT
}
else
{
//SET IMAGE WIDTH TO SCREEN WIDTH
}
As you see, I first choose a random image from a specific folder and then set this as background image.
I want this application to run in full screen. However, if i set the bgimage ImageLayout property to Zoom, there will be this ugly borders and if I set it to stretch, it will look awful.
I want to achieve the following:
I get the current used screensize via screen bounds, and then adjust the image to fit the screen without being distorted.
Part of the image will be cut away but the main aim is, that the entire screen is always filled out by the image (See the comments in if). I don't know how to do this because if I try
bgimage.Height = UsedScreen.Height
I cant overwrite the image height.
Any ideas?
I want to assign height and width of dynamically created image to a canvas .
Here is my code
Image image=new Image();
BitmapImage bm=new BitmapImage();
bm.UriSource=new Uri("url",Urikind.RelativeOrAbsolute);
image.Source=bm;
MyCanvas.Height=image.Height;
MyCanvas.Width=image.Width;
but it gives 0.0 value when i check in debug mode ,when I change image.Height to image.ActualHeight it gives NaN .
How to resolve this.
You should use the ActualWidth and ActualHeight properties of the Image control. The Width and Height are the dimensions you want the control to have; by default their value is double.NaN, which means "Auto".
But anyway, it still won't be enough:
at this point, the image has not finished loading, so its width and height are not accessible yet. You need to initialize the image like that:
BitmapImage bm=new BitmapImage();
bm.BeginInit();
bm.UriSource=new Uri("url",Urikind.RelativeOrAbsolute);
bm.EndInit();
the Image control is not yet part of the visual tree, so its dimensions can't be computed
So ActualWidth and ActualHeight will still not give your the correct values... A better way would be to set the canvas size according to the width and height of the BitmapImage:
MyCanvas.Height= bm.Height;
MyCanvas.Width = bm.Width;
I solved it in this way
BitmapImage bm = new BitmapImage();
bm.UriSource=new Uri("ms-appx:///" + d.source, UriKind.RelativeOrAbsolute);
bm.ImageOpened += (sender, e1) =>
{
DrawCanvas.Height = bm.PixelHeight;
DrawCanvas.Width = bm.PixelWidth;
};
I am trying to use a C# port of TwoDScrollView in a Xamarin/Android project.
It works fine. We are adding scale gesture (we are showing an image that can be zoomed in/out by the user). That works fine as well.
The issue is that TwoDScrollView relies on ImageView.Width and ImageView.Height to make its calculation and that does NOT change - causing problems when trying to scroll after scaling. On resizing we are doing:
fullscreenImageView.ScaleX = _scaleFactor;
fullscreenImageView.ScaleY = _scaleFactor;
var lp = fullscreenImageView.LayoutParameters;
lp.Width = (int) (fullscreenImageView.Drawable.IntrinsicWidth * _scaleFactor);
lp.Height = (int) (fullscreenImageView.Drawable.IntrinsicHeight * _scaleFactor);
fullscreenImageView.RequestLayout (); //the request layout was just a test,
// it doesn't work either way
We can see how the layoutparameter width and height change, but the View.Width and View.Height never change... it is always the dimensions of the original image we loaded. How can we make that update? (one solution is to scale the bitmap and assign it to the imageview, but that's lousy and slow).
thanks.
According to this answer you should be able to set the dimensions of an ImageView object like this
image_view.getLayoutParams().width = (int) (fullscreenImageView.Drawable.IntrinsicWidth * _scaleFactor);
image_view.getLayoutParams().height = (int) (fullscreenImageView.Drawable.IntrinsicHeight * _scaleFactor);
where image_view is a reference to the same ImageView instance that your TwoDScrollView is looking to for dimensions.
Assuming your fullscreenImageView extends ImageView you can add this method in your fullscreenImageView
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = width * getDrawable().getIntrinsicHeight() / getDrawable().getIntrinsicWidth();
setMeasuredDimension(width, height);
}
I'm working on some image processing and for debug I'm overlaying colours on the original bitmap.
The problem is the image is rendered in a picture box with SizeMode set to Zoom and invalidating every time I update a pixel is Really slow and just gets slower the larger picturebox is (for the same size image)
What I think might help is if I only invalidate the pixel(s) I've changed but I don't know how convert the co-ordinates of the pixel I've changed into a rectangle rendered on the control. Obviously if the image is being drawn larger than the original image then the rectangle I'm invalidating is going to be more than one pixel
Added a method to get the zoom and padding of the picture pox
private void CalculateZoomAndPadding()
{
Double imageAspect = (Double)pictureBox1.Image.Width / (Double)pictureBox1.Image.Height;
Double pbAspect = (Double)pictureBox1.Width / (Double)pictureBox1.Height;
Boolean heightRestricted = imageAspect < pbAspect;
hPadding = 0;
vPadding = 0;
if (heightRestricted)
{
zoom = (Double)pictureBox1.Height / (Double)pictureBox1.Image.Height;
Double imageWidth = (Double)pictureBox1.Image.Width * zoom;
hPadding = (Double)(pictureBox1.Width - imageWidth) / 2d;
}
else
{
zoom = (Double)pictureBox1.Width / (Double)pictureBox1.Image.Width;
Double imageHeight = (Double)pictureBox1.Image.Height * zoom;
vPadding = (Double)(pictureBox1.Height - imageHeight) / 2d;
}
}
then to invalidate a pixel called invalidate like this:
pictureBox1.Invalidate(new Rectangle(Convert.ToInt32(Math.Floor(x * zoom)) + Convert.ToInt32(hPadding) -1, Convert.ToInt32(Math.Floor(y * zoom)) + Convert.ToInt32(vPadding) -1, PixelSize, PixelSize));
when I first did this I only invalidated the are directly covered by the pixel but found that this was subject to rounding errors so expanded it to include a few extra.
Can you change all the pixels and then just invalidate the image once?
I'd just add a timer that fires 30 or 60 times per second that invalidates the whole control. While there might be a slight delay in updating you shouldn't be able to notice it due to your monitor's refresh rate most likely being 60 Hz only anyway.