Mosaic




'Functions for Processing Bitmaps

Declare Function VarPtrArray Lib "msvbvm50.dll" Alias _
"VarPtr" (Ptr() As Any) As Long
Declare Sub CopyMemory Lib "kernel32" Alias _
"RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Declare Function GetObjectAPI Lib "gdi32" _
Alias "GetObjectA" (ByVal hObject As Long, _
ByVal nCount As Long, lpObject As Any) As Long
Type BITMAP
bmType As Long
bmWidth As Long
bmHeight As Long
bmWidthBytes As Long
bmPlanes As Integer
bmBitsPixel As Integer
bmBits As Long
End Type
Type SafeArrayBound
cElements As Long
lLbound As Long
End Type
Type SafeArray2D
cDims As Integer
fFeatures As Integer
cbElements As Long
cLocks As Long
pvData As Long
bounds(0 To 1) As SafeArrayBound
End Type
Name: Mosaic
Description:
Takes a picturebox, and it's contents, and runs an animated mosaic
transition through it
Inputs:
pctMosaic, the picturebox object that you're wanting to manipulate
MosaicMode, set it to 1 For mosaic, 2 for demosaic, 3 for mosaic,
Then demosaic
Assumes:Nothing.
If you want to edit it, that's another story :)
Side Effects:
Can crash some computers. Seems to be a display driver
to windows problem! I don't know what causes this!
Sub GenMosaic(pctMosaic As Variant, MosaicMode As Integer)
'Mosaic Mode is 1 for Mosaic, 2 for DeMosaic

Static mosaicgoing As Boolean
'Keep a static variable to check if the sub's running.

'If it is, EXIT! Otherwise, GPF!

If mosaicgoing = True Then Exit Sub
mosaicgoing = True
'Init variables

Dim pict() As Byte
Dim SA As SafeArray2D, bmp As BITMAP
Dim r As Integer, c As Integer, Value As Byte, i As Integer, colour As Integer, j As Integer, k As Integer, L As Integer
Dim pCenter As Integer, pC As Integer, pR As Integer
Dim rRangei As Integer, rRangej As Integer, ti As Integer, ti2 As Integer
Dim uC As Integer, uR As Integer
Dim PictureArray() As Byte
Dim mRange As Integer
Dim cLimit As Integer, rLimit As Integer
'Copy to the array

GetObjectAPI pctMosaic.Picture, Len(bmp), bmp
If bmp.bmPlanes <> 1 Or bmp.bmBitsPixel <> 8 Then
MsgBox "Non-256 colour bitmap detected. No mosaic effects"
Exit Sub
End If
'Init the SafeArray

With SA
.cbElements = 1
.cDims = 2
.bounds(0).lLbound = 0
.bounds(0).cElements = bmp.bmHeight
.bounds(1).lLbound = 0
.bounds(1).cElements = bmp.bmWidthBytes
.pvData = bmp.bmBits
End With
'Map the pointer over

CopyMemory ByVal VarPtrArray(pict), VarPtr(SA), 4
'Make a temporary array to hold the bitmap data.

ReDim PictureArray(UBound(pict, 1), UBound(pict, 2))
'Copy the bitmap into this array. I could use copymemory

'again, but this is fast enough, and a lot safer :)

For c = 0 To UBound(pict, 1)
For r = 0 To UBound(pict, 2)
PictureArray(c, r) = pict(c, r)
Next r
Next c
'Clean up

CopyMemory ByVal VarPtrArray(pict), 0&, 4
Select Case MosaicMode
Case 1
'Mosaic

For k = 1 To 16 Step 1
For L = 1 To 1
mRange = k ^ 1.5
GoSub Mosaic
Next L
Next k
Case 2
'DeMosaic

For k = 16 To 0 Step -(1)
For L = 1 To 1
mRange = k ^ 1.5
GoSub Mosaic
Next L
Next k
Case 3
'Mosaic, then DeMosaic

For k = 1 To 8 Step 1
mRange = k ^ 1.5
GoSub Mosaic
Next k
For k = (8) To 0 Step -(1)
mRange = k ^ 1.5
GoSub Mosaic
Next k
End Select
mosaicgoing = False
Exit Sub
'Mosaic:

'Get the bitmap info again, in case something's changed

GetObjectAPI pctMosaic.Picture, Len(bmp), bmp
'Reinit the SA

With SA
.cbElements = 1
.cDims = 2
.bounds(0).lLbound = 0
.bounds(0).cElements = bmp.bmHeight
.bounds(1).lLbound = 0
.bounds(1).cElements = bmp.bmWidthBytes
.pvData = bmp.bmBits
End With
'Fake' the pointer

'CopyMemory ByVal VarPtrArray(pict), VarPtr(SA), 4 Work out the

'distance between the square division grid, and the pixel to get data from.

pCenter = (mRange) \ 2
'Find the limits of the image

uC = UBound(pict, 1)
uR = UBound(pict, 2)

For c = 0 To UBound(pict, 1) Step (mRange + 1)
For r = 0 To UBound(pict, 2) Step (mRange + 1)
'Work out the distance between the square

'division grid, and the pixel to Get data from.

pCenter = (mRange) \ 2
'Pixel size to copy over

rRangei = (mRange)
rRangej = (mRange)
'Check if it's running out of bound, in case you turned

'the compiler option off.

If c + mRange > UBound(pict, 1) Then rRangei = UBound(pict, 1) - c
If r + mRange > UBound(pict, 2) Then rRangej = UBound(pict, 2) - r
'Work out where to get the data from

pC = c + pCenter
pR = r + pCenter
If pC > UBound(pict, 1) Then pC = c
If pR > UBound(pict, 2) Then pR = r
'Get the palette entry

Value = PictureArray(pC, pR)
If c = 0 Then cLimit = -pCenter
If r = 0 Then rLimit = -pCenter
'Copy the palette entry number over the region's pixels

For i = cLimit To (rRangei)
For j = rLimit To (rRangej)
If c + i < 0 Or r + j < 0 Then Goto SkipPixel
pict(c + i, r + j) = Value
SkipPixel:
Next j
Next i
SkipThis:
Next r
Next c
EndThis:
'Clean up

CopyMemory ByVal VarPtrArray(pict), 0&, 4
'Refresh, so the user sees the change. Don't replace

'with a DoEvents!

'Refreshing is slower, but it's less dangerous!

pctMosaic.Refresh
Return
End Sub











( mosaic.html )- by Paolo Puglisi - Modifica del 17/12/2023