From: Nobody on
"Bee" <Bee(a)discussions.microsoft.com> wrote in message
news:B2CBE975-4A53-46B7-AC1A-557C2876893F(a)microsoft.com...
> I need to be able to copy the selected area to the clipboard and then
> paste
> the selected area only on to a picturebox pixture with a moveable paste
> image.

Check out MaskBlt().



From: Nobody on
"Nobody" <nobody(a)nobody.com> wrote in message
news:uMwV0R3ZKHA.5300(a)TK2MSFTNGP02.phx.gbl...
> "Bee" <Bee(a)discussions.microsoft.com> wrote in message
> news:B2CBE975-4A53-46B7-AC1A-557C2876893F(a)microsoft.com...
>> I need to be able to copy the selected area to the clipboard and then
>> paste
>> the selected area only on to a picturebox pixture with a moveable paste
>> image.
>
> Check out MaskBlt().
>

On the other hand, that function may not be suitable for what you are trying
to do, I have not tried it.


From: Nobody on
Search the newsgroups for "vb TransparentBlt".


From: Mike Williams on
"Bee" <Bee(a)discussions.microsoft.com> wrote in message
news:B2CBE975-4A53-46B7-AC1A-557C2876893F(a)microsoft.com...

> Thank you both for some good insights.
> Unfortuantely I am not that gifted to take it further.

The thing is that most people here don't have the time to write full working
examples for you, and even if they do have the time they often do not have
the inclination, because it is always a better idea in the long run (for
yourself I mean) for people to post responses containing just get some
sample starter code or some information and for you to take it to the next
step yourself.

> Perhaps there is sample code or books that might
> take me to the next step. Suggestions?

A lot depends on which things you already know and which you don't. To get
you a bit further along the road to your goal here is a modification of my
previous example which takes the process one step further in that it now
creates a sprite image and the associated mask image for you. The sprite
image is your selection on a white background and the mask image is a black
on white image where the white pixels represent the transparent pixels of
the sprite (see code at end of this response). These two images are what you
need to draw a "transparent sprite" onto any part of your main PictureBox
(or anywhere else) and you need to combine them (commonly in a multiple blit
operation, although there are other different methods) using a standard
"sprite drawing" technique. Alternatively, you could simply use a single
call to the TransparentBlt API using only the sprite image and specifying
white as the transparent colour. The problem with the TransparentBlt API
though is that it does not use a supplied mask (it creates its own on the
fly) and so any parts of the image that you do not want to be transparent
and that just happen to be the same colour as the selected transparent
colour will also be drawn transparently, which is not what you want. Most
real sprite drawing methods do not have that limitation, because they
commonly use both a sprite image and a mask, and so I would suggest that's
what you do. Transparently drawing the sprite on the PictureBox is only part
of your solution of course, because according to your latest post you also
want to be able to drag the transparently drawn sprite around the man
pictureBox in real time, which requires a little more code.

Anyway, here's the example code (below) which allows you to use the mouse to
freehand draw your selection and which then creates the appropriate sprite
and mask images. Once you've tried it you'll be able to add the extra code
yourself to actually transparently draw and move the sprite around the main
PictureBox with the mouse, using the sprite and mask images that my code
already provides for your sprite drawings. Drawing and moving sprites is a
fairly standard operation for which you'll find lots of example code dotted
around the web. I would advise you to search Google and see what you can
come up with in the way of sample code and tutorials for sprite drawing and
sprite movement or animation in VB6, and then write the required code
yourself. If you really do get stuck though after reading teavailable
tutorials then feel free to post again.

Start a new VB project and place three PictureBoxes and three Command
Buttons on the Form. Name the three PictureBoxes picMain, picSprite and
picMask respectively. Then paste in the following code.

Mike

Option Explicit
Private Declare Function Polygon Lib "gdi32" _
(ByVal hdc As Long, lpPoint As POINTAPI, _
ByVal nCount As Long) As Long
Private Declare Function CreatePolygonRgn Lib "gdi32" _
(lpPoint As POINTAPI, ByVal nCount As Long, _
ByVal nPolyFillMode As Long) As Long
Private Declare Function PaintRgn Lib "gdi32" _
(ByVal hdc As Long, ByVal hRgn As Long) As Long
Private Declare Function GetRgnBox Lib "gdi32" _
(ByVal hRgn As Long, lpRect As RECT) As Long
Private Declare Function OffsetRgn Lib "gdi32" _
(ByVal hRgn As Long, ByVal x As Long, _
ByVal y As Long) As Long
Private Declare Function SelectClipRgn Lib "gdi32" _
(ByVal hdc As Long, ByVal hRgn As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" _
(ByVal hObject As Long) As Long
Private Declare Function BitBlt Lib "gdi32" _
(ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, _
ByVal nWidth As Long, ByVal nHeight As Long, _
ByVal hSrcDC As Long, ByVal xSrc As Long, _
ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Const ALTERNATE As Long = 1
Private Const WINDING As Long = 2
Private Const NULLREGION As Long = 1
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type POINTAPI
x As Long
y As Long
End Type
Private d1() As POINTAPI
Private lastCoord As Long, SelectionValid As Boolean
Private Rgn1 As Long, Rgn2 As Long, Rect1 As RECT
Private Drawing As Boolean, SpriteVisible As Boolean

Private Sub Form_Load()
Dim s1 As String
Me.WindowState = vbMaximized
Me.Show
s1 = "c:\temp\jessica1.jpg"
picMain.AutoRedraw = True
picMain.Move 0, 0, Me.ScaleWidth, Me.ScaleHeight - Command1.Height
picMain.ScaleMode = vbPixels
picMain.PaintPicture LoadPicture(s1), 0, 0, _
picMain.ScaleWidth, picMain.ScaleHeight
picSprite.ScaleMode = vbPixels
picSprite.BorderStyle = vbBSNone
picSprite.BackColor = vbWhite
picSprite.AutoRedraw = True
picSprite.ZOrder 1
picMask.ScaleMode = vbPixels
picMask.BorderStyle = vbBSNone
picMask.BackColor = vbWhite
picMask.FillColor = vbBlack
picMask.FillStyle = vbFSSolid
picMask.AutoRedraw = True
picMask.ZOrder 1
Command1.Move picMain.Width * 0.3, picMain.Height
Command2.Move Command1.Width * 1.2 + Command1.Left, picMain.Height
Command3.Move Command2.Width * 1.2 + Command2.Left, picMain.Height, _
Command2.Width * 1.5, Command2.Height
Command1.Caption = "Cut Selection"
Command2.Caption = "Copy Selection"
Command3.Caption = "Show / Hide Sprite and Mask"
Command1.Enabled = False: Command2.Enabled = False
End Sub

Private Sub Form_Unload(Cancel As Integer)
DeleteObject Rgn1
DeleteObject Rgn2
End Sub

Private Sub picmain_MouseDown(Button As Integer, _
Shift As Integer, x As Single, y As Single)
Dim retVal As Long
Select Case Button
Case vbLeftButton
If SelectionValid = True Then
picMain.DrawMode = vbXorPen
picMain.FillStyle = vbFSTransparent
Polygon picMain.hdc, d1(0), lastCoord + 1
End If
SelectionValid = False
Command1.Enabled = False
Command2.Enabled = False
Drawing = True
picMain.ForeColor = vbWhite
picMain.DrawMode = vbNop
picMain.PSet (x, y)
picMain.DrawMode = vbXorPen
ReDim d1(0 To 100)
lastCoord = 0
d1(lastCoord).x = x
d1(lastCoord).y = y
Case vbRightButton
' not yet used
End Select
End Sub

Private Sub picmain_MouseMove(Button As Integer, _
Shift As Integer, x As Single, y As Single)
If Not Drawing Then Exit Sub
picMain.Line -(x, y)
lastCoord = lastCoord + 1
If lastCoord > UBound(d1) Then
ReDim Preserve d1(0 To lastCoord + 100)
End If
d1(lastCoord).x = x
d1(lastCoord).y = y
End Sub

Private Sub picmain_MouseUp(Button As Integer, _
Shift As Integer, x As Single, y As Single)
Drawing = False
If Button = vbLeftButton Then
picMain.Line -(d1(0).x, d1(0).y)
If lastCoord > 0 Then
SelectionValid = True
Command1.Enabled = True
Command2.Enabled = True
End If
End If
End Sub

Private Sub MakeSpriteAndMask()
picSprite.Width = Me.ScaleX(Rect1.Right - Rect1.Left, _
vbPixels, Me.ScaleMode)
picSprite.Height = Me.ScaleY(Rect1.Bottom - Rect1.Top, _
vbPixels, Me.ScaleMode)
picSprite.Cls ' clear to white
' move Rgn2 to location (0, 0) and select into picSprite
OffsetRgn Rgn2, -Rect1.Left, -Rect1.Top
SelectClipRgn picSprite.hdc, Rgn2
' blit the rectangle containing the region into
' from picMain into picSprite
BitBlt picSprite.hdc, 0, 0, picSprite.ScaleWidth, _
picSprite.ScaleHeight, picMain.hdc, _
Rect1.Left, Rect1.Top, vbSrcCopy
picSprite.Refresh ' just for display while testing
' set up picMask accordingly
picMask.Width = picSprite.Width
picMask.Height = picSprite.Height
picMask.Cls
PaintRgn picMask.hdc, Rgn2
picMask.Refresh ' just for display while testing
End Sub

Private Sub Command1_Click()
' Cut selected area to sprite and mask buffers
Dim retVal As Long
If SelectionValid = True Then
' erase vbXorPen drawn polygon by redrawing
Polygon picMain.hdc, d1(0), lastCoord + 1
' create two regions using the polygon data
DeleteObject Rgn1: DeleteObject Rgn2
Rgn1 = CreatePolygonRgn(d1(0), lastCoord + 1, WINDING)
Rgn2 = CreatePolygonRgn(d1(0), lastCoord + 1, WINDING)
' paint the region white
retVal = GetRgnBox(Rgn1, Rect1)
If retVal <> 0 And retVal <> NULLREGION Then
MakeSpriteAndMask
' cut the selected area to white
picMain.FillColor = vbWhite
picMain.FillStyle = vbFSSolid
picMain.DrawMode = vbCopyPen
PaintRgn picMain.hdc, Rgn1
picMain.FillStyle = vbFSTransparent
picMain.Refresh
End If
End If
SelectionValid = False
Command1.Enabled = False
Command2.Enabled = False
End Sub

Private Sub Command2_Click()
' Copy selected area to sprite and mask buffers
Dim retVal As Long
If SelectionValid = True Then
' erase vbXorPen drawn polygon by redrawing
Polygon picMain.hdc, d1(0), lastCoord + 1
' create two regions using the polygon data
DeleteObject Rgn1: DeleteObject Rgn2
Rgn1 = CreatePolygonRgn(d1(0), lastCoord + 1, WINDING)
Rgn2 = CreatePolygonRgn(d1(0), lastCoord + 1, WINDING)
' paint the region white
retVal = GetRgnBox(Rgn1, Rect1)
If retVal <> 0 And retVal <> NULLREGION Then
MakeSpriteAndMask
picMain.Refresh
End If
End If
SelectionValid = False
Command1.Enabled = False
Command2.Enabled = False
If picSprite.Visible Then
picSprite.Move 0, 0
picMask.Move Me.ScaleWidth - picMask.Width, 0
End If
End Sub

Private Sub Command3_Click()
' show / hide the sprite and mask PictureBoxes
' (This is just for test purposes and the
' sprite and mask images will overlap on the
' Form they are large
If SpriteVisible Then
picSprite.ZOrder 1: picMask.ZOrder 1
SpriteVisible = False
Else
picSprite.Move 0, 0
picMask.Move Me.ScaleWidth - picMask.Width, 0
picMask.ZOrder 0: picSprite.ZOrder 0
SpriteVisible = True
End If
End Sub

From: Bee on
Thanks again Mike.
I used the clipboard because it seemed easier for me to deal with it all
when I was doing the limited box lasso. It works and has the side benefit
that the copy or cut image is available on the clipboard if needed.

I am always torn as in when to use a picturebox component or a Dim pic As
Picturebox or Dim pic As StdPicture.

I will take a long look at this latest effort on your part.

Maybe you should write a book on all of this graphics API call stuff.
I would buy it.
I'll bet others would too because as far as I know, stuff like this is not
built into that other language or C++. Many would get a good education.
You are very well informed.
Still would like to find a book or website dealing with all of this.