PrintDocument - Scale or something else not right? - c#

I'm using a C# printdocument class. My printer's driver is set to print at 1000 DPI. I am placing strings down the page at various intervals. I am using a PageUnit of Pixel (so 1,000 pixels = 1 inch?) to place these DrawString()s down the paper. Higher in the paper, they appear fine; however as you get lower, they aren't quite as far down as they should be. By the bottom of the paper, it's off a quarter of an inch.
Any ideas where I should start to resolve this issue?
For example: the DrawString() that should be Y coordinates 4147 (pixles) down (at 1000 DPI, should be about 4.147 inchs down) is actually only about 4.010 inches down~.

Related

placing text in the middle of the screen

Im using Consolas font to display player score. The screen is 480 wide and i want it to be in the middle. The size is 24 so to place it in the middle, shouldn't i do:
string score = "9999";
middle = 480/2 - (score.Lenght*24)/2;
Some how the text is too much to the left (big numbers) or too much to the right (low numbers).
I though I could calulate this since consolas is a monospaced font?
You're better off using this:
http://msdn.microsoft.com/en-us/library/6xe5hazb%28v=vs.110%29.aspx
Or for xna:
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.spritefont.measurestring.aspx
You can use it to measure exactly how many pixels wide the string will be when you draw it.

Snake in C# - player can scale window - dividing manual-scaled window into identical squares

As part of my self-education of programming I decided to make a snake in C#. The problem I have is about the client size of the game form.
I want player to be able to scale the window of the game, which is divided into 25 x 25 grid (every coordinate is like "one pixel") - it means, that at any moment, the window is divided into 25 x 25 identical squares.
The problem I get is near this code:
int SquareSide = (ClientSize.Width / 25);
When I set the ClientSize strictly to for example 600 x 600, which is a multiple of 25, everything goes OK. But when I don't (for example by manual resizing, which can change the size to, for example, 711 x 711), it creates at the right side a 'strip', which seems to be the rest of pixels, which can't be used because we are dividing to integer number.
My question is - is there any not-extremely-hard way to achieve dividing ANY client size of form into 25 x 25 grid without this problem? I tried using double, but FillRectangle method doesn't accept it.
I hope my question is understandable and thank you for replies.
To tell you the truth, there is
g.FillRectangle(Brush b, RectangleF rect)
RectangleF is a rectangle whose coordinates are float.
So you can use:
float SquareSide = (ClientSize.Width * 1f / 25);
I would try to simply handle OnResize event of the window, and at the moment user finishes rezise it, force the size that program need for perfect fit of the grid.
So for example at the moment user releases mouse and you figure out that one dimensions of the window 711x711, bring it to nearest correct fit 700x700.
In this way you guarantee good user experience on different monitor resolutions and for you guarantee a correct fit of the grid you draw.
Hope this helps.
Switch to float coordinates for everything. Make sure your game looks OK when lines do not have whole pixel coordinates. Make sure you "find next cell" code also works with floats, including mouse position detection if needed.
The other approach is to be happy with integer coordinates (and cells of the same size) and make page layout flexible to accomodate some unused space for odd 711x711 layouts (i.e. just center the field and keep some variable width border).

Detect Original Picture From Scanned Image

When I scan a small picture, the scanner output is a big picture. How can I detect original picture from scanned image?
I think you are confusing physical size with resolution. The photograph you are scanning obviously has a physical size — you can measure this with a ruler. When you scan however, you end up with a picture that has a resolution (pixel size) rather than a physical size and this is controlled by the DPI setting in your scanning software. DPI means dots-per-inch and controls how many dots (pixels) will be created for each inch of your photograph — 300 dpi would result in 300 pixels across for each inch width of your photograph and 300 pixels down for each inch of height. As an example, a photograph 10 inches square would produce a 10 * 300 * 10 * 300 = 9 million pixel (or approximately 9 mega-pixel) image.
Physical size will not actually have much meaning on the computer until you come to print your image again*. Then, you can specify the output DPI — how many pixels make up each inch of your printed document. So if you were to scan at 300 dpi and print at 150 dpi, you would end up with an image that is twice the size of your original (as less pixels are making up each inch so those scanned pixels go twice as far). For example, the 9 million pixels of the above example would be printed 150 for every inch across and down (150² per square inch) thus would produce an image that is 20 inches square.
Physical size and resolution are intertwined, however. The more dpi you scan at, the more information about the original document you preserve which means you can print at much larger sizes without the image appearing pixelated. As an extreme example, if you were to print at 1 dpi, you could make those scanned pixels spread over a huge number of inches but each square inch would be a block of solid colour.
* The web mixes things up in that images are usually handled in pixel form thus their size on screen is dependent upon the user's monitor and page zoom settings.

How to give a textbox a fixed width of 17,5 cm?

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.

How do I determine the true pixel size of my Monitor in .NET?

I want to display an image at 'true size' in my application. For that I need to know the pixel size of the display.
I know windows display resolution is nominally 96dpi, but for my purposes I want a better guess. I understand this information may not always be available or accurate (e.g. older CRT displays), but I imagine with the prevelance of LCD displays that this should be possible!
Is there a way to get the pixel size of my display?
Is there a way to determine if the pixel size is accurate?
.NET API's preferred (I couldn't find them), but Win32 is OK too, I'm happy to P/Invoke.
For the display size you'll want Screen.PrimaryScreen.Bounds.Size (or Screen.GetBounds(myform)).
If you want the DPI, use the DpiX and DpiY properties of Graphics:
PointF dpi = PointF.Empty;
using(Graphics g = this.CreateGraphics()){
dpi.X = g.DpiX;
dpi.Y = g.DpiY;
}
Oh, wait! You wanted actual, hold a ruler up to the monitor and measure, size?! No. Not possible using any OS services. The OS doesn't know the actual dimensions of the monitor, or how the user has it calibrated. Some of this information is theoretically detectable, but it's not deterministic enough for the OS to use it reliably, so it doesn't.
As a work around, you can try a couple of things.
You can try to query the display string of the installed monitor device (I'm not sure how to do that) and see if you can parse out a sensible size out of that. For example, the monitor might be a "ValueBin E17p", and you might deduce that it's a 17" monitor from that. Of course, this display string is likely to be "Plug and Play Monitor". This scheme is pretty sketchy at best.
You could ask the user what size monitor they have. Maybe they'll know.
Once you know (or think you know) the monitor's diagonal size, you need to find its physical aspect ratio. Again, a couple of things:
Assume the current pixel aspect ratio matches the monitor's physical aspect ratio. This assumes that (A) the user has chosen a resolution that is ideal for their monitor, and that (B) the monitor has square pixels. I don't know of a current consumer-oriented computer monitor that doesn't have square pixels, but older ones did and newer ones might.
Ask the user. Maybe they'll know.
Once you know (or think you know) what the monitor's diagonal size and physical aspect ratio are, then you you can calculate it's physical width and height. A2 + B2 = C2, so a few calculations will give it to you good:
If you found out that it's a 17" monitor, and its current resolution is 1280 x 1024:
12802 + 10242 = 2686976
Sqrt(2686976) = 1639.1998047828092637409837247032
17" * 1280 / 1639.2 = 13.274768179599804782820888238165"
17" * 1024 / 1639.2 = 10.619814543679843826256710590532"
This puts the physical width at 13.27" and the physical height at 10.62". This makes the pixels 13.27" / 1280 = 10.62" / 1024 = 0.01037" or about 0.263 mm.
Of course, all of this is invalid if the user doesn't have a suitable resolution, the monitor has wacky non-square pixels, or it's an older analog monitor and the controls aren't adjusted properly for the display to fill the entire physical screen. Or worse, it could be a projector.
In the end, you may be best off performing a calibration step where you have the user actually hold a ruler up to the screen, and measure the size of something for you. You could:
Have the user click the mouse on any two points an inch (or a centimeter) apart.
Draw a box on the screen and have the user press the up and down arrows to adjust its height, and the left and right arrows to adjust its width, until the box is exactly one inch (or centimeter) square according to their ruler.
Draw a box on the screen and have the user tell you how many inches/centimeters it is in each dimension.
No matter what you do, don't expect your results to be 100% accurate. There are way too many factors at play for you (or the user) to get this exactly correct, every time.
Be aware that 96 dpi is usually pretty close to accurate. Modern pixels on non-projected screens all tend to be about 0.25 mm, give or take, so you usually end up with about 100 physical pixels per inch, give or take, if the monitor is set to its native resolution. (Of course, this is a huge generalization and does not apply to all monitors. Eee PCs, for example, have pixels about 0.19 mm in size, if I remember the specs correctly.)
sorry, you've got to P/Invoke for this information.
Here's the link that I utilized for it a while ago:
http://www.davidthielen.info/programming/2007/05/get_screen_dpi_.html
You can check by just manually calculating from your screen size
cos(45)*LCD_SCREEN_DIAGONAL_IN_INCHES/sqrt(HORZ_RES^2 + VERT_RES^2)
That would give you the pixel width in inches
GetDeviceCaps can be P/Invoke'd to get some figures, but I've never known the figures to be that trustworthy...
You may obtain the physical dimensions of the display using the EDID information stored in the registry. You can obtain the appropriate monitor's registry key using the EnumDisplayDevices windows API call.
Physical Dimensions to the Screen object:
TL;DR
WPF's True Size = Pixels * DPI Magnification
DPI Magnification:
Matrix dpiMagnification
= PresentationSource.FromVisual(MyUserControl).CompositionTarget.TransformToDevice;
double magnificationX = dpiMagnification.M11;
double magnificationY = dpiMagnification.M22;
Discussion
I had trouble solving this question still in 2020. Back when this question was asked/answered in 2009, .NET C# probably meant Windows Forms. But WPF is the de facto standard of the day...
By asking about "true size" you have probably already figured out that the operating system does some calculation with actual pixels (say 1366x768, which I understand is usual laptop resolutions) and the DPI (hard to find) in order to give a control's true size. And you are trying to make an app that scales to different monitors.
This DPI actual number seems to be hidden, but it has been normalized (converted to a percentage). Assume 100% = 96 DPI, just because the actual number does not matter anymore. People can easily increase the system-wide text size by going to Desktop on Windows 10 > right click > Display settings > section Scale and layout > change the percentage to magnify text and other elements.
You can find the pixels another way, and multiple/divide the pixel by the DPI percentage in order to get true size. For instance, I want to drag a UserControl around a canvas element of a WPF window with the mouse. The user control's pixel count and the mouse xy-coordinates were off by the normalized DPI. In order to keep the mouse moving at the same rate as the user control, I use:
double newXCoord = System.Windows.Forms.Cursor.Position.X;
double newYCoord = System.Windows.Forms.Cursor.Position.Y;
double deltaX = newXCoord - oldXCoord;
double deltaY = newYCoord - oldYCoord;
double magnificationX = 1;
double magnificationY = 1;
Matrix dpiMagnification
= PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice;
if (magnificationMatrix != null)
{
magnificationX = dpiMagnification.M11;
magnificationY = dpiMagnification.M22;
}
PixelsFromLeft += deltaX / m_magnificationX;
PixelsFromTop += deltaY / m_magnificationY;

Categories