I am drawing a rectangle in millimeter on a panel using the following code in c# by entering the width and length in mm at runtime. However the resultant rectangle drawn varies in size in different monitors. I want the rectangle to appear same size irrespective of the running the app in any monitor. Can any1 help me?. currently the width for 10mm measures 12mm and length for 10mm shows 11mm using a scale. I tested the app on different monitors, there again it shows different length. Is their anyway that I can show it to be of same width and length?
void panel1_Paint(object sender, PaintEventArgs e)
{
SolidBrush ygBrush = new SolidBrush(Color.YellowGreen);
g = panel1.CreateGraphics();
g.PageUnit = GraphicsUnit.Millimeter;
int w = Int32.Parse(textBox1.Text.ToString());
int h = Int32.Parse(textBox2.Text.ToString());
rct = new Rectangle(94, 27, w, h);
g.FillRectangle(ygBrush, rct);
}
Most displays aren't properly configured so that the computer knows the DPI (dots-per-inch). Physical units like millimeters only work if the computer knows how many pixels are in a millimeter, both horizontally and vertically.
Essentially, the method you're using is correct - but you're very unlikely in the real world to come across properly-configured machines.
If you needed to solve this problem in your software you could perhaps include a "configuration" option where the user would be responsible for setting the scale of the application.
Related
I'm working on a basic mindmap program but I don't have a lot of experience with drawing with WPF. I want to be able to draw rectangles with text on them and i would like to be able to click on the rectangles to change the text for example.
As of now I have:
private void DrawSubject(int curve, double X, double Y, Brush clr)
{
Rectangle rect = new Rectangle();
rect.Width = 62;
rect.Height = 38;
rect.Fill = clr;
rect.Stroke = line;
rect.RadiusX = rect.RadiusY = curve;
Canvas.SetLeft(rect, X);
Canvas.SetTop(rect, Y);
mindmap.Children.Add(rect);
}
SolidColorBrush line = new SolidColorBrush(Color.FromArgb(255, 21, 26, 53));
minmap is the name of the canvas. I want to be able to draw a lot of these rectangles which present branches of the mindmap. However, when I drew 10,000 of these on random locations the process memory in the diagnostic tools went up by 100 MB, after it was done drawing all of them. I did this to sort of simulate a mindmap with 10,000 branches. So i was wondering if there might be a way to decrease the used memory for these rectangles?
Or is it better to use DrawingVisual and a grid.click event which checks if the clicked position matches the position of a rectangle by putting the coordinates of the rectangle in a List?
I would attempt the DrawingVisual method you described, if that proves costly in performance(I don't know how well DrawingVisual works) you could look into embedding OpenGL or DirectX into your application and rendering them via that.
But raytracing drawn visuals rather than making a Control for each is definitely the way to go for your scale.
I updated a chart from essentially being 72dpi, to 300dpi. This is because I am using itextsharp to add an image to my pdf and the quality was poor. So I increased the size of the image by 3X and the image does look better, but here is the problem.
DPI has increased, but detail has become very hard to see.
Original Chart Image
Refactored Chart Image
Code
This is how I resized my chart.
private static System.Drawing.Bitmap GetChartBitmap()
{
System.Drawing.Rectangle targetBounds = new System.Drawing.Rectangle(0, 0, chart_runs.Width, chart_runs.Height);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(targetBounds.Width, targetBounds.Height);
bitmap.SetResolution(1000, 1000);
chart_runs.DrawToBitmap(bitmap, targetBounds);
bitmap.Save(#"C:\Temp\OriginalChartImage.bmp");
System.Drawing.Bitmap bitmap3 = new System.Drawing.Bitmap(1650, 990);
bitmap3.SetResolution(300, 300);
chart_runs.DrawToBitmap(bitmap3, new System.Drawing.Rectangle(0, 0, 1650, 990));
bitmap3.Save(#"C:\Temp\RefactoredChartImage.png");
//This stuff below is for my code elsewhere. Using bitmap3 to be added to pdf.
//chart_runs.DrawToBitmap(bitmap, targetBounds);
string path = System.IO.Path.GetTempPath();
bitmap1.Save(path + #"\Image.png");
return bitmap1;
}
I have looked at the Microsoft msdn examples and haven't found anything that addresses my problem. Namely, how can I either increase the size of my labels so people can read them again. OR, is there a way for me to increase the DPI and keep the same label x and label y scale that was used in the first picture? That is, have a larger image and 300DPI, but scale 0 to 300 by 20's and not 5's like my refactored picture?
Attempts to fix
Scaling the axis? See here. I don't think this is working right. Not much success here.
Been trying to find a way in Chart class to see if there is a way to specify strict scales. (20 on y scale vs 15 seconds on x scale).
Most online resources are pleased just to increase the scale of the picture and walk away. And things like this here.
I would greatly appreciate any help and assistance.
Couple different questions, with a couple different answers. The easiest would be to change the font size of your axis labels to be bigger. This can be done via
chart1.ChartAreas[0].AxisX.LabelStyle.Font = new Font...;
Without doing that, your labels won't be readable no matter what else you do, and that's just because you changed the DPI (that's exactly what changing the DPI does).
If you want the labels to be displayed every 20 units on the y axis and every 15 on the x, you can use the Interval and IntervalType properties of the axis. The IntervalType is used when you have DateTime objects being displayed:
chart1.ChartAreas[0].AxisX.Interval = 15;
chart1.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Seconds;
chart1.ChartAreas[0].AxisY.Interval = 20;
Your first link about scaling the axis is essentially zooming in or out, which is why you haven't had success.
Im printing on a labelprinter with 7.5X8 cm labels using the regular GDI+/.NET method and it works fine
void pdPrintLabel(object sender, PrintPageEventArgs ev)
{
Graphics g = ev.Graphics;
using (Font smallFont = new Font(FontFamily.GenericSansSerif, 6),
mediumFont = new Font(FontFamily.GenericSansSerif, 8),
bigFont = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Bold))
{
SizeF smallSize = g.MeasureString("XXX", smallFont);
SizeF mediumSize = g.MeasureString("XXX", mediumFont);
SizeF bigSize = g.MeasureString("XXX", bigFont);
Brush blackBrush = Brushes.Black;
g.DrawString((bagNumber / 50 + 1) + bagNumber, bigFont, blackBrush, pos);
// etc
}
}
Now the printer is changed, same model just a different printer. The same code now fills only half the label. Some setting is different I guess.
I could fix this with
ev.Graphics.ScaleTransform(1.3f, 1.4f);
but only after finetuning/recompiling/testing the arguments. I dont want to change that code every time a new printer is used of course.
So is there an algorithm with which to compute the correct ScaleTransform arguments?
edit:
And on top of that, importing the settings from one printer and exporting them to the other did not change anything
The default scaling mode for printers is GraphicsUnit.Display, one pixel in your code is 0.01 inch on paper. Which is a resolution-independent scaling mode, output will always have the same size on paper regardless of the printer resolution. So you never need to use Graphics.ScaleTransform to adjust the scaling yourself.
There's something wrong with the printer driver for this printer, it appears to mis-report the printer resolution. Which is very rare, particularly so when you use the exact same printer model. Make sure it isn't a built-in feature of the printer to scale output that just happens to have a different setting on the second printer. Not entirely unusual for label printers, they like to accommodate software that isn't designed to deal with various label sizes. You'll need assistance from the manufacturer if you cannot sort it out from the manual.
I've got a 2D game that I'm working on that is in 4:3 aspect ratio. When I switch it to fullscreen mode on my widescreen monitor it stretches. I tried using two viewports to give a black background to where the game shouldn't stretch to, but that left the game in the same size as before. I couldn't get it to fill the viewport that was supposed to hold the whole game.
How can I get it to go fullscreen without stretching and without me needing to modify every position and draw statement in the game? The code I'm using for the viewports is below.
// set the viewport to the whole screen
GraphicsDevice.Viewport = new Viewport
{
X = 0,
Y = 0,
Width = GraphicsDevice.PresentationParameters.BackBufferWidth,
Height = GraphicsDevice.PresentationParameters.BackBufferHeight,
MinDepth = 0,
MaxDepth = 1
};
// clear whole screen to black
GraphicsDevice.Clear(Color.Black);
// figure out the largest area that fits in this resolution at the desired aspect ratio
int width = GraphicsDevice.PresentationParameters.BackBufferWidth;
int height = (int)(width / targetAspectRatio + .5f);
if (height > GraphicsDevice.PresentationParameters.BackBufferHeight)
{
height = GraphicsDevice.PresentationParameters.BackBufferHeight;
width = (int)(height * targetAspectRatio + .5f);
}
//Console.WriteLine("Back: Width: {0}, Height: {0}", GraphicsDevice.PresentationParameters.BackBufferWidth, GraphicsDevice.PresentationParameters.BackBufferHeight);
//Console.WriteLine("Front: Width: {0}, Height: {1}", width, height);
// set up the new viewport centered in the backbuffer
GraphicsDevice.Viewport = new Viewport
{
X = GraphicsDevice.PresentationParameters.BackBufferWidth / 2 - width / 2,
Y = GraphicsDevice.PresentationParameters.BackBufferHeight / 2 - height / 2,
Width = width,
Height = height,
MinDepth = 0,
MaxDepth = 1
};
GraphicsDevice.Clear(Color.CornflowerBlue);
The image below shows what the screen looks like. The black on the sides is what I want (and is from the first viewport) and the second viewport is the game and the cornflower blue area. What I want is to get the game to scale to fill the cornflower blue area.
Use a viewport http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.viewport_members.aspx
As is also the case in commercial games, you should provide an option to the user that allows them to switch between 4:3 aspect and 16:9 aspect. You should be able to just modify the camera viewing ratio accordingly.
EDIT:
As far as I have seen, there are no games that 'auto-detect' the proper aspect ratio to use.
As has been pointed out, there are ways to make a good guess as to what the proper aspect ratio is. If XNA allows you to get at the current Windows user's screen settings data, you can determine an aspect ratio based off of the monitor resolution.
Once you have determined the monitor resolution of the user, you can best decide how to deal with it. At first, the best bet may be to just put black bars on the left/right side of the screen to allow full-screen with a 16:9 aspect ratio that is essentially still using the 4:3 artwork.
Eventually you could modify the game so that it changes the viewing port size when the aspect ratio is 16:9. This wouldn't require changing any art assets, just how they are being rendered.
First of all I'm assuming you're talking about XNA 4.0, which AFAIK there are breaking changes between XNA 3.x and XNA 4.0.
I'm relatively new at XNA, however it seems to me that your assets does not fit the size of the window. Let's say that your game are is 320x240 and your window is bigger e.g. 640x480.
Thus you can specify PreferredBuffer in order to scale up your application. So, tell to XNA you are going to use 320x240 by setting the following values;
_graphics.PreferredBackBufferWidth = 320;
_graphics.PreferredBackBufferHeight = 240;
Additionally you can start fullscreen mode by setting:
_graphics.IsFullScreen = true;
Also, you have to handle manually the how the items should change their size once the Window has changed their size.
Checkout my sample at.
https://github.com/hmadrigal/xnawp7/tree/master/XNASample02
(BTW, you can press F11 to switch between fullscreen and normal view)
Best regards,
Herber
I'm not sure if you can actually scale your view port like that. I understand what you're trying to do, but to do it you'd have to do the following.
Set your screen backbuffer width and height to the 16:9 resolution.
Program in the displacement so that objects didn't draw in those borders.
The thing is, all major games these days, if you play them on a 16:9 monitor and select a 4:3 resolution, will stretch to fit the screen. This isn't something you usually want to overcome. You either support many resolutions in your game, or you will get stretching when a user uses the wrong resolution for his or her screen type.
Usually, one sets up their game, and their textures to work based on the relative dimensions of the current viewport or backbuffer width and height. This way, regardless of the resolution inputted, the game scales to work with that width/height ratio.
It's a bit more work, but in the end, makes your game far more polished and compatible with a wide array of systems.
The only time this may not be done is if the app runs in a window (NOT fullscreen).
I have an application with a textbox, and the width of the textbox on the screen must always be 17,5 centimeters on the screen of the user.
This is what I tried so far:
const double centimeter = 17.5; // the width I need
const double inches = centimeter * 0.393700787; // convert centimeter to inches
float dpi = GetDpiX(); // get the dpi. 96 in my case.
var pixels = dpi*inches; // this should give me the amount of pixels
textbox1.Width = Convert.ToInt32(pixels); // set it. Done.
private float GetDpiX()
{
floar returnValue;
Graphics graphics = CreateGraphics();
returnValue = graphics.DpiX;
graphics.Dispose(); // don’t forget to release the unnecessary resources
return returnValue;
}
But this gives me different sizes with different resolutions.
It gives me 13 cm with 1680 x 1050 and 21,5 cm with 1024 x 768.
What am I doing wrong?
The method graphics.DpiX does not give the real dots per inch of the monitor. It returns the DPI set in Windows Display properties, mostly either 96 or 120 DPI.
It is not possible to read the real DPI of the monitor. Microsoft did research this for Windows Vista/7 but as long as manufactures of monitors do not provide a standard way to read the value from the monitor hardware it will not be possible.
Yes, unfortunately Xenan is right.
To workaround the problem you could allow a sort of by hand calibration, done by the user.
e.g. draw a line of 400 pixel on the screen, ask the user to measure it on the screen and set the result. Now is really simple to calculate the PPI (pixels per inch) that is your calibration.
Width property of the Size structure depend on PageUnit and PageScale settings of the Graphics class. Try playing around with these settings to get your desired effect. Since you most likely need to modify these settings on the Paint event of the control, I suggest you create your own custom TextBox control instead.