Re: Problem with SavePicture, and a question on new versions



<no.addr@xxxxxx> wrote in message news:ddn9go$o24@xxxxxxxxxxxxxx

> The code now in real use is as follows. The same code will be
> called to take several pictures on several forms. Note that Scale
> mode does not have to be in pixels. The plotting is all done with
> twips.

Yep. The specific task you are carrying out allowed you to "get away"
with using twips instead of pixels, but it is not something I would
advise you to continue to do, because doing so will almost certainly
"trip you up" at some time in the future, and I'll explain why. Consider
your line of code . . .

PicBitBlt.Move 0, 0, ScaleWidth, ScaleHeight

That code moves the [invisible] picture box to location 0, 0 on your
Form and sets its width and height to the scalewidth and scaleheight of
your Form. So, if the client area of your Form happens to be (say) 700 x
500 pixels then the picture box will also be 700 x 500 pixels. That will
be true regardless of the ScaleMode you are using for the Form, because
the Width and Height of a control (the picture box) are always specified
in the units used by its "container" (your Form). So far, so good.

Now consider your two lines of code that "blit" the image of the visible
Form into the invisible autoredraw picture box . . .

k = GetDC(Me.hWnd)
i = BitBlt(PicBitBlt.hDC, 0, 0, Me.ScaleWidth, Me.ScaleHeight, k, 0, 0,
&HCC0020)

Those two lines (as you obviously already know) produce a copy of your
Form in the picture box, and (as you have discovered) the bitmap shows
the entire client area of your Form and it has the same pixel size
whether the Form's Scalemode is pixels or twips. That, however, can be
considered to be a "lucky strike" on your part, and it happens simply
because the scalemode units you are using for your Form (twips) happen
to be *smaller* than the scale units that the BitBlt API is using
(pixels).

Take the example of a Form with a client area of 700 x 500 pixels and
which is using a ScaleMode of Twips (something like your own Form)
currently displayed on a computer that happens to be running at the
standard Windows "96 pixels per inch" setting (sometimes called the
"small fonts" setting). That setting (96 pixels per inch) is the same as
"15 twips per pixel" (because there are 1440 twips to the inch). For
such a Form the ScaleWidth will be 10500 and the ScaleHeight will be
7500 (both twips). Your BitBlt line (shown above) effectively becomes:

k = GetDC(Me.hWnd)
i = BitBlt(PicBitBlt.hDC, 0, 0, 10500, 7500, k, 0, 0, &HCC0020)

Now, as far as the API BitBlt routine is concerned it uses pixels for
all units (by default), so the above line is effectively asking BitBlt
to draw an area of the display starting at the top left corner of your
displayed Form's client area and to draw it starting at the top left
corner of the Autoredraw picture box and to draw a total area that is
10500 pixels wide and 7500 pixels high. Of course it cannot possibly
complete that entire task, because neither of the device contexts
contains a bitmap that is large enough, so it draws an area of pixels
that is equal to the smaller of the two device contexts, the rest being
automatically "clipped". So, you end up with a bitmap that is the same
size as your picture box (700 x 500 pixels in this case) that contains
the full image of the client area of your Form. That was lucky! If you
instead happened to be using (say) Millimeters for the same 700 x 500
pixel Form's ScaleMode then the line:

i = BitBlt(PicBitBlt.hDC, 0, 0, Me.ScaleWidth, Me.ScaleHeight, k, 0, 0,
&HCC0020)

would (on that specific 96 pixels per inch computer) effectively become:

i = BitBlt(PicBitBlt.hDC, 0, 0, 185.2, 132.3, k, 0, 0, &HCC0020)

and so although you would still end up with a 700 x 500 pixel bitmap, it
would contain just a small portion of your Form (185 x 132 pixels) at
its top left corner, the rest of the bitmap being the "blank" background
colour of the picture box. And if you were using inches (for example) as
the ScaleMode you would end up with just a few "drawn" pixels (7 x 5).
Similar "incorrect size or incorrect placement" problems would occur if
you decided to use BitBlt to draw just a small specified area of your
Form to (say) a specified area of a picture box. The solution of course
is to use Pixels as your ScaleMode whenever you are using the API
drawing or blitting routines, or alternatively add some math to perform
the appropriate conversion. A third alternative would be to "tell" the
API routines to use some other scale units (instead of pixels which they
use by default), but I wouldn't suggest doing that unless there was a
compelling reason to do so.

Sorry for giving you another "lecture", but you did say that you were
just beginning to start using the API routines and that you wanted to
learn about them, so I thought you might as well start off on the right
foot ;-)

> The bitmaps produced, however, are LARGE. Certainly not for
> carrying on diskettes. Sometimes, the code will generate upto 64
> such bitmaps. I can of course resave them RLE compressed
> (manually, which is tedious), but can I do this in VB3 with a
> couple of lines of code?

I wish! It is of course possible to do it, but it would require *a lot*
of code, and extensive use of the API routines. Alternatively, instead
of using the API you could convert the bitmap into Byte array data (if
VB3 has such things) which would allow you to reasonably quickly perform
the conversion yourself. You would, however, need to know full details
of the bitmap file format (which is a fairly simple format), and you
would also have to first convert the bitmap data to 8 bit (from the 24
bit format of your current saved bitmap, if your machine happens to be
running at higher than 16 bit colour depth) because RLE compressed
bitmap files only apply to 8 or 4 bit bitmaps. Either of those methods
would require a lot of code, certainly more than a couple of lines! If
you decide to get into this stuff then you might like to look at DIBs,
which are explained at the following link:

http://edais.mvps.org/Tutorials/GDI/DIB/index.html

You might also like to check out the Windows bitmap file format, which
can be found at:

http://www.wotsit.org/

Personally I've never got into converting bitmaps to 8 bit RLE
compressed bitmaps myself. One day I might do so, but I certainly
haven't got time at the moment. There are other methods of compression
(some lossless anmd some lossy) as you obviously already know, but all
of them require either a lot of VB code and a lot of API routines or
alternatively a "ready made" third party control. The only "lossy"
method that you could do that requires only a couple of lines of code is
to "stretch" the bitmap to a smaller pixel size, but I doubt whether
that method would suit your purposes.

> Where can I read about API use? I have seen plenty of pages
> on the Internet in the last two days, but either I get some trivial
> articles or reference materials (lists of available subroutines).

There are various resources available. You could start off by
downloading the API guide from:

http://www.mentalis.org/index2.shtml

The guide is an easily navigated list of almost all of the popular API
routines and each routine contains one or more VB examples. I'd get hold
of that as soon as I can if I were you, because there are rumours that
it may bot be available for much longer (although I don't know whether
thoise rumours are true).

For a more detailed and extremely useful treatment of the API stuff you
could do a lot worse than get yourself a copy of Dan Appleman's Visual
Basic Programmer's Guid to the Win32 API. It's not a cheap book, but
it's worth its weight in gold, if you ask me.

Mike



.



Relevant Pages

  • Re: Handling big pictures
    ... I would be interested in an API that I ... > could use to read the picture into memory and handle it there instead ... > and the picture box are 500x500 pixels in size. ... pixels off the control's area due to VB's dynamically scaled back-buffer, so enabling the AutoSize property will scale the control ...
    (microsoft.public.vb.winapi.graphics)
  • Re: Create picture in memory and move to a specific hdc
    ... I need to create a picture into memory and then send ... > If you want to create a Bitmap then use the CreateDIBSection() or ... > you're creating a monochrome Bitmap.) ... > at the OLEPicture library on my site which wraps an API ...
    (microsoft.public.vb.winapi.graphics)
  • Re: How to load bitmap into array
    ... by reading the pixels will not necessarily be the values used to PLOT the pixels, ... You will not get a 2-dimensional array; you will get a vector of bits which can represent ... I have a picture which is a bitmap picture. ...
    (microsoft.public.vc.mfc)
  • Re: Add a logo to hard copy
    ... > I have been asked to add a logo to a paper form. ... As you will see from the above code, the original size of your picture ... if you do stick to using a bitmap then ... but this time at a larger size (98 x 168 pixels for example). ...
    (comp.lang.basic.visual.misc)
  • Multi-image Bitmap Extraction
    ... I have a multi-image bitmap, 13 x 16 pixels each image, and ... a total of 16 images in one bitmap. ... an API that is used to extract the images from the bitmap? ...
    (microsoft.public.vb.general.discussion)