font scaling and WYSIWYG

E

Eric Eggermann

Hello all,
I'm building an app that lays out and prints flash cards. Now the card might
be any size, but when the user is working on the card, I draw the preview
isotropically, as large as possible. The user specifies a font size for the
document, but I need to scale this for the preview.

The scaling code I have is very close but not right. I can only notice that
it's wrong occasionally when I have a piece of text that wraps, and the wrap
occurs at a different place in the printed output than in the preview. I
need to make my preview jive with the output. One more thing, the preview
seems to always be on the small side.
Pseudo code is like this
Convert the size of the actual card from hundreths of an inch to pixels

Divide the width and height of the preview rectangle by their respective
values in the size derived above, and use the lesser of those
two values as the scale.

Determine the scaled font size by multiplying the user selected font
size by the scale factor determined above, and create a new font with
this new size, and draw the text.


Here's the relevant code mashed into a straight line.

//Get the size of the card in hundreths of an inch
SizeF cardUnitSize = PaperType.CardSizein;
if(isLandscape)
{
//switch around the cardUnitSize values
float temp;
temp = cardUnitSize.Height;
cardUnitSize.Height = cardUnitSize.Width;
cardUnitSize.Width = temp;
}
SizeF screenSize = new SizeF(cardUnitSize.Width / 100 * grfx.DpiX,
cardUnitSize.Height / 100 * grfx.DpiY);

float scale = Math.Min(this.Parent.PreviewRect.Size.Width /
cardUnitSize.Width,
this.Parent.PreviewRect.Size.Height / cardUnitSize.Height);
float scaleSize = font.SizeInPoints * scale;
textFont = new Font(font.FontFamily,
scaleSize,
font.Style);
grfx.DrawString(strContent, textFont, txtBrush, rectDest, strFmt);

I've also mucked about with the PageScale, and ScaleTransform properties,
and managed to do no better. Any ideas?

TIA
Eric
 
B

Bob Powell [MVP]

You're working too hard...

The graphics transform will scale the page for you any way you like. Just
set-up the transform before you draw the flash card at its normal size. The
application after my signature shows how a drawing routine that always uses
a 24 point font size can be scaled to any size of page.

--
Bob Powell [MVP]
C#, System.Drawing

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdiplus_faq.htm

Read my Blog at http://bobpowelldotnet.blogspot.com

----------------------------------------------------------------------------
----
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace fontscaling
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//

SetStyle(ControlStyles.ResizeRedraw |
ControlStyles.DoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer |
ControlStyles.UserPaint, true);
}

protected void PaintStuff(Graphics g)
{
//Paints everything at 1:1 scale
Font fn=new Font("Verdana",24f);
g.FillRectangle(Brushes.White,0,0,800,600); //The page is always 800
by 600.
g.FillEllipse(Brushes.Blue,50,50,200,200); // draw a circle
g.DrawString("This is some text in 24 point
Verdana",fn,Brushes.Black,10,300,StringFormat.GenericTypographic);
fn.Dispose();
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.BackColor = System.Drawing.SystemColors.ControlDark;
this.ClientSize = new System.Drawing.Size(376, 286);
this.Name = "Form1";
this.Text = "Form1";

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

protected override void OnPaint(PaintEventArgs e)
{
//calculate the scaling...
//we know the page is 800*600
float ratio=Math.Min(this.ClientSize.Width/800f,
this.ClientSize.Height/600f);
Matrix mx=new Matrix(ratio,0,0,ratio,0,0);
e.Graphics.Transform=mx;
PaintStuff(e.Graphics);
base.OnPaint (e);
}

}
}
 
E

Eric Eggermann

Bob Powell said:
You're working too hard...

The graphics transform will scale the page for you any way you like. Just
set-up the transform before you draw the flash card at its normal size. The
application after my signature shows how a drawing routine that always uses
a 24 point font size can be scaled to any size of page.

Thanks Bob, I'll have a good look at that code in a bit, but, the reason I
didn't go with the transform is that I need to keep track of which bit of
the screen applies to which part of the card. To a limited extent, the user
can click on text bits and drag them around. That part of the UI is very
primitive, but if If use the transform, to draw the bits on the screen, can
I figure out which bit the user is clicking? When I draw part of the card
for a preview, I need to set a region object that I can compare click events
against later. Can that be done?

Eric
 
B

Bob Powell [MVP]

You can backtrack mouse positions from any transform by inverting the
transform and using the resulting matrix to transform the current mouse
coordinates. The management of mouse clicks etc is done in the normal way
but the mouse coords are scaled back to the virtual page.

Well Formed has an article containing a complete canvas class implementation
that does all this. http://www.bobpowell.net/october2003.htm

Send me your e-mail address. Remove the spamkiller from my email to mail me.

--
Bob Powell [MVP]
C#, System.Drawing

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdiplus_faq.htm

Read my Blog at http://bobpowelldotnet.blogspot.com
 
E

Eric Eggermann

Thanks again Bob.
I took your advice below and altered my program to make use of it. I
used ScaleTransform and TranslateTransform to scale and place my card
preview, and I wound up with exactly the same results. The preview does not
jive with printed output under certain circumstances.

I use a document object and a print preview control to preview a sheet of
cards, and that matches up with the printed output, so far as I've tested,
so I looked for differences between the two procs that print a preview of a
card, and the page itself. Something must be there, but I cannot find it.

The preview and print code is different though. But this is because when I
draw a preview, I'm drawing one side of a card, centered in some area of the
screen, and the user can interact with some parts of it. When I print, the
location of the card depends on how many other cards are before it in the
collection, and what sort of paper we are printing on. So, when drawing a
preview, I leave everything up to the card face, and even pass in a
reference to the control it's being painted on. When printing, or previewing
a page of cards, an object at a higher level decides the rectangle that the
card face prints itself on. But I've found through testing that both bits of
code are working on the same exact rectangle, one of which gets scaled, (the
preview) and one of which is not (the print job). In other words, Two
different bits of code do the preview and the print, but both are definitely
dealing with the same rectangle when I call Graphics.Draw[something].

That was really wordy, but if you or anybody else has an idea as to what I
might try, look at, read, or test next, it would be greatly appreciated.

Eric
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top