WPF Background setting failed - wpf

Here is a code.
var image = new BitmapImage(new Uri(#"pack://application:,,,/Images/background.png",
UriKind.RelativeOrAbsolute));
var backgroundBrush = new ImageBrush()
{
ImageSource = image,
Viewport = new Rect(0, 0, image.PixelWidth / ActualWidth,
image.PixelHeight / ActualHeight),
TileMode = TileMode.Tile,
Stretch = Stretch.None,
};
// Set it for the main window.
Background = backgroundBrush;
It works just fine on my PC with XPSP3 and .Net 4.0. But when I run the same sample on Eee PC T91MT with Windows 7 Home Premium it fails. No exceptions, but nothing is drawn (solid color brushes ARE drawn if used instead, though). I thought it could be the result of limited resources, but on Viliv S5, that has about the same specs it works fine too.
Any ideas?
Thanks!
UPDATE
The root of the problem is Viewport's rect. Since the bitmap has twice window's size by X, the rect is (0, 0, 2, 1). So, on power computer with XPSP3, the left half of the image is drawn. But on Eee PC it causes a problem with visualization.

The answer is just normalizing Viewport rectangle. E.g. instead of (0,0,2,1) I had to set it as (0,0,1,0.5).
I'm not sure, but it looks like WPF just transmit rect values (after some transformation) into a D3D driver, which is (or is not) able to handle it the right way. So, non-normalized rect Viewport works on GeForce-based machine but does not on Eee PC with it's integrated video's driver.

Related

WPF FormattedText randomly disappears in high resolution images

I have the requirement to create 600 DPI "trifold" images, which have the dimensions of 25.5"x11" (three times the size of a Letter page). To do so, I’m using WPF Imaging through the DrawingVisual, DrawingContext, and RenderTargetBitmap classes.
When I generate the image in lower resolutions, 400 DPI or less for example, all of the text displays in the correct positions as expected. However, once I increase my image resolution to the 500 DPI level and beyond, certain text positioned in the far right of the image will simply disappear, while other relatively positioned text/shapes print perfectly. The craziest part about it is that as I try varying DPIs, different text will appear/disappear. In one test case, 600 DPI is missing one set of drawn FormattedTexts, 650 DPI is missing a different set of drawn FormattedTexts, and 700 DPI prints everything fine!
I’ve recreated the issue with the snippet of code below. Run as-is (600 DPI) and all you get is a very large white image. Change the Dpi constant to 400 or lower, and it prints the text just fine.
Note that I’ve tried turning many of the knobs within the DrawingVisual class (e.g. VisualBitmapScalingMode, VisualTextRenderingMode, VisualEdgeMode, etc.) to no avail. Most of my research on those settings found them as useful settings to correct “fuzzy” text, not disappearing text. I’ve also had no luck with any of the guideline/snap settings of the DrawingVisual or DrawingContext.
Note that I’ve recreated this issue on both Win7 and Win2008R2, and my application is running .NET 4.5.
Any ideas?
const double ImageWidthInches = 25.5;
const double ImageHeightInches = 11.0;
const double Dpi = 600.0;
const double DeviceIndependentUnits = 96.0;
const double TypographicUnits = 72.0;
var visual = new DrawingVisual();
var drawing = visual.RenderOpen();
drawing.DrawRectangle(
Brushes.White,
null,
new Rect(0,
0,
ImageWidthInches*DeviceIndependentUnits,
ImageHeightInches*DeviceIndependentUnits));
var formattedText = new FormattedText(
"Why doesn't this display?",
CultureInfo.CurrentUICulture,
FlowDirection.LeftToRight,
new Typeface(new FontFamily("Arial Narrow"),
FontStyles.Normal,
FontWeights.Normal,
FontStretches.Normal),
8.0*DeviceIndependentUnits/TypographicUnits,
Brushes.Black);
drawing.DrawText(formattedText,
new Point(23.39*DeviceIndependentUnits,
2.6635416666666671*DeviceIndependentUnits));
drawing.Close();
var renderTarget = new RenderTargetBitmap(
(int) (ImageWidthInches*Dpi),
(int) (ImageHeightInches*Dpi),
Dpi,
Dpi,
PixelFormats.Default);
renderTarget.Render(visual);
var tiffEncoder = new TiffBitmapEncoder {Compression = TiffCompressOption.Ccitt4};
tiffEncoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (var fileStream = new FileStream(#"c:\recreateWpfTextIssue.tif", FileMode.Create, FileAccess.Write))
tiffEncoder.Save(fileStream);
The workaround to this bug is to round the font size to 2 decimal positions:
Math.Round(8.0*DeviceIndependentUnits/TypographicUnits, 2),
This and some extra information can be found in the matching MSDN post: http://social.msdn.microsoft.com/Forums/en-US/98717e53-89f7-4d5f-823b-7184781a7b85/wpf-formattedtext-randomly-disappears-in-high-resolution-images

Drawing to a bitmap from a WPF canvas

I have a canvas that contains an Image in which I dislay an existing BMP. I draw rectangles on the canvas and add these to the Children colllection. When I click save, I want to update the underlying BMP file.
The following code works, but the rectangle that gets drawn to the BMP is way smaller than what I drew. I guess there's some difference in the co-ordinates? Maybe I shouldn't be using System.Drawing?
using (Graphics g = Graphics.FromImage(image))
{
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
foreach (var child in canvas.Children)
{
if (child is System.Windows.Shapes.Rectangle)
{
var oldRect = child as System.Windows.Shapes.Rectangle;
// need to do something here to make the new rect bigger as the scale is clearly different
var rect = new Rectangle((int)Canvas.GetLeft(oldRect), (int)Canvas.GetTop(oldRect), (int)oldRect.Width, (int)oldRect.Height);
g.FillRectangle(Brushes.Black, rect);
}
}
... code to save bmp
All suggestions welcome!
Thanks
Try using the System.Windows.Media.Imaging.RenderTargetBitmap Class (an example here).
Wpf uses Device Independent Graphics so you have to compensate for the DPI :
RenderTargetBitmap bmp = new RenderTargetBitmap((int)Canvas1.Width, (int)Canvas1.Height, 96, 96, PixelFormats.Default);
bmp.Render(Canvas1);
From Third Link:
There are two system factors that determine the size of text and graphics on your screen: resolution and DPI. Resolution describes the number of pixels that appear on the screen. As the resolution gets higher, pixels get smaller, causing graphics and text to appear smaller. A graphic displayed on a monitor set to 1024 x 768 will appear much smaller when the resolution is changed to 1600 x 1200.

winforms app written in win7 looks different on win xp. why?

I have written a simple app in winforms (.net 4.0) on win 7. Application looks how I want but when I tried it on windows xp everything looks different.
I have created a sample example to show how it looks on win 7 and xp.
What can I do to have the same look on both systems?
The problem is not only with the background and font color but with the controls too. Here I show how the numericupdown looks but with table layout I have problem too.
private void InitializeComponent()
{
this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
this.groupBox1 = new System.Windows.Forms.GroupBox();
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
this.SuspendLayout();
//
// numericUpDown1
//
this.numericUpDown1.DecimalPlaces = 2;
this.numericUpDown1.Increment = new decimal(new int[] {
1,
0,
0,
131072});
this.numericUpDown1.Location = new System.Drawing.Point(21, 26);
this.numericUpDown1.Maximum = new decimal(new int[] {
1,
0,
0,
0});
this.numericUpDown1.Name = "numericUpDown1";
this.numericUpDown1.Size = new System.Drawing.Size(54, 22);
this.numericUpDown1.TabIndex = 0;
//
// groupBox1
//
this.groupBox1.Location = new System.Drawing.Point(21, 82);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(226, 99);
this.groupBox1.TabIndex = 1;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "groupBox1";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.ActiveCaption;
this.ClientSize = new System.Drawing.Size(407, 331);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.numericUpDown1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
this.ResumeLayout(false);
}
I have no modified the xp color themes.
I have the same result on two diffrent computers with win xp.
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.ActiveCaption;
These are the statements that cause your trouble. I'll pick-off the easy one first, don't make the BackColor of the form the same as the caption color. If you want to pick a theme color then only choose the "Control" color. Albeit that you'll typically get the old battleship gray. Picking a neutral pastel color is your best bet but honoring the user's preference will never get you into trouble.
The AutoScaleDimensions property is auto-generated, based on the video adapter's DPI setting. Which is different the XP machine. You've got 120 dots-per-inch on your dev machine, 96 DPI (the default) on XP. On Win7, that's set by the widget that looks like a ruler, Control Panel + Display, "Set custom text size (DPI)".
The AutoScaleMode property is correctly set to Font. This ensures that all controls are automatically scaled to fit the font size. Which is larger on your Win7 machine because of the higher DPI setting. Accordingly, the form and its controls shrink on the XP machine. The problem with the NumericUpDown control is that its a bit buggy (in more than one way), it doesn't scale the up/down glyphs properly. They are proportionally too large, not leaving enough room for the text portion. Simply making it a bit wider solves the problem.
Auto-scaling is fairly ugly, it is rarely 100% perfect. The best thing to do is to switch your dev machine to 96 dpi. A very common setting, still today. Scaling up almost always works better than scaling down.
this.BackColor = System.Drawing.SystemColors.ActiveCaption;
There's your problem. The color is going to be dependent on the operating system. http://msdn.microsoft.com/en-us/library/system.drawing.systemcolors.activecaption.aspx
Consider setting an explicit color value (e.g. one of the System.Drawing.Color http://msdn.microsoft.com/en-us/library/system.drawing.color.aspx enumerations) instead. Won't look exactly the same, but it will be closer.

Winforms Print Preview Blurry

I have a print preview that displays a captured panel on a form 'Panel1.DrawToBitmap(memoryImage, bounds);'
I also save the image to my hard drive - 'memoryImage.Save("diary.png")'
The image in the print preview at any zoom level is blurry, the saved image is perfect (viewed in windows photo viewer & PS).
Id like the print preview to be as good as the saved image, any ideas?
here's the code:-
private void CaptureScreen()
{
int x = splitContainerDiary.Location.X;
int y = splitContainerDiary.Location.Y;
int SCwidth = splitContainerDiary.Panel1.Width;
int SCheight = splitContainerDiary.Panel1.Height;
Rectangle bounds = new Rectangle(x, y, SCwidth, SCheight);
memoryImage = new Bitmap(SCwidth, SCheight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
splitContainerDiary.Panel1.DrawToBitmap(memoryImage, bounds);
memoryImage.Save("diary.png");
}
private void printDocumentDiary_PrintPage(object sender, PrintPageEventArgs e)
{
CaptureScreen();
Font HeaderFont = new Font("Consolas", 16, FontStyle.Bold);
e.Graphics.DrawString(selectedYear.ToString() + " - " + name, HeaderFont, Brushes.Black, 15, 15);
e.Graphics.DrawImage(Image.FromFile("diary.png"), 5, 5);
// e.Graphics.DrawImage(memoryImage, 0, 40);
PrintDoodle(e);
}
I have tried to draw the image from memory (e.Graphics.DrawImage(memoryImage, 0, 40) and also from the saved image 'e.Graphics.DrawImage(Image.FromFile("diary.png"), 5, 5);' They are both blurry in print preview.
I have tried different Pixel formats with no joy either.
I have tried saving the image as BMP, JPG, PNG with no joy either (when drawing image fromFile).
I have tried using BitBlt routine also with the same results.
Tino
This is an inevitable consequence of the dramatic difference between the device resolution of a printer vs a monitor. A printer typically can print with a resolution of 600 dots per inch. A monitor is typically set to 96 DPI. So when you print an image that's razor sharp on a monitor, each pixel of the image requires printing a blob of 6 x 6. Short from the blockiness this produces, anything that's drawn on screen with anti-aliasing will get those anti-aliasing pixels drawn 6 times larger as well. Completely ruining the effect. This is especially noticeable with any text that's drawn with ClearType anti-aliasing. The red and blue fringes become very noticeable on paper.
You can partly solve this by drawing the image one-to-one on the printer, ensuring that 1 pixel in the image becomes 1 pixel on paper. That ought to now look nice and sharp (minus the ClearType problem) but you'll be looking at a postage stamp. Growing your arms six times longer would have the same effect.
Well, this just doesn't work well. Use the PrintDocument class so you can draw stuff to the printer using its native resolution. Use the methods provided by e.Graphics in the PrintPage event handler. Avoid images unless they are photos, anything that doesn't have finely detailed line art will scale well.
I have encountered a similar "blurry font" problem, while trying to print out some custom text, which I've pre-arranged as Labels in the TableLayoutPanel.
My solution for the blurriness was as follows: I have created a panel and labels four times as big as the desired final size (by using font 44 instead of 11, and using width and height four times greater).
Then I've created a (large) bitmap, and downscaled it in the final step (DrawImage):
using (var bmp = new Bitmap(tableLayout.Width, tableLayout.Height))
{
tableLayout.DrawToBitmap(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
printPageEventArgs.Graphics.DrawImage(
bmp,
printPageEventArgs.MarginBounds.X,
printPageEventArgs.MarginBounds.Y,
bmp.Width / 4,
bmp.Height / 4);
}
The resulting text looks much sharper both in the preview and in the actual printed page.
Of course, such an approach can only work if you can manipulate the Control's size, for example by creating it "off screen". But it will not work if you require the actual displayed control to be printed.

Image Flipping in WPF

How do you get an image to be reflected in wpf without using the xaml? I have a rectangle with a BitmapImageBrush as its fill. I want to be able to regularly flip this image (X-axis) back and forth at will in C#. I've read about using the ScaleTransform property but this only seems to work in the xaml and that's not what I want.
This is how the image is created:
ImageBrush l = new ImageBrush(new BitmapImage(new Uri(uriPath, UriKind.Relative)));
_animation.Add(l);
_visual = new Rectangle();
_visual.Fill = _animation[0];
_visual.Width = width;
_visual.Height = height;
_visual.Visibility = Visibility.Visible;
_window.GameCanvas.Children.Add(_visual);
_animation is a list of ImageBrushes.
This is really simple, yet I can't seem to figure out how to do it. Please help.
You can still add a scale transform programmatically, rather than using xaml.
For instance, in this article.
To do the flip, set your scale transform to be negative in the direction you want to flip (ie, if horizontal, set x to -1, or -desiredScale if you also want to resize).

Resources