Solved

Help centering diagonal Watermark - is not consistent  !!

Posted on 2004-10-01
23
329 Views
Last Modified: 2010-05-18
I've created some basic code that creates information along the edges of a page.

It also creates a diagonal 'watermark' across the face of the page.

I'm having trouble keeping the watermark centered when I change the watermark text.
For example, if I use "watermark", the text is positioned differently than if I use "NOT FOR DISTRIBUTION" - and neither are centered as they should be.

My code calculates the font size based on the text length.

Can someone help me figure out why my centering code does not work properly???

I need to be able to use any font, any text and still have the watermark be
centered on the digonal.

Please test your code - I will!

I think that the Printer.TextHeight and Printer.TextWidth methods return inaccurate info...
I've also tried GetTextExtentPoint32 with the same results.

Click this link do download my sample code...
http://whoit.home.comcast.net/TESTrotate.zip

Or contact me by email:
<email address removed - Bingie EE PE>
0
Comment
Question by:wehoit
  • 10
  • 5
  • 2
  • +3
23 Comments
 
LVL 32

Expert Comment

by:Erick37
ID: 12200000
I have not seen the algorithm yet, but a quick question or two:

If the text is not rotated, does it center correctly?

If the text is rotated, do you adjust it's position according to the sine of the angle?
0
 
LVL 1

Author Comment

by:wehoit
ID: 12200138
Erick -

1) Yes

2) Yes - and the Cosine

Check out the code - it's very short and clear, plus it's easy to run and test.
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12200462
Well I ran your code.

It output "NOT FOR PRODUCTION" on a diagonal across an 8.5x11 size paper.
Running a ruler diagonally across the paper, from corner to corner, lines up with the tops of the letters.
I am assuming you want the alignment through the center of the text?

My printer is an HP Laserjet 5P
0
 
LVL 1

Author Comment

by:wehoit
ID: 12200628
I'm looking for centering - left/right and top bottom, along the diagonal, with the alignment through the center.

It should work for any typeface (or certainly the most common) , upper/lower/mixed case, etc....

I'd like to continue to calculate the font size dynamically so that it fills the available diagonal space inside the margins.
It should not conflict with the border text, regardless of how many lines there are on each page edge.

I have Acrobat, so I typically print to a PDF file for testing - saves a lot of paper if you can do it.

Please feel free to ask any more questions....
0
 
LVL 1

Author Comment

by:wehoit
ID: 12216909
Is anyone working on this?

'Cause if not, I'll delete it and re-submit.

I'm raising the point value this time.
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12216997
I could not get it working correctly in the time I had to look at it.  I believe the problem lies in calculating the hypotenuse according to the height of the text.  As the textheight increases the triangle defined by (topleft margin) - (currentx currenty) - (the intersection of hyp and the top of page) decreases.

As the height increases:
1) the hypotenuse should decrease
2) CurrentX should remain at the left border
3) CurrentY should decrease

That's as far as I got, no working algorithms.  Feel free to delete and resubmit to the top of the stack.

Good Luck!

Eric.

0
 
LVL 1

Expert Comment

by:Lycaon
ID: 12217551
Hold the question open a bit longer.  Let me take a crack at it. :p
0
 
LVL 1

Author Comment

by:wehoit
ID: 12217620
I've already asked Support to allow me to close and re-post it, but if they do, I'll let you know.

By all means, have at it!
0
 
LVL 1

Expert Comment

by:Lycaon
ID: 12218463
Bleh, I know how to do it in my head, but I just don't have the math skill to code it.

Good luck to anyone who does get it. :)
0
 
LVL 1

Author Comment

by:wehoit
ID: 12218590
Why don't you try explaining it to me - perhaps I can write the math.

Just so you know, this is what I do now:

1) Calculate the angle from corner to corner
2) Calculate the length of the diagonal (hypotenuse) from corner to corner.
3) Calculate the font size based on using TextWidth until it equals or exceeds the hypotenuse.
4) Calculate the left position by getting the hypotenuse minus the TextWidth, then finding the length of the base of the triangle formed by the 'new' hypotenuse and a horizontal and vertical line. Add this to the left margin.
5) Calculate the vertical (y) position using the same method as step 4.

Unfortunately, I think that TextWidth/TextHeight are not returning correct values...
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 7

Expert Comment

by:Burbble
ID: 12232913
Arg. I've been working on this for about an hour now, but no success. I'm still a little unsure about what you are calculating at certain points, but I don't think the math is the problem. Here's what I've come up with, maybe it'll spark an idea in someone else's mind (these are referencing the setBanners Sub):

- Printer.FontSize is not being set to the proper values when you are calculating the length of the page's hypotenuse. It seems to always be off by a multiple of 0.08, and is also returning a non-integer when you set rotobj.Font.

- pageWidth and pageHeight are each approximately 0.5 less than the actual dimensions of the paper size (meaning, 0.25" margins all around are automatically being factored in). The actual values of the two variables are not exactly 8.0" and 10.5" for some reason -- they are both off by a few hundredths.

- An observation: The phrase in all capital letters (i.e. "NOT FOR PRODUCTION") is centered properly, but the phrases in lower-case or mixed letters (i.e. "watermark" or "Not For Production") are not centered properly.

It's a conundrum, it is... Lastly,

>> Unfortunately, I think that TextWidth/TextHeight are not returning correct values...

I don't understand what these are supposed to be returning. Is it the height and width of the text at 0 degrees, returned in pixels? Or is it the height and width of the rotated text (meaning, the lengths of the tall vertical leg and the short horizontal leg of the triangle, respectively)?
Sorry if that seems like an obvious question; I understand the actual mathematics involved (aka "triangle stuff"), but I don't understand very well how Visual Basic handles the Printer object in this regard... lol :)

-Burbble
0
 
LVL 26

Expert Comment

by:EDDYKT
ID: 12236400
Have you tried to set printer.scalemode, this field is important
0
 
LVL 1

Author Comment

by:wehoit
ID: 12236938
Burbble -

I've noticed the incorrect values that you  pointed out, but I think they are irrelevant. If they're always off by the same amount (which they are) then the math should still place the watermark at the same place every time - which, of course, it doesn't.

As for TextWidth/Height - it returns the width or height of the text based on 0 degrees. It doesn't take into account any rotation. Besides, I use it before the rotation.
Also, they return units based on the ScaleMode setting of the device. In this case, the printer is Twips by default.

Which also refers to the comment by EDDYKT - I don't change the ScaleMode - it's twips and I work with twips for all the other calculations.

Yes, it is incredibly frustrating!!! I've been tinkering with this for DAYS, which leads me to believe that the math is basically sound, but the TextWidth/Height is wrong.
I've also tried the API GetTextExtentPoint32 which returns different values but still doesn;t solve the problem...

I wanted to change the point value of this question to 750 but I'm not allowed to.

I really need a solution to this problem, and I know it can be solved...
0
 
LVL 26

Expert Comment

by:EDDYKT
ID: 12237229
Just a thought, instead of using arial can you use courier which is fixed size for all character


also use form to return textwidth instead of using printer object and see what is the different
0
 
LVL 32

Accepted Solution

by:
Erick37 earned 200 total points
ID: 12241212
Here is as far as I got.  It works better, but not perfect.  The textwidth seems to be shorter than I calculated it to be, not sure why.  Anyway give it a try.  I only modified the setBanners function, so here it is...

Private Sub setBanners(Optional page As Integer)

Dim pageWidth As Double, pageHeight As Double, pi As Double
Dim rotobj As New rotator, txHite As Integer
Dim banner As String
Dim twip As Integer, halftwip As Integer

twip = 1440
halftwip = 720
pi = 3.14159

'get the current page size
pageWidth = ScaleX(GetDeviceCaps(Printer.hdc, HORZSIZE), vbMillimeters, vbInches)
pageHeight = ScaleY(GetDeviceCaps(Printer.hdc, VERTSIZE), vbMillimeters, vbInches)

Debug.Print "Width, Height", pageWidth, pageHeight


txHite = Printer.TextHeight("Tj") 'sample text for calculating height only
Set rotobj.Device = Printer
rotobj.Font = tfont

'do the top/bottom banners
rotobj.Angle = 0 'same for all top & bottom

'tops
Printer.CurrentY = 0  'same for all Top

'top left
Printer.CurrentX = 0
banner = iso.tleft
GoSub handleHorz

'top center
Printer.CurrentX = (pageWidth * halftwip) - (Printer.TextWidth(iso.tcenter) * halftwip)
banner = iso.tcenter
GoSub handleHorz

'top right
Printer.CurrentX = (pageWidth * twip) - Printer.TextWidth(iso.tright)
banner = iso.tright
GoSub handleHorz

' Bottom labels
Printer.CurrentY = ((pageHeight - margs.bottom) * twip)

'bottom left
Printer.CurrentX = 0
banner = iso.bleft
GoSub handleHorz

'bottom center
Printer.CurrentX = (pageWidth * halftwip) - (Printer.TextWidth(iso.bcenter) * halftwip)
banner = iso.bcenter
GoSub handleHorz

'bottom right
Printer.CurrentX = (pageWidth * twip) - Printer.TextWidth(iso.bright)
banner = iso.bright
GoSub handleHorz

'Do the side banners
rotobj.Angle = 90 'same for all (Could make this a param in VueLogic)

'lefts
Printer.CurrentX = 0

'leftbottom
Printer.CurrentY = ((pageHeight - margs.bottom) * twip) - txHite
banner = iso.lbottom
GoSub handleVert

'leftcenter
Printer.CurrentY = (pageHeight * halftwip) + (Printer.TextWidth(iso.lcenter) * halftwip)
banner = iso.lcenter
GoSub handleVert

'lefttop
Printer.CurrentY = (margs.top * twip) + Printer.TextWidth(iso.ltop)
banner = iso.ltop
GoSub handleVert

'rights
Printer.CurrentX = (pageWidth - margs.right) * twip

'rightbottom
Printer.CurrentY = ((pageHeight - margs.bottom) * twip) - txHite
banner = iso.rbottom
GoSub handleVert

'rightcenter
Printer.CurrentY = (pageHeight * halftwip) + (Printer.TextWidth(iso.rcenter) * half)
banner = iso.rcenter
GoSub handleVert

'righttop
Printer.CurrentY = (margs.top * twip) + Printer.TextWidth(iso.rtop)
banner = iso.rtop
GoSub handleVert

'Watermark
Dim aRad As Double

'//complimentary angle
Dim aCompRad As Double

Dim twidth As Long '// changed to long!
Dim xHyp As Double, nHyp As Double

'// need a temp holder to calc hypotenuse, etc.
Dim lCurrY As Long
Dim lCurrX As Long

'rotate watermark diagonally
'work in twips


'// need to work on this...
'find the diagonal hypotenuse
xHyp = Sqr(((pageWidth * twip) ^ 2) + ((pageHeight * twip) ^ 2))
'//

'find the diagonal angle
aRad = Atn(pageHeight / pageWidth)

aCompRad = Atn(pageWidth / pageHeight)

rotobj.Angle = aRad * (180 / pi)

'find the font size for the diagonal
Printer.FontSize = 2

Do
    Printer.FontSize = Printer.FontSize + 2
   
    twidth = Printer.TextWidth(iso.wmark)
   
    '// current y changes as text height increases
    lCurrY = (pageHeight * twip) - (margs.bottom * twip) - (Cos(aRad) * Printer.TextHeight("Xyj"))
   
    '// Need to recalc the hyp based on text height
    '//xhyp = (currenty - top margin) / (cosine(complimentary angle))
    If Cos(aRad) < 0.01 Then 'Prevent overflow
        xHyp = (pageWidth - margs.left - margs.right) * twip
    Else
        xHyp = (lCurrY - (margs.top * twip)) / Cos(aCompRad)
    End If
   
    '//Debug.Print "HYP = ", xHyp, "twidth = ", twidth, "lcurry = ", lCurrY, "Size = ", Printer.FontSize
   
Loop Until twidth > xHyp

Debug.Print "printer.ScaleMode", Printer.ScaleMode

Printer.FontSize = Printer.FontSize - 2

'///TEST
'//Printer.FontSize = 64

rotobj.Font = Printer.FontSize & ",Arial,0,0,400,0,0,0,0,3, 2, 1, 34"

Debug.Print rotobj.Font

''''find new hyp length by subtracting the width of the text / 2
''''this sould be the space left over along the diagonal after subtracting the text width
'''nHyp = (xHyp - Printer.TextWidth(iso.wmark)) * 0.5

''''width/height of available area
'''wid = (pageWidth - margs.left - margs.right) * twip
'''hite = (pageHeight - margs.top - margs.bottom) * twip

'''horizontal center should be
'''width of left margin + length of triangle base from hypotenuse
'''Printer.CurrentX = (margs.left * twip) + (nHyp * Cos(aRad))

'//
'//
'// Current x should be 0 + left margin
lCurrX = margs.left * twip
'//

''''vertical center should be
''''page bottom - bottom margin - length of triangle side from hypotenuse - half the text height
''''Printer.CurrentY = (pageHeight * twip) - (margs.bottom * twip) - (nHyp * Sin(aRad)) - (Printer.TextHeight(iso.wmark) * 0.5)

'//
'//
'// Current y should be page height - bottom margin - (cosine(angle) * text height)
lCurrY = (pageHeight * twip) - (margs.bottom * twip) - (Cos(aRad) * Printer.TextHeight("Xyj"))
'///

'// draw a line around what we think the text is
Dim tmpX As Long, tmpY As Long, lTxtH As Long, lTxtW As Long
Printer.CurrentX = lCurrX
Printer.CurrentY = lCurrY
lTxtH = Printer.TextHeight(iso.wmark)
lTxtW = Printer.TextWidth(iso.wmark)
tmpX = lCurrX + (Cos(aRad) * lTxtW)
tmpY = lCurrY - (Sin(aRad) * lTxtW)
Printer.Line -(tmpX, tmpY)
tmpY = Printer.CurrentY
tmpX = Printer.CurrentX
Printer.Line -(tmpX + Sin(aRad) * lTxtH, tmpY + Cos(aRad) * lTxtH)
tmpY = Printer.CurrentY
tmpX = Printer.CurrentX
Printer.Line -(tmpX - (Cos(aRad) * lTxtW), tmpY + (Sin(aRad) * lTxtW))
tmpY = Printer.CurrentY
tmpX = Printer.CurrentX
Printer.Line -(lCurrX, lCurrY)
'//end draw text outline

'// Draw the margins
tmpX = margs.left * twip
tmpY = margs.top * twip
Printer.CurrentX = tmpX
Printer.CurrentY = tmpY
Printer.Line -((pageWidth - margs.right) * twip, tmpY)
tmpX = Printer.CurrentX
tmpY = Printer.CurrentY
Printer.Line -(tmpX, (pageHeight - margs.bottom) * twip)
tmpX = Printer.CurrentX
tmpY = Printer.CurrentY
Printer.Line -(margs.left * twip, tmpY)
tmpX = Printer.CurrentX
tmpY = Printer.CurrentY
Printer.Line -(tmpX, margs.top * twip)
Debug.Print "margs", margs.top, margs.right, margs.bottom, margs.left
'// end drawing margins

'///
Printer.CurrentX = lCurrX
Printer.CurrentY = lCurrY
'//
'//


rotobj.PrintText iso.wmark
Exit Sub

handleHorz:
    chunks = Split(banner, vbCrLf)
    oldY = Printer.CurrentY
    For i = 0 To UBound(chunks)
        rotobj.PrintText CStr(chunks(i))
        Printer.CurrentY = Printer.CurrentY + txHite
    Next i
    Printer.CurrentY = oldY
    Return
   
handleVert:
    chunks = Split(banner, vbCrLf)
    oldX = Printer.CurrentX
    For i = 0 To UBound(chunks)
        rotobj.PrintText CStr(chunks(i))
        Printer.CurrentX = Printer.CurrentX + txHite
    Next i
    Printer.CurrentX = oldX
    Return
End Sub
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12241339
As a side note.  Please use Option Explicit as the first line in all modules.  This forces you to Dim all your variables.  I ran across a couple undeclared variables in your code ("half" for example which I believe should be called "halftwip").  This kind of error is very difficult to trace because the compiler does not complain, and just sets the value to 0.
0
 
LVL 1

Author Comment

by:wehoit
ID: 12241699
Erick -

Your code is consistent, but I'm looking to get the watermark centered. Yours is always in the lower-left corner.
Also, it seems as though the biggest change you make is when you calculate the font size - it now comes out smaller than mine - why did you this?

The actual code for positioning the text (setting CurrentX and CurrentY) is nearly identical to my original code.

I've been tinkering with it still, and have found that TextHeight includes not only the height of the actual text, but also the imposed line spacing. My testing came up with a value of 0.155 which can account for this spacing. (Your example shows this line spacing when you draw the box around the text area.)
When I incorporate this into my earlier code I get this for the CurrentY:
Printer.CurrentY=(pageHeight * twip) - (margs.bottom * twip) - (Printer.TextHeight(iso.wmark) * 0.155) - (Printer.TextHeight(iso.wmark) * half)
This is more accurate for the vertical centering although it is still not completely accurate.

Regarding the TextWidth, it seems to calculate additional space based on the text kerning and the fact that it's a proportional font (I can't use a fixed-width font like EDDYKT suggested 'cause I need to give the user the option of selecting any font...) So, for example, if you don't use the Rotate method ans simply try to left-align the text at 0, you'll see what I mean....

As for "half" - that's definitely my fault - I removed the lines defining and setting the var - it's supposed to be "half=0.5" - sorry.
Halftwip is something else. If you notice, when you changed "half" to "halftwip", the centered text around the edges disappeared...
0
 
LVL 1

Author Comment

by:wehoit
ID: 12266590
All -

I've been working on this and have come very close to solving it.
I've updated the sample code at this link:
http://whoit.home.comcast.net/TESTrotate.zip

I'd still like to get it working 100%.


0
 
LVL 8

Expert Comment

by:tonsofpcs
ID: 12358786
wehoit: I do not have a printer available, so I cannot test the code, and hence am not looking at it, but can you offset the text vertically by [height/2] before rotating it? This will align it at the center, and make it seem more of in-the-same-spot each time.  
Also, if you change the font to a fixed-pitch font, and try two different strings of the same character length, do they show up in the same place?
0
 
LVL 1

Author Comment

by:wehoit
ID: 12359087
tonsofpcs -

First - be aware that I wanted to reduce the point value - mainly to Erick 200 pts since no one else really came close.

Also, be aware that I have mainly solved it my self and have uploaded newer test code.

I have offset the text before rotation, by several methods. You'll have to look at the code for the current solution as it's fairly complex.

As for Fixed -width fonts, they have a tendency to look worse and still not be positioned any better than variable-width fonts.

If someone wants to take my uploaded code and make it work 100%, I'll split the points with you and Erick.
0
 
LVL 1

Author Comment

by:wehoit
ID: 12393411
While not a complete answer, it did help point me in the right direction to *mostly* solve this myself.

Thanks for the effort.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

If you have ever used Microsoft Word then you know that it has a good spell checker and it may have occurred to you that the ability to check spelling might be a nice piece of functionality to add to certain applications of yours. Well the code that…
I was working on a PowerPoint add-in the other day and a client asked me "can you implement a feature which processes a chart when it's pasted into a slide from another deck?". It got me wondering how to hook into built-in ribbon events in Office.
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now