Code archives/Graphics/ScaleImageFast

This code has been declared by its author to be Public Domain code.

Download source code

ScaleImageFast by sswift2005
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.
; -------------------------------------------------------------------------------------------------------------------------------------
; 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-111102005
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_2005
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 screen
DrawSizeImage = 13 millisecs to scale to full screen

Conclusion... 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




TAS2010
very nice


Code Archives Forum