[bb] ScaleImageFast by sswift [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:39

Previous topic - Next topic

BlitzBot

Title : ScaleImageFast
Author : sswift
Posted : 1+ years ago

Description : This function scales an image an arbitrary amount on each axis, and is 80x faster than the default ScaleImage function in Blitz!

Actually, I should say, it is 80x faster than the ScaleImage function in BlitzPlus.  I have not tested it against the ScaleImage function in Blitz3D.  

It will probably be faster than the one in Blitz3D as well, but the major speed boost here may be due to CopyRect being hardware accelerated in BlitzPlus.


Code :
Code (blitzbasic) Select
; -------------------------------------------------------------------------------------------------------------------------------------
; This function scales an image an arbitrary amount on the X and Y axis, and returns a pointer to the new image.
; The original image is not modified.
;
; This function is 80x faster than the ScaleImage function that comes with Blitz!
; -------------------------------------------------------------------------------------------------------------------------------------
Function ScaleImageFast(SrcImage, ScaleX#, ScaleY#)

Local SrcWidth,  SrcHeight
Local DestWidth, DestHeight
Local ScratchImage, DestImage
Local SrcBuffer, ScratchBuffer, DestBuffer
Local X1, Y1, X2, Y2

; Get the width and height of the source image.
SrcWidth  = ImageWidth(SrcImage)
SrcHeight = ImageHeight(SrcImage)

; Calculate the width and height of the dest image.
DestWidth  = Floor(SrcWidth  * ScaleX#)
DestHeight = Floor(SrcHeight * ScaleY#)

; If the image does not need to be scaled, just copy the image and exit the function.
If (SrcWidth = DestWidth) And (SrcHeight = DestHeight) Then Return CopyImage(SrcImage)

; Create a scratch image that is as tall as the source image, and as wide as the destination image.
ScratchImage = CreateImage(DestWidth, SrcHeight)

; Create the destination image.
DestImage = CreateImage(DestWidth, DestHeight)

; Get pointers to the image buffers.
SrcBuffer     = ImageBuffer(SrcImage)
ScratchBuffer = ImageBuffer(ScratchImage)
DestBuffer    = ImageBuffer(DestImage)

; Duplicate columns from source image to scratch image.
For X2 = 0 To DestWidth-1
X1 = Floor(X2 / ScaleX#)
CopyRect X1, 0, 1, SrcHeight, X2, 0, SrcBuffer, ScratchBuffer
Next

; Duplicate rows from scratch image to destination image.
For Y2 = 0 To DestHeight-1
Y1 = Floor(Y2 / ScaleY#)
CopyRect 0, Y1, DestWidth, 1, 0, Y2, ScratchBuffer, DestBuffer
Next

; Free the scratch image.
FreeImage ScratchImage

; Return the new image.
Return DestImage

End Function


Comments :


jfk EO-11110(Posted 1+ years ago)

 this is cool. and since we are talking about it, how about to use a sprite to scale an image? simply move the original onto a texture, then move the sprite away from a camera until it reaches a certain size, den take it by Renderworld. Could be pretty fast. Sorry for hijacking the thread :P


Kevin_(Posted 1+ years ago)

 Swift....Although very fast it is a massive memory consumer. It brought up the 'Virtual Memory Low' alert when I ran it.You are better off creating your scratch images outside your function and setting them as Global and not using the free image command at all.Here is an example by Nullmind (blitzcoder) that I have modified that uses a scratch image the same size as the screen.Time tests on my XP2400+ & Ati 9000 Pro...ScaleImage    = 1840 millisecs to scale to full screenDrawSizeImage = 13 millisecs to scale to full screenConclusion... DrawSizeImage Function is 141 times faster than the Blitz ScaleImage command.
; Fast Bitmap Scale. Original by Nullmind.
;
; Use I & O keys to zoom in and out
;
SeedRnd(MilliSecs())

SW=800:SH=600
Graphics SW,SH,32,2
SetBuffer BackBuffer()

Global scratch%=CreateImage(SW,SH)                ; create a scratch image

For r=1 To 500                                    ; draw random stuff
    x=Rand(0,SW):y=Rand(0,SH)
    s=Rand(20,100):Color Rand(0,255),Rand(0,255),Rand(0,255)
    Rect x,y,s,s
Next

Image=CreateImage(200,200)                        ; grab an image from it
GrabImage image,350,350

;Image=LoadImage("MapTile.bmp")                   ; Or load an image here

w=ImageWidth(Image):h=ImageHeight(Image)
x=250:y=175

Color 255,255,255

SI=6       ; Size increase in pixels

Repeat
  If KeyDown(23)
     w=w+SI:h=h+SI:x=x-(SI/2):y=y-(SI/2)
  EndIf
  If KeyDown(24)
     w=w-SI:h=h-SI:x=x+(SI/2):y=y+(SI/2)
  EndIf
 
  DrawSizeImage(Image,x,y,w,h)
  Text 0,0,"Use I & O keys to Zoom"
 
  Flip False:Cls
Until KeyDown(1)
End

; **********************************************************

Function DrawSizeImage(image,x%,y%,w%,h%)
     Local ih%=ImageHeight(image)
     Local iw%=ImageWidth(image)

     Local sw%=Abs(w)
     Local sh%=Abs(h)
     
     Local xr#=(Float(iw)/Float(sw))
     Local yr#=(Float(ih)/Float(sh))
     
     fromimg=ImageBuffer(image)
     toimg=ImageBuffer(scratch)
     
     Local vf=-1+((h>0)*2)
     
     Local fw=(w<0)*w
     Local fh=(h<0)*h
     
     If w>=0
          For ix=0 To sw
               CopyRect ix*xr,0,1,ih,ix,0,fromimg,toimg
          Next
     Else
          For ix=0 To sw
               CopyRect ix*xr,0,1,ih,sw-ix,0,fromimg,toimg
          Next
     EndIf

     For iy=0 To sh
          CopyRect 0,iy*yr,sw,1,x+fw,y+(iy*vf),toimg
     Next
End Function




TAS(Posted 1+ years ago)

 very nice [/i]