[futurebasic] Re: [FB] Pixel Color Change

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : October 2002 : Group Archive : Group : All Groups

From: Robert Purves <robert.purves@...>
Date: Wed, 9 Oct 2002 21:56:33 +1300
On Wednesday, October 9, 2002, at 06:24  PM, Russ Pagel wrote:
>
> From the standpoint of speed I've always changed loops like this to 
> move
> math out of loops whenever possible.
>
> You can move the "baseAddr1 + (yy * myRowBytes1)" part out of the xx
> loop so it'll only do the math once when yy changes.  Also just to be
> picky the "left = 0" is getting executed every time through the yy loop
> as well.
>
> The following should be somewhat faster for the 8 bit version
>
> left = 0 // Execute once only
> FOR yy=0 TO pictRect.bottom - 1
> myOffset=baseAddr1 + (yy * myRowBytes1)  // Execute only when yy 
> changes
> FOR xx=0 TO pictRect.right - 1
> Pixel1 = myOffset + (xx*4) // Yep, that is a pixel.
> long if Pixel1.1`` = rA and Pixel1.2`` = gA and Pixel1.3`` = bA
> Pixel1.1`` = rB
> Pixel2.2`` = gB
> Pixel3.3`` = bB
> end if
> NEXT xx
> NEXT yy
>
> Maybe someone else can answer:  Could the "long if" compare function
> above be made faster by somehow loading Pixel1 as a long, ANDing off 
> the
> last byte and doing a single compare (if) to a long constant?


Yes, you can do just that, as illustrated below. This squeezes a few 
more nanoseconds by 'strength reduction' (no multiplications in the 
loops, only additions/subtractions), and by using register variables 
for the inner loop.


'-----------------
register on

// return handle to new picture, with color change for each pixel
// whose RGB components are identical with the special color 'seek'
local mode
local fn ColorizePictH( pictH as ^^Picture, seek as ^RGBColor,¬
                       repl as ^RGBColor )
// next 5 vars are register in PPC
dim as long      x, y, seekPixel, replPixel
dim as Ptr       addr
dim as long      rowBytes
dim as Ptr       rowAddr, tempGW, @ currGW
dim as Rect      r
dim as Handle  @ currDev, pictH2
dim pmHandle as ^^PixMap
dim as OSErr     err

pictH2 = _nil // default if error
long if pictH
r = pictH..picFrame
OffsetRect( r, -r.left, -r.top )
// make a GWorld, the same size as the picture
err = fn NewGWorld( tempGW, 32, r, 0, 0, 0 )
long if ( err == _noErr )
GetGWorld( currGW, currDev ) // save current
SetGWorld( tempGW, 0 )
picture , pictH // draw in GWorld

pmHandle = fn GetGWorldPixMap( tempGW )
rowBytes = pmHandle..rowBytes and 0x3fff
rowAddr  = fn GetPixbaseAddr( pmHandle )
// construct 32-bit pixels from RGBColors
seekPixel = ((seek.red and 0xff00) << 8) + ¬
      (seek.green and 0xff00) + (seek.blue >> 8)
replPixel = ((repl.red and 0xff00) << 8) + ¬
      (repl.green and 0xff00) + (repl.blue >> 8)
// test each pixel
y = r.bottom - 1
while ( y )
addr = rowAddr
x = r.right - 1
while ( x  )
if ( addr.nil& == seekPixel ) then addr.nil& = replPixel
x--
addr += 4
wend
rowAddr += rowBytes
y--
wend

pictH2 = usr GetPict( r ) // make new picture
SetGWorld( currGW, currDev ) // restore
DisposeGWorld( tempGW ) // prevent memory leak

end if
end if
end fn = pictH2


// Main program
'~'1
dim as Handle    pictH, pictH2
dim as Rect      r
dim as RGBColor  seekRGB, replaceRGB
dim as long j

SetRect( r, 0, 0, 600, 400 )
window 1, "Color Convert", @r, _docNoGrow
text _geneva, 24

picture on // make demo picture
EraseRect( r )
pen 2, 2
for j = 1 to 50
if maybe then color _zRed else color _zBlack
plot rnd( r.right ), rnd( r.bottom ) to rnd( r.right ), rnd( r.bottom )
next
print @(1,1) "Click mouse to convert black to blue"
picture off , pictH
picture , pictH

do
HandleEvents
until fn Button

// seek color black
seekRGB.red    = 0
seekRGB.green  = 0
seekRGB.blue   = 0

// replacement color blue
replaceRGB.red   = 0
replaceRGB.green = 20000
replaceRGB.blue  = 65535

pictH2 = fn ColorizePictH( pictH, seekRGB, replaceRGB )
long if ( pictH2 )
picture , pictH2 // draw new picture
xelse
stop "ColorizePictH failed"
end if

do
HandleEvents
until 0
'-----------------

Robert P.