Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Scaling bitmaps when DPI>96 1

Status
Not open for further replies.

HughLerwill

Programmer
Nov 22, 2004
1,818
GB
Dear all,

I am adjusting some of my software to accomodate use when screen resolution is set to a value greater than the normal 96 dpi in Windows display properties dialog - Settings tab - Advanced button - General tab

The code below prints a bitmap containing a company logo in the top right of a printed or previewed (PictureBox) page. The size of the bitmap image printed/ previwed is reduced with an increased screen dpi unless steps are taken.

Modifications made for increased dpi are detailed in the code comments.

The problem is that MS Paint which is typically used to create bitmaps does not give the option to select dpi when a file is created or record the dpi it was created with in the bitmap file header. Thus 1) the value of 96 dpi is assumed if the bitmap's PelsPerMeter property is set to zero and 2) I have to recommend that Logo files are created on a Windows system using a 96 dpi display property setting or 3) I have to recommend that Logo files are created with a program such as PaintShop Pro which allows specification of dpi and saves it in the bitmap.

Am I giving myself a hard time using bitmaps for the logos, and would other file formats be more suitable?

Function PrntCoLogo(Pdevice As Object, BitMapFile$) As Boolean

'does the company logo on reports
Dim PrntHeight!, PrntWidth!
Dim Prntx&
Dim pic As New StdPicture

If Len(Dir$(Path2LogoFiles$() & "\" & BitMapFile$)) Then

'if using Printer it must be initialized.
If Pdevice Is Printer Then Pdevice.Print " "

Set pic = LoadPicture(Path2LogoFiles$() & "\" & BitMapFile$)
'scalemode of StdPicture object is fixed Himetric
'pic.Scalemode does not work

'however all the work is done in pixels.
Pdevice.ScaleMode = vbPixels

'so convert himetric to pixels, and reduce image to half size to reduce jagginess

'next 2 lines modified to accomodate use of screen dpis greater than the standard 96
'PrntHeight = Pdevice.ScaleY(pic.Height / 2, vbHimetric, vbPixels) * GetWindowsDPI(0)
'PrntWidth = Pdevice.ScaleX(pic.Width / 2, vbHimetric, vbPixels) * GetWindowsDPI(1)

'GetWindowsDPI(n) gets the DPI setting in Windows display properties
'GetBitMapDpi gets the DPI setting from the bitmap header(if PelsPerMeter set to zero 96 dpi is assumed/ returned)
'args for both; ; (0) for Xdpi, (1) fpr Ydpi
PrntHeight = Pdevice.ScaleY(pic.Height / 2, vbHimetric, vbPixels) _
* GetWindowsDPI(0) / GetBitMapDpi(Path2LogoFiles$() & "\" & BitMapFile$, 0)
PrntWidth = Pdevice.ScaleX(pic.Width / 2, vbHimetric, vbPixels) _
* GetWindowsDPI(1) / GetBitMapDpi(Path2LogoFiles$() & "\" & BitMapFile$, 1)

'position picture to the extreme top right of the page
Prntx = Pdevice.ScaleWidth - PrntWidth - 1

On Error Resume Next
Pdevice.PaintPicture pic, Prntx, 0, PrntWidth, PrntHeight

If Err Then
MsgBox "Error " & Err & " printing graphics based header" & ret$ & "Text based header printed", vbInformation
Else
PrntCoLogo = True
End If
On Error GoTo 0

Set pic = Nothing

End If

End Function

regards Hugh
 
I think you are making more of this than you need to ...

If you set the scalemode of PDevice to a device independant mode (e.g twips or Inches) then you can choose exactly how big you want the logo to appear without worrying at all about DPI settings, as all the necessary scaling will be taken care of for you (although obviously you'll get distortions if the bitmap is scaled too much)
 
strongm,

I think I see where you are coming from and think it would work if the final logo to be printed was always the same size; however it is not, the user may use a logo file which covers the entire printed page if for example he wants graphics to appear at the bottom of it or at the far left, otherwise he may use a smaller one.
I suppose I could insist that all logo files were sized to cover the entire page though and then scale them to fit the fixed dimension of the page as I think you are suggesting.
I am thinking though that I would rather use a graphics file format that would reproduce a fixed size image not affected but the host computer's dpi setting. Bitmaps would be fine if I could rely on their PelsPerMeter property being set.

Thanks Hugh
 
>Bitmaps would be fine if I could rely on their PelsPerMeter property being set

Why do you think this, given that the x and y PelsPerMeter setting has zero effect on the actual resolution of the stored bitmap? Essentially they are just properties that identify the ideal target display resolution, not the resolution of the stored image; Windows generally ignores the value, and displays the bitmap at the resolution of the target device.



 
Strongm,

<Why do you think this>

Because my modified code works just how I'd like it to when the bitmap's PelsPerMeter property is used.

<Windows generally ignores the value, and displays the bitmap at the resolution of the target device.>

So you create a bitmap under MS Paint on a system using 144dpi, which is 3*3 inches; when transfered to a 96 dpi system it is reproduced at 4.5*4.5 inches.

regards Hugh,
 
All I'm saying is that if you know the required size of the logo is (e.g.) 3*3 inches then it seems to me that it would be much easier to do this:
Code:
[blue][green]' TargetRender should be Form, Picturebox or Printer[/green]
Private Sub PaintIt(srcPic As StdPicture, targetRender As Object, width As Single, height As Single, Optional picscale As ScaleModeConstants = vbTwips, Optional left As Single = 0, Optional top As Single = 0) '(srcPic, targetpic, 2,3, vbinches, 0,0)
    targetRender.ScaleMode = vbMillimeters
    targetRender.PaintPicture srcPic, ScaleX(left, picscale, vbMillimeters), ScaleY(top, picscale, vbMillimeters), ScaleX(width, picscale, vbMillimeters), ScaleY(height, picscale, vbMillimeters), 0, 0, srcPic.width / 100, srcPic.height / 100 [green]' himetric is 100 times bigger than vbMillimeters so we jut need to scale things here[/green]
End Sub[/blue]
which will render the logo as 3*3 inches 2 inches acroos and 3 inches down the page when called like

[tt]PaintIt mypicture, Printer, 3, 3, vbInches , 2, 3[/tt]

no matter what the source or target device resolutions.

(If you really need the BMP DPI because you don't know the logo size, it is worth knowing that MS Paint works at 113 DPI)
 
Stongm,

Sorry I thought I had made it clear a couple of messages ago that the logo can vary in size, reference to 3*3 changing into 4.5*4.5 was just an example of the effect when moving from a 144 dpi system to one using 96dpi.

Thanks for your code; especially the note re Himetric being 100 * vbmillimeters which I had never realised before.

Tried playing around using JPEG files instead of bitmaps yesterday and found the situation does not really change. However if I can reliably get the creation dpi from a JPEG I may have it cracked.
So do JPEGs always contain dpi specs or are these usually left blank too, and how can I retrieve those numbers from a JPEG. I have tried playing around with the JPEG header but no luck so far.

regards

 
>clear ... [] ... the logo can vary in size

Sure - but I made the assumption (now seen to be incorrect) that at least the designer might know the size of the logo that they designed.

>So do JPEGs always contain dpi specs
Um - no ...

> how can I retrieve those numbers from a JPEG.
Code:
[blue]Option Explicit
Private Type BasicJPGHeader
    SOI As Integer
    Marker As Integer
    length As Integer
    identifier As String * 5
    version(1 To 2) As Byte
    units As Byte
    structurepadding As Byte
    xdensity As Integer
    ydensity As Integer
    xthumbnail As Byte
    ythumbnail As Byte
End Type

Private Sub Command1_Click()
    Dim myjpg As BasicJPGHeader
    Dim hfile As Long
    Dim strUnits As String
    
    hfile = FreeFile
    
    Open "c:\1inch.jpg" For Binary As hfile
    Get #hfile, , myjpg
    Close hfile
    Select Case myjpg.units
        Case 0
            strUnits = "aspect ratio"
        Case 1
            strUnits = "dots per inch"
        Case 2
            strUnits = "dots per cm"
    End Select
    MsgBox "x " & strUnits & ": " & myjpg.xdensity & vbCrLf & "y " & strUnits & ": " & myjpg.ydensity
End Sub[/blue]
 
Strongm,

<<So do JPEGs always contain dpi specs
Um - no ...>>
But it seems (with the help of your last code) that MS Paint does include it (them) in JPEGs saved using it. Could be I have a solution there.
I'd omitted to include the structurepadding element in the UDT I was previously using to read the JPEG header.

Thank you for all your help, it is much appreciated.

regards Hugh


 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top