WPF - Getting Image Width/Height from internet URL - wpf

I've managed to get an image's width/height if its stored in my computer with the following code:(Fullpath is the file's full location)
var bitmapFrame = BitmapFrame.Create(new Uri(FullPath), BitmapCreateOptions.DelayCreation, BitmapCacheOption.None);
var width = bitmapFrame.PixelWidth;
var height = bitmapFrame.PixelHeight;
But the second I try to change the FullPath to an internet image (such as http://www.interweb.in/attachments/pc-wallpapers/16187d1222942178-nature-wallpaper-nature-summer-wallpaper.jpg) the width and height will not determine the real values needed and will just remain with the value of "1".
I've been sitting for a few hours here trying to figure out what went wrong and working a way around it but without success.
Thank you very much in advance!

Try this. For net Uri the ImageSource will download the image asynchronously, to avoid blocking.
var bitmapFrame = BitmapFrame.Create(new Uri(FullPath), BitmapCreateOptions.None, BitmapCacheOption.None);
if(bitmapFrame.IsDownloading)
{
bitmapFrame.DownloadCompleted += (e, arg) =>{
var width = bitmapFrame.PixelWidth;
var height = bitmapFrame.PixelHeight;
}
}
You want to wait for the DownloadCompleted event.

Related

Screenshot WPF app not working on second monitor

There are other similar questions, but they deal with only screenshotting the displayed application. My application is transparent, so I need to take a screenshot of both the displayed window and the background behind it.
This function correctly screenshots the app on my main monitor, but when it goes to the other monitor, the screenshots are the wrong shape and are completely black. If the window is partly on the monitor, then it still works, but as soon as the other monitor takes control of the window, I get black screenshots. How do I get the screenshots to render correctly?
Here is my function:
public void SaveSnapshot2(int count)
{
string imageName = "image" + count.ToString() + ".jpeg";
string basePath = Path.GetFullPath(Environment.CurrentDirectory);
string folderPath = Path.Combine(basePath, "Snapshots");
string fullPath = Path.Combine(folderPath, imageName);
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
System.Windows.Point relativeWindowPosition = App.Current.MainWindow.PointToScreen(new System.Windows.Point(0, 0));
System.Windows.Point relativeBottomRightWindowPosition = App.Current.MainWindow.PointToScreen(new System.Windows.Point(App.Current.MainWindow.Width, App.Current.MainWindow.Height));
System.Windows.Point actualWidthHeight = new System.Windows.Point((relativeBottomRightWindowPosition.X - relativeWindowPosition.X), (relativeBottomRightWindowPosition.Y - relativeWindowPosition.Y));
System.Drawing.Size convertedSize = new System.Drawing.Size((int)actualWidthHeight.X, (int)actualWidthHeight.Y);
Bitmap Screenshot = new Bitmap((int)actualWidthHeight.X, (int)actualWidthHeight.Y, PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(Screenshot))
{
// Crops the screenshot
// The relativePoint is where the top left corner of the image is. This is correct.
g.CopyFromScreen((int)relativeWindowPosition.X, (int)relativeWindowPosition.Y, 0, 0, convertedSize); // or (0, 0, 0, 0, Screenshot.Size) to get the whole bitmap image
}
try
{
Screenshot.Save(fullPath, ImageFormat.Jpeg);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ", the image did not save.");
}
Screenshot.Dispose();
}
Coming up with names for the points was difficult. I hope they are clear enough.
Does the coordinate system change when a window is on a separate monitor? Am I going about this the right way?
I guess you have not declared DPI awareness in the application manifest. It's a common pitfall when you have multiple monitors of different DPI. If have not, most methods and functions related to screen coordinates will return incorrect values and thus the calculation based on those values will be screwed up.
To solve this, add the application manifest which declares DPI awareness. See Setting the default DPI awareness for a process. PerMonitorV2 is the key for Per-Monitor DPI.

Codename One rounded image from an internet source

I am trying to display a rounded image that I get straight from the Internet.
I used the code below to create a round mask, get the image from the Internet, then tried to either set the mask on the image or the label itself. None of these approaches worked. If I remove the mask, the image is displayed fine. If I keep the code to set the mask then all I see is an empty white circle.
I have the idea that if I apply the mask on the image itself, then it may not take effect because the image was not downloaded at the time the mask was applied.
But I don't seem to understand why calling setMask on the label is also not working.
// Create MASK
Image maskImage = Image.createImage(w, l);
Graphics g = maskImage.getGraphics();
g.setAntiAliased(true);
g.setColor(0x000000);
g.fillRect(0, 0, w, l);
g.setColor(0xffffff);
g.fillArc(0, 0, w, l, 0, 360);
Object mask = maskImage.createMask();
// GET IMAGE
com.cloudinary.Cloudinary cloudinary = new com.cloudinary.Cloudinary(ObjectUtils.asMap(
"cloud_name", "REMOVED",
"api_key", "REMOVED",
"api_secret", "REMOVED"));
// Disable private CDN URLs as this doesn't seem to work with free accounts
cloudinary.config.privateCdn = false;
Image placeholder = Image.createImage(150, 150);
EncodedImage encImage = EncodedImage.createFromImage(placeholder, false);
Image img2 = cloudinary.url()
.type("fetch") // Says we are fetching an image
.format("jpg") // We want it to be a jpg
.transformation(
new Transformation()
.radius("max").width(150).height(150).crop("thumb").gravity("faces").image(encImage, "http://upload.wikimedia.org/wikipedia/commons/4/46/Jennifer_Lawrence_at_the_83rd_Academy_Awards.jpg");
Label label = new Label(img2);
label.setMask(mask); // also tried to do img2.applyMask(mask); before passing img2
So I tried various things:
1) Removing the mask that was set through cloudinary - That did not work
2) applied the mask to the placeholder & encoded image (as expected these shouldnt affect the final version that is getting published)
3) This is what works! I am not sure if the issue is really with downloading the picture before or after applying the mask.. time can tell down the road
Label label = new Label();
img2.applyMask(mask); // If you remove this line , the image will no longer be displayed, I will only see a rounded white circle ! I am not sure what this is doing, it might be simply stalling the process until the image is downloaded? or maybe somehow calling repaint or revalidate
label.setIcon( img2.applyMask(mask));
Here is what worked for me if anyone else is having similar issues:
//CREATE MASK
Image maskImage = Image.createImage(w, l);
Graphics g = maskImage.getGraphics();
g.setAntiAliased(true);
g.setColor(0x000000);
g.fillRect(0, 0, w, l);
g.setColor(0xffffff);
g.fillArc(0, 0, w, l, 0, 360);
Object mask = maskImage.createMask();
//CONNECT TO CLOUDINARY
com.cloudinary.Cloudinary cloudinary = new com.cloudinary.Cloudinary(ObjectUtils.asMap(
"cloud_name", "REMOVED",
"api_key", "REMOVED",
"api_secret", "REMOVED"));
// Disable private CDN URLs as this doesn't seem to work with free accounts
cloudinary.config.privateCdn = false;
//CREATE IMAGE PLACEHOLDERS
Image placeholder = Image.createImage(w, l);
EncodedImage encImage = EncodedImage.createFromImage(placeholder, false);
//DOWNLOAD IMAGE
Image img2 = cloudinary.url()
.type("fetch") // Says we are fetching an image
.format("jpg") // We want it to be a jpg
.transformation(
new Transformation()
.crop("thumb").gravity("faces")
.image(encImage, url);
// Add the image to a label and place it on the form.
//GetCircleImage(img2);
Label label = new Label();
img2.applyMask(mask); // If you remove this line , the image will no longer be displayed, I will only see a rounded white circle ! I am not sure what this is doing, it might be simply stalling the process until the image is downloaded? or maybe somehow calling repaint or revalidate
label.setIcon( img2.applyMask(mask));
Shai, I seriously appreciate your time!! Thank you very much. Will have to dig more into it if it gives me any other problems later but it seems to consistently work for now.
The Cloudinary API returns a URLImage which doesn't work well with the Label.setMask() method because, technically, a URLImage is an animated image (it is a placeholder image until it finishes loading, and then "animates" to become the target image).
I have just released a new version of the cloudinary cn1lib which gives you a couple of options for working around this.
I have added two new image() methods. One that takes an ImageAdapter parameter that you can use to apply the mask to the image itself, before setting it as the icon for the label. Then you wouldn't use Label.setMask() at all.
See javadocs for this method here
The other method uses the new Async image loading APIs underneath to load the image asynchronously. The image you receive in the callback is a "real" image so you can use it with a mask normally.
See javadocs for this method here
We are looking at adding a soft warning to the Label.setMask() and setIcon() methods if you try to add an "animated" image and mask it so that it is more clear.
I think the making code you set to the label might be conflicting with the masking code you get from Cloudinary.

WPF printing - PrintableAreaWidth & Height stuck in landscape?

I'm printing a FlowDocument using the following code:-
var printDialog = new PrintDialog();
var result = printDialog.ShowDialog();
if (!result.Value)
{
return;
}
var pageWidth = printDialog.PrintableAreaWidth;
var pageHeight = printDialog.PrintableAreaHeight;
flowDoc.ColumnWidth = pageWidth;
flowDoc.PageWidth = pageWidth;
flowDoc.PageHeight = pageHeight;
var paginator = ((IDocumentPaginatorSource)flowDoc).DocumentPaginator;
printDialog.PrintDocument(paginator, "Name");
The print dialog shows the page as being A4 Portrait, however the values of printDialog.PrintableAreaWidth and .PrintableAreaHeight are 1122 & 793 respectively, i.e. landscape.
Changing the orientation or the paper size via the dialog has no effect on these values. What's going on?
Update
I've added a screenshot showing the PrintDialog properties. Notice how the PrintTicket property reflects the correct page size and orientation, yet the two PrintableArea... properties are the wrong way around.
I'm starting to think this is a "funny" with the printer/driver. I've tried printing to the "XPS Document Writer" printer, and the pages render correctly when I view the created file. (And if I view the PrintDialog's properties, the PrintableArea... properties correctly reflect an A4 portrait page).

Null values for PageMediaSize of a PrintTicket with Adobe PDF Creator using custom page size

I'm writing a WPF application to get and save print profiles (and another application using this print profiles to print documents).
It works fine except when I try to use Adobe PDF Creator has a printer with custom size (like 800mm by 1200mm). Then the PageMediaSize Width and Height are null in the print ticket.
Here's the code I use to get the PrintTicket :
PrintDialog pd = new PrintDialog();
if (pd.ShowDialog() == true)
{
PrintDocument doc = new PrintDocument();
doc.PrintPage += (o, a) =>
{
PrintQueue pq = pd.PrintQueue;
PrintTicket ticket = pd.PrintTicket;
...
a.Cancel = true;
};
doc.Print();
}
The PrindDialog contains the correct width and height for the page, but if I try to use the PrintTicket to print a document it crash, stating that PageMediaSize cannot contains null values.
Anyone have an idea on how to get a working PrintTicket ?
It sounds like a problem with Adobe PDF Creator's driver. The driver provides values for all the sizes, so if there is a problem, you might want to contact the makers of the printer/driver.
A way around this would be to figure out the sizes (800mm x 1200mm) and assume a resolution of 1/96 inches. Then do a conversion:
Width: ( 800mm) / (25.4 mm/in) / (1/96in) = 3023.62
Height: (1200mm) / (25.4 mm/in) / (1/96in) = 4535.43
And with those values you can say:
pd.PrintTicket.PageMediaSize = new PageMediaSize(Width, Height);

The DoubleAnimation doesn't work

//Create my grid and child controls
var layoutRoot = new System.Windows.Controls.Grid
{
Background = new SolidColorBrush(Colors.Blue),
Name = "layaoutRoot1",
Height = 400.0,
VerticalAlignment = System.Windows.VerticalAlignment.Stretch,
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch
};
layoutRoot.ColumnDefinitions.Add(new ColumnDefinition()
{
Width = new GridLength(1, GridUnitType.Auto)
});
layoutRoot.ColumnDefinitions.Add(new ColumnDefinition()
{
Width = new GridLength(1, GridUnitType.Star)
});
var myImage = new Image
{
Source = new BitmapImage(new Uri(#"C:\Path\to\Image\img.png")),
Stretch = Stretch.UniformToFill,
Margin = new Thickness(3),
Width = 50.0,
Height = 50.0,
};
var textBlocklbl = new TextBlock
{
Text = "Label Here",
FontFamily = new FontFamily("Arial"),
FontSize = 14.0,
FontWeight = FontWeights.Bold,
Margin = new Thickness(3)
};
layoutRoot.Children.Add(myImage);
layoutRoot.Children.Add(textBlocklbl);
System.Windows.Controls.Grid.SetColumn(myImage, 0);
System.Windows.Controls.Grid.SetColumn(textBlocklbl, 1);
grid1.Children.Add(layoutRoot); //grid1 is placed on the MainWindow
Storyboard myStorboard = new Storyboard();
DoubleAnimation myDoubleAnimation = new DoubleAnimation();
myDoubleAnimation.From = 0.0;
myDoubleAnimation.To = 300.0;
myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(3));
myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
//myDoubleAnimation.AutoReverse = true;
myStorboard.Children.Add(myDoubleAnimation);
Storyboard.SetTargetName(myDoubleAnimation, layoutRoot.Name);
Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(System.Windows.Controls.Grid.HeightProperty));
myStorboard.Begin();
Your animation cannot find source for animation. Setting TargetName will not work until you put animation into logical tree. Use StoryBoard.SetTarget(layoutRoot) instead of StoryBoard.SetTargetName(layoutRoot.Name).
Here is what you could do to resolve it:
1) First of all you could debug it. You just launch the code in Visual Studio in debug mode and keep looking into Output window until you see error there. I believe you will see it there soon - then you can fix it. There is still a chance that you won't see any errors.
2) Second, you should try to debug it again. Take your code, paste it into clean solution. Still doesn't work? Great! Keep removing parts of the code which doesn't look related to the issue. VerticalAlighnment, HorizontalAlignment, do you really need them? Can the issue be reproducible without those properties? Remove them. Less code - easier to debug. Ok, finally you have 10 lines of code but it still doesn't work. Take a sample from MSDN which is working and looks as close to your as possible and find the difference. You can even replace parts of your code with MSDN one to see whether it will help or not.
3) And ok, it still doesn't work, you haven't found any samples and there is no way for you to debug it - you need community help. Ask question correctly. If you are a professional developer then probably you've seen it many times - users coming with only one statement it doesn't work. You have to test/debug/fix it completely on your own. But those are your clients, they will pay you money eventually. This is free community which is driven only on behalf of our interest. If we are not interested to answer your question - we will never answer it. So ask a question which worth answering. Pasting the code which doesn't work is not enough. You should also provide an information regarding the part which doesn't work. And what have you tried to fix it yourself. If we will think that you're trying to exploit us - we won't answer your question.
Thanks for your time.
UPDATE Ok, just tried to debug it. Exactly as I said. Your code gives an exception that layoutRoot cannot be found. The exact message is: No applicable name scope exists to resolve the name 'layaoutRoot1'.. You just had to run your own code in VS, exactly as you said.

Resources