Home All Groups Group Topic Archive Search About

GDI+ and resizing a PictureBox

Author
15 Aug 2010 6:39 PM
Nobody
I am using GDI+ in one of my VB6 apps(mainly for anti aliasing support). It
works fine, but when I create the Graphics object, which takes a PictureBox
hDC. It never draws outside the PictureBox original size if I make it bigger
later, as if the Graphics object gets the hDC size only when it's created,
and truncates any drawing to that. Is there a way to tell the Graphics
object the new width and height?

Also, hDC remains the same throughout the life of the control, except when
you make the control bigger and AutoRedraw=True(because VB needs to create a
bigger bitmap). When AutoRedraw=False, hDC property never changes when the
PictureBox is resized(Whether bigger or smaller).

So is there away to tell the Graphics object that the hDC has changed?

In reality, I have to use double buffering, and the only method I found is
to recreate the Graphics object. I hate to recreate the Graphics object each
time while the user is resizing the form unless I have to.

Below is sample code that demonstrates the problem. To try it, add a
PictureBox, and 2 CommandButtons to Form1, then paste the following code.
Run the project, then click on "Draw 1st Line", followed by "Draw 2nd Line".
The second line should be larger and go to the other corner of the
PictureBox, but it's truncated at the original size.

API declarations came from the following source:

http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=37541&lngWId=1

There is a Type Library version at this location(You don't need it for the
sample below to work):

http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=42861&lngWId=1

In reality, I am using the type library version. I believe that VB only
takes from it what I actually used, and EXE size would be smaller, plus I
don't need to include the TLB or register it when distributing the
application. The API declaration version is 2644 lines long!

Option Explicit

Private Type GdiplusStartupInput
   GdiplusVersion As Long              ' Must be 1 for GDI+ v1.0, the
current
                                       ' version as of this writing.
   DebugEventCallback As Long          ' Ignored on free builds
   SuppressBackgroundThread As Long    ' FALSE unless you're prepared to
call
                                       ' the hook/unhook functions properly
   SuppressExternalCodecs As Long      ' FALSE unless you want GDI+ only to
                                       ' use its internal image codecs.
End Type

' NOTE: Enums evaluate to a Long
Public Enum GpStatus   ' aka Status
   Ok = 0
   GenericError = 1
   InvalidParameter = 2
   OutOfMemory = 3
   ObjectBusy = 4
   InsufficientBuffer = 5
   NotImplemented = 6
   Win32Error = 7
   WrongState = 8
   Aborted = 9
   FileNotFound = 10
   ValueOverflow = 11
   AccessDenied = 12
   UnknownImageFormat = 13
   FontFamilyNotFound = 14
   FontStyleNotFound = 15
   NotTrueTypeFont = 16
   UnsupportedGdiplusVersion = 17
   GdiplusNotInitialized = 18
   PropertyNotFound = 19
   PropertyNotSupported = 20
End Enum

' Quality mode constants
Public Enum QualityMode
   QualityModeInvalid = -1
   QualityModeDefault = 0
   QualityModeLow = 1       ' Best performance
   QualityModeHigh = 2      ' Best rendering quality
End Enum

Private Enum SmoothingMode
   SmoothingModeInvalid = QualityModeInvalid
   SmoothingModeDefault = QualityModeDefault
   SmoothingModeHighSpeed = QualityModeLow
   SmoothingModeHighQuality = QualityModeHigh
   SmoothingModeNone
   SmoothingModeAntiAlias
End Enum

Private Enum FillMode
   FillModeAlternate        ' 0
   FillModeWinding           ' 1
End Enum

Private Enum GpUnit  ' aka Unit
   UnitWorld      ' 0 -- World coordinate (non-physical unit)
   UnitDisplay    ' 1 -- Variable -- for PageTransform only
   UnitPixel      ' 2 -- Each unit is one device pixel.
   UnitPoint      ' 3 -- Each unit is a printer's point, or 1/72 inch.
   UnitInch       ' 4 -- Each unit is 1 inch.
   UnitDocument   ' 5 -- Each unit is 1/300 inch.
   UnitMillimeter ' 6 -- Each unit is 1 millimeter.
End Enum

Private Declare Function GdiplusStartup Lib "gdiplus" (token As Long, _
    inputbuf As GdiplusStartupInput, _
    Optional ByVal outputbuf As Long = 0) As GpStatus
Private Declare Sub GdiplusShutdown Lib "gdiplus" (ByVal token As Long)
Private Declare Function GdipCreateFromHDC Lib "gdiplus" ( _
    ByVal hdc As Long, graphics As Long) As GpStatus
Private Declare Function GdipSetSmoothingMode Lib "gdiplus" ( _
    ByVal graphics As Long, ByVal SmoothingMd As SmoothingMode) As GpStatus
Private Declare Function GdipCreatePen1 Lib "gdiplus" ( _
    ByVal color As Long, ByVal Width As Single, ByVal unit As GpUnit, _
    pen As Long) As GpStatus
Private Declare Function GdipDrawLineI Lib "gdiplus" ( _
    ByVal graphics As Long, ByVal pen As Long, ByVal x1 As Long, _
    ByVal y1 As Long, ByVal x2 As Long, ByVal y2 As Long) As GpStatus
Private Declare Function GdipDeletePen Lib "gdiplus" ( _
    ByVal pen As Long) As GpStatus
Private Declare Function GdipDeleteGraphics Lib "gdiplus" ( _
    ByVal graphics As Long) As GpStatus

Private Const WM_CLOSE = &H10
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" ( _
    ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
    lParam As Any) As Long

Private GDIpLoaded      As Boolean
Private token           As Long
Private graphics        As Long
Private pen             As Long

Private Sub Form_Load()
    Dim GpInput          As GdiplusStartupInput

    Me.ScaleMode = vbPixels
    Picture1.ScaleMode = vbPixels
    Me.Width = 600 * Screen.TwipsPerPixelX
    Me.Height = 300 * Screen.TwipsPerPixelY
    Picture1.Move 10, 10, 100, 100
    Command1.Move Me.ScaleWidth - 100, 10, 90, 30
    Command2.Move Me.ScaleWidth - 100, 50, 90, 30
    Command1.Caption = "Draw 1st Line"
    Command2.Caption = "Draw 2nd Line"

    ' Load the GDI+ Dll
    GpInput.GdiplusVersion = 1
    If GdiplusStartup(token, GpInput) <> Ok Then
        MsgBox "Error loading GDI+!", vbCritical
        PostMessage hWnd, WM_CLOSE, 0, ByVal 0&
        Exit Sub
    End If

    GDIpLoaded = True

    ' Initializations

    ' Initialize the graphics class - required for all drawing
    Debug.Print GdipCreateFromHDC(Picture1.hdc, graphics)

    ' Optional: Set Anti-Aliasing mode
    Debug.Print GdipSetSmoothingMode(graphics, SmoothingModeAntiAlias)

    ' Create a red pen
    Debug.Print GdipCreatePen1(RGB(255, 0, 0) Or &HFF000000, 1, UnitPixel, _
        pen)

End Sub

Private Sub Command1_Click()
    If Not GDIpLoaded Then
        Exit Sub
    End If

    ' Draw the first line
    Debug.Print GdipDrawLineI(graphics, pen, 0, 0, 100, 100)

End Sub

Private Sub Command2_Click()
    If Not GDIpLoaded Then
        Exit Sub
    End If

    ' Resize the PictureBox
    Picture1.Width = 200
    Picture1.Height = 200

    ' Draw a larger line, it's truncated at the original PictureBox size
    Debug.Print GdipDrawLineI(graphics, pen, 0, 0, 200, 200)
End Sub

Private Sub Form_Unload(Cancel As Integer)
    If GDIpLoaded Then
        ' Clean up
        GdipDeletePen pen
        GdipDeleteGraphics graphics

        ' Shutdown the GDI+ Dll
        GdiplusShutdown (token)
    End If
End Sub

Author
15 Aug 2010 10:02 PM
Nobody
"Nobody" <nob***@nobody.com> wrote in message
news:O5cM1kKPLHA.5644@TK2MSFTNGP04.phx.gbl...
>    ' Create a red pen
>    Debug.Print GdipCreatePen1(RGB(255, 0, 0) Or &HFF000000, 1, UnitPixel,
> _
>        pen)

The RGB values are reversed in GDI+, so use the function below instead.
Alpha value need to be high enough, otherwise you may not see anything
because it represents transparency level.

Public Function RGBA(ByVal Red As Long, _
                      ByVal Green As Long, _
                      ByVal Blue As Long, _
                      ByVal Alpha As Long) As Long
    Dim result As Long

    If Alpha >= 128 Then
        result = &H80000000
    End If
    result = result Or ((Alpha And &H7F&) * &H1000000)
    result = result Or (Red * &H10000)
    result = result Or (Green * &H100)
    RGBA = result Or Blue
End Function
Author
15 Aug 2010 11:04 PM
Nobody
"Nobody" <nob***@nobody.com> wrote in message
news:O5cM1kKPLHA.5644@TK2MSFTNGP04.phx.gbl...
>    ' Initialize the graphics class - required for all drawing
>    Debug.Print GdipCreateFromHDC(Picture1.hdc, graphics)

Recreating the Graphics object works fine and seems unnoticeable, so I guess
this thread is closed unless someone has a better suggestion...
Author
17 Aug 2010 8:27 AM
Dee Earley
On 16/08/2010 00:04, Nobody wrote:
> "Nobody"<nob***@nobody.com>  wrote in message
> news:O5cM1kKPLHA.5644@TK2MSFTNGP04.phx.gbl...
>>     ' Initialize the graphics class - required for all drawing
>>     Debug.Print GdipCreateFromHDC(Picture1.hdc, graphics)
>
> Recreating the Graphics object works fine and seems unnoticeable, so I guess
> this thread is closed unless someone has a better suggestion...

IIRC, this is the way it should be used.

..NET has the CreateGraphics() method you use when painting (or it does
it implicitly in OnPaint), similar to the native GDI BeginPaint() function.

--
Dee Earley (dee.ear***@icode.co.uk)
i-Catcher Development Team

iCode Systems

(Replies direct to my email address will be ignored.
Please reply to the group.)
Author
16 Aug 2010 9:47 AM
Mike Williams
"Nobody" <nob***@nobody.com> wrote in message
news:O5cM1kKPLHA.5644@TK2MSFTNGP04.phx.gbl...

> I am using GDI+ in one of my VB6 apps(mainly for anti aliasing support).

Maybe it's just me (these old eyes of mine are probably not quite what they
used to be!), but I'm not really keen on GDI+ output when stretching images,
at least not when reducing their size, which is the most common required
stretching task when dealing with camera originals. The GDI+ NearestNeighbor
mode is obviously not very good (about the equivalent of StretchBlt's
COLOR_ON_COLOR, which is also the VB PaintPicture mode). The GDI+
HighQualityBilinear mode is smoother but very blurred, and the GDI+
HighQualityBicubic mode is the best of the three (as expected), but whilst
having a decent smoothing it noticeably blurrs the image, making it look
quite out of focus. In comparison, StretchBlt's HALFTONE mode gives almost
as much smoothing whilst at the same time retaining all the sharpness of the
original image. StretchBlt's HALFTONE output does not look out of focus at
all. I would definitely say that StretchBlt's output certainly looks the
best to me.

Naturally, as with most things, it's "horses for courses" and there will be
certain types of image (particularly computer drawn images) where the loss
of focus of GDI+ HighQualityBicubic mode might be more than compensated for
by the slightly better smoothing effect, and probably also when expanding
the size of images (I haven't tried any comparisons on that yet because it
is not something I normally need to do) but for my own needs I very much
prefer StretchBlt's HALFTONE output to the GDI+ slightly out of focus
output.

Mike
Author
16 Aug 2010 12:25 PM
Mayayana
| Naturally, as with most things, it's "horses for courses" and there will
be
| certain types of image (particularly computer drawn images) where the loss
| of focus of GDI+ HighQualityBicubic mode might be more than compensated
for
| by the slightly better smoothing effect, and probably also when expanding
| the size of images (I haven't tried any comparisons on that yet because it
| is not something I normally need to do)

  It's my understanding that bicubic is recommended
for enlarging only -- bilinear for reducing....though I can't
tell you now where I read that.
Author
16 Aug 2010 1:29 PM
Mike Williams
"Mayayana" <mayayana@invalid.nospam> wrote in message
news:i4bakm$3r0$1@news.eternal-september.org...

>  It's my understanding that bicubic is recommended
> for enlarging only -- bilinear for reducing....though I
> can't tell you now where I read that.

Yeah, you're probably right. But I've just tried enlarging an image to 4.5
times its width and height using GDI+ HighQualityBicubic and compared it to
the output of the standard GDI32 StretchBlt Halftone mode at the same size
and I haven't changed my mind. I still prefer the output of StretchBlt, even
when enlarging images. The sample I used was the small image of an eye from
here:

http://www.dpreview.com/learn/?/Glossary/Digital_Imaging/Interpolation_01.htm

Neither GDI+ nor StretchBlt quite reach the quality of the PhotoShop output
shown on that page, but they are both respectable and of the two I still
prefer the StretchBlt output, which is very close to the smoothness of GDI+
but significantly sharper, at least to my eyes.

Mike
Author
16 Aug 2010 11:10 PM
Mayayana
Show quote Hide quote
|
| >  It's my understanding that bicubic is recommended
| > for enlarging only -- bilinear for reducing....though I
| > can't tell you now where I read that.
|
| Yeah, you're probably right. But I've just tried enlarging an image to 4.5
| times its width and height using GDI+ HighQualityBicubic and compared it
to
| the output of the standard GDI32 StretchBlt Halftone mode at the same size
| and I haven't changed my mind. I still prefer the output of StretchBlt,
even
| when enlarging images. The sample I used was the small image of an eye
from
| here:
|
|
http://www.dpreview.com/learn/?/Glossary/Digital_Imaging/Interpolation_01.htm
|
| Neither GDI+ nor StretchBlt quite reach the quality of the PhotoShop
output
| shown on that page, but they are both respectable and of the two I still
| prefer the StretchBlt output, which is very close to the smoothness of
GDI+
| but significantly sharper, at least to my eyes.
|

   Isn't halftone a dithering method that would lose
colors? How does that work on a true-color system?

  The images on that page don't look very different
to me, except the fractal method, which looks
noticeably better. But I've never heard of "fractal
interpolation", and the link to www.altamira-group.com
seems to be dead.
Author
17 Aug 2010 10:29 AM
Mike Williams
"Mayayana" <mayayana@invalid.nospam> wrote in message
news:i4cgd0$3a1$1@news.eternal-september.org...

> Isn't halftone a dithering method that would
> lose colors? How does that work on a
> true-color system?

Well, the colour halftones I remember from my youth were the pictures in the
old comic books (and later in photos in newspaper images) where the image
was composed of dots that that differed in both colour and size, with a
limited number of colours that was partly made up for by the fact that the
dot size was not fixed, but those comic book halftones I recall from my
youth were over half a century ago now and the details of the halftone
method might have changed quite a bit since I was a lad! As far as your
remark about the possibility of it losing colours is concerned, StretchBlt
halftone certainly does not seem to have any problem at all dealing with
full colour images. In fact I've just tested it on a 6338 x 4934 pixel .bmp
photo which contains 3,694,204 unique colours. When I use StretchBlt
halftone I get the following results:

6338 x 4934 pixels : 3,694,204 unique colours (original)
9507 x 7401 pixels : 4,685,815 unique colours (1.5 x 1.5)
4754 x 3700 pixels : 3,026,265 unique colours (.75 x .75)

It certainly does not look to me as though StretchBlt halftone is having any
problem at all dealing with lots of colours. As far as the StretchBlt
halftone mode is concerned, I do not know the details of the algorithm it
uses, or even if the name "halftone" in that respect refers to an adaption
of the old early classic halftone methods or perhaps something that might
now be quite different. What I do know is that, at least to my own eyes,
reducing the size of photos using StretchBlt's halftone mode (which is about
the only thing I ever do with it) produces results as good as any you can
get from GDI+, and even better where sharpness is concerned (as is the case
with my old eyes!). It might be that GDI+ does better when increasing the
size of photos, but personally I never have the need to do that. If I did
then I would certainly look into it and I would perform some tests and, if
GDI+ turned out to be better at increasing the size of photos, then I would
use it (although neither StretchBlt nor GDI+ is going to give you anywhere
near the quality that you get from something like Adobe PhotoShop of
course!). I've got nothing against using GDI+, it's just that the for
reducing the size of photos (which is the only thing I normally do with
StretchBlt) I actually prefer StretchBlt's halftone output to any of the
three GDI+ outputs.

> The images on that page [the three different GDI+
> methods] don't look very different to me . . .

Actually they all look different to me, although the second and third are
quite similar.

> . . . except the fractal method, which looks noticeably better.

Yes, it does, Lots better. But sadly neither StretchBlt nor GDI+ can use
that method. StretchBlt will never be updated to use it of course, because
GDI32 is dead in the water as far as Micro$oft is concerned. Perhaps one
day, when all the Micro$oft employees stop watching their CEO dancing around
on the stage like a deranged lunatic . . .

    http://www.youtube.com/watch?v=Y89wBYVHkY4&NR=1

.. . . and when they instead get on with some actual work, they might be able
to buy some people from Adobe or somewhere who actually know what they're
doing and get them to produce a "Micro$oft update" for GDI+ for them :-)

Mike
Author
18 Aug 2010 1:27 AM
Mayayana
Show quote Hide quote
| > Isn't halftone a dithering method that would
| > lose colors? How does that work on a
| > true-color system?
|
| Well, the colour halftones I remember from my youth were the pictures in
the
| old comic books (and later in photos in newspaper images) where the image
| was composed of dots that that differed in both colour and size, with a
| limited number of colours that was partly made up for by the fact that the
| dot size was not fixed, but those comic book halftones I recall from my
| youth were over half a century ago now and the details of the halftone
| method might have changed quite a bit since I was a lad! As far as your
| remark about the possibility of it losing colours is concerned, StretchBlt
| halftone certainly does not seem to have any problem at all dealing with
| full colour images. In fact I've just tested it on a 6338 x 4934 pixel
..bmp
| photo which contains 3,694,204 unique colours. When I use StretchBlt
| halftone I get the following results:
|
| 6338 x 4934 pixels : 3,694,204 unique colours (original)
| 9507 x 7401 pixels : 4,685,815 unique colours (1.5 x 1.5)
| 4754 x 3700 pixels : 3,026,265 unique colours (.75 x .75)
|
| It certainly does not look to me as though StretchBlt halftone is having
any
| problem at all dealing with lots of colours.

Thanks for that info. I asked because I didn't know what
halftone does so I looked it up, and found this:

http://support.microsoft.com/kb/168743

But based on your results it sounds like halftone
can also perform a sort of anti-dither, filling in
likely colors in an enlargement.

  I did a quick look around for fractal interpolation
and found various things. It doesn't seem to be
a clear-cut issue. One page I found was here:

http://www.resampling.narod.ru/

Lots of methods... but no source code. Maybe one
of these days when I have time I'll look into that.
It looks like it could take a long time to get hold
of straight VB code for these methods.
Author
18 Aug 2010 2:40 PM
Mike Williams
Show quote Hide quote
"Mayayana" <mayayana@invalid.nospam> wrote in message
news:i4fcqg$k5v$1@news.eternal-september.org...
> >
> > [Mike Williams said]  In fact I've just tested it on a
> > 6338 x 4934 pixel .bmp photo which contains
> > 3,694,204 unique colours. When I use StretchBlt
> > halftone I get the following results: [snipped]
>
> Thanks for that info. I asked because I didn't know
> what halftone does so I looked it up, and found this:
> http://support.microsoft.com/kb/168743
> But based on your results it sounds like halftone
> can also perform a sort of anti-dither, filling in
> likely colors in an enlargement.

Actually the page at the link you posted mostly concerns itself with the
GDI32 SetColorAdjustment function and so its initial mention of halftone
StretchBlt limited itself to how it can use dithering to overcome the
limitations of BitBlt's remapping when drawing a full colour 24 bit image
into a lower colour depth display, such as a 16 bit display for example. But
when you are using a halftone StretchBlt to reduce or enlarge the pixel size
of an original 24 bit bitmap and to save the output as a new image (rather
than simply draw it to the screen) then instead of using PictureBoxes you
would normally load the original bitmap into a 24 bit DIB and ask StretchBlt
to draw its output into another 24 bit DIB, and in that case it has the full
sixteen million colours to work with in both DIBs regardless of the colour
depth of the display on which your code is running. StretchBlt is then
capable of calculating new colour values for various pixels (although I
don't know the specific algorithm it uses) and it has the full sixteen
million colours at its disposal and is not limited to the colours used in
the original when it does that. Not that it often matters much these days of
course, where almost all desktops and laptops are running full colour
displays.

By the way, thank you for the link to the SetColorAdjustment function. It is
something I had briefly looked a long time ago but had almost totally
forgotten about, so I'm glad you posted that link. I might look at it again
now. There seem to be all sorts of filters that can be applied to
StretchBlt, many of which look quite interesting. The only one I had ever
used myself, when I briefly looked at it ages ago, was the contrast filter,
but that particular filter did not work very well as I recall. On many
photos it worked okay if you altered both the brightness and the contrast,
but on some photos, particularly those that have an original average
brightness level far removed from the 128 mid value, it was not possible to
get a good contrast adjustment at all using SetColorAdjustment, regardless
of what you did. In fact I seem to recall that was why I stopped using it
and instead wrote code to perform the contrast adjustment pixel by pixel in
straight VB code, which turned out to be just as fast as StretchBlt halftone
contrast but which is capable of producing a high quality contrast on all
images, regardless of their original average brightness level.

Anyway, thanks again for the link. I'll probably have a look at
SetColorAdjustment again.

Mike