DrawImage with transparent color?

Linux specific forum
GBeebe
Enthusiast
Enthusiast
Posts: 263
Joined: Sat Oct 09, 2004 6:52 pm
Location: Franklin, PA - USA
Contact:

DrawImage with transparent color?

Post by GBeebe »

Code: Select all

    StartDrawing(ImageOutput(imgmap))
        BackColor(0)
        DrawImage(ImageID(walldef()\image), 15, 15)  
    StopDrawing()
This copies waldef()\image onto the imgmap image. waldef()\image was loaded from a bmp file with a black background. How do I do this with the black background being transparent?
User avatar
Kapslok
User
User
Posts: 34
Joined: Tue Sep 01, 2009 2:29 pm
Location: Finland

Re: DrawImage with transparent color?

Post by Kapslok »

This copies waldef()\image onto the imgmap image. waldef()\image was loaded from a bmp file with a black background. How do I do this with the black background being transparent?
Hi. I'd need the very same function, but my practices with GTK haven't been enough. I also tried to read pixeldata to buffer with Point/Plot operations, but it gets quite slow.
GBeebe
Enthusiast
Enthusiast
Posts: 263
Joined: Sat Oct 09, 2004 6:52 pm
Location: Franklin, PA - USA
Contact:

Re: DrawImage with transparent color?

Post by GBeebe »

A very ugly way:

Code: Select all

Procedure Blit_Img(src, dst, x, y, TransparentColor = -1)
  For xx = 0 To ImageWidth(src) - 1
    For yy = 0 To ImageHeight(src) - 1
        StartDrawing(ImageOutput(src))
            color = Point(xx, yy)
        StopDrawing()
        If color <> transparentcolor
            StartDrawing(ImageOutput(dst))
                Plot(x + xx, y+ yy, color)
            StopDrawing()
        EndIf   
    Next
Next    


EndProcedure
GBeebe
Enthusiast
Enthusiast
Posts: 263
Joined: Sat Oct 09, 2004 6:52 pm
Location: Franklin, PA - USA
Contact:

Here is a faster method

Post by GBeebe »

Code: Select all

Procedure ImgDraw(srcImage, dstImage, x, y, ClearColor = -1)
    w = ImageWidth(srcImage)
    h = ImageHeight(srcImage)
    *tmp = AllocateMemory(w * h * 4) ;temporary memory for source image data
    StartDrawing(ImageOutput(srcImage))
    ;loop through the image to collect data
        For a = 0 To w-1
            For b = 0 To h-1
                c.l = Point(a, b) ;get the color
                PokeL(*tmp + ((b * w)  + (a)) * 4 , c)    ;save the color
            Next
        Next
    StopDrawing()
    ;draw the temporary image data on the destination    
    StartDrawing(ImageOutput(dstImage))
        For a = 0 To w-1
            For b = 0 To h-1
               c = PeekL(*tmp + ((b * w)  + (a)) * 4)    ;read the color
               If c <> ClearColor
                    Plot(x + (a-1), y + (b-1), c)
                EndIf   
            Next
        Next
    StopDrawing()
    FreeMemory(*tmp) ;clean up
EndProcedure


If OpenWindow(0, 0, 0, 210, 210, "ImgDraw", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
       
    src = LoadImage(#PB_Any, "test.bmp")
    dst = CreateImage(#PB_Any, 200, 200)
    StartDrawing(ImageOutput(dst))
        Box(0, 0, ImageWidth(dst), ImageHeight(dst), RGB(255, 0, 255))
    StopDrawing()
    
    ImgDraw(src, dst, 50, 50, 0)
    
    ImageGadget(#PB_Any, 5, 5, 200, 200, ImageID(dst))
    
    Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
  EndIf
User avatar
Kapslok
User
User
Posts: 34
Joined: Tue Sep 01, 2009 2:29 pm
Location: Finland

Re: DrawImage with transparent color?

Post by Kapslok »

Code: Select all

; inside start-stopdrawing pair
; loads imagedata to *adr Not bigger than 256x256 images
Procedure LoadSlowTransparentImage(*adr,x,y,wid,hei)

   Protected x2,y2,x3
   Protected wid2,modu

   If wid<1 Or hei<1
      ProcedureReturn 0
   EndIf
   
   If wid*hei>256*256
      ProcedureReturn 0
   EndIf

   wid2=wid>>3
   modu=wid & 3

   PokeW(*adr,wid) : *adr+2
   PokeW(*adr,hei) : *adr+2

   For y2=y To y+hei-1
      If wid2>0
         For x2=x To x+(wid2-1)<<3
            PokeL(*adr,Point(x2,y2)) : *adr+4 : x2+1
            PokeL(*adr,Point(x2,y2)) : *adr+4 : x2+1
            PokeL(*adr,Point(x2,y2)) : *adr+4 : x2+1
            PokeL(*adr,Point(x2,y2)) : *adr+4 : x2+1

            PokeL(*adr,Point(x2,y2)) : *adr+4 : x2+1
            PokeL(*adr,Point(x2,y2)) : *adr+4 : x2+1
            PokeL(*adr,Point(x2,y2)) : *adr+4 : x2+1
            PokeL(*adr,Point(x2,y2)) : *adr+4 
         Next
      EndIf
      If modu>0
         For x3=x2 To x2+modu-1
            PokeL(*adr,Point(x3,y2)) : *adr+4
         Next
      EndIf
   Next

EndProcedure


; Draws an image from memorybuffer
; It has to be loaded there with LoadTransparentImage(id,x,y,wid,hei)
Procedure DrawSlowTransparentImage(*adr,x,y,c)

   Protected x2,y2
   Protected wid,hei,d
   Protected x3,wid2,modu
   wid=PeekW(*adr) : *adr+2
   hei=PeekW(*adr) : *adr+2

   If wid=0 Or hei=0
      ProcedureReturn 0
   EndIf

   wid2=wid>>3
   modu=wid & 3

   ;CallDebugger. No, call God.
   
   For y2=y To y+hei-1
      If wid2>0
         For x2=x To x+(wid2-1)<<3
            d=PeekL(*adr) : *adr+4 : If d<>c : Plot(x2,y2,d) : EndIf : x2+1
            d=PeekL(*adr) : *adr+4 : If d<>c : Plot(x2,y2,d) : EndIf : x2+1
            d=PeekL(*adr) : *adr+4 : If d<>c : Plot(x2,y2,d) : EndIf : x2+1
            d=PeekL(*adr) : *adr+4 : If d<>c : Plot(x2,y2,d) : EndIf : x2+1

            d=PeekL(*adr) : *adr+4 : If d<>c : Plot(x2,y2,d) : EndIf : x2+1
            d=PeekL(*adr) : *adr+4 : If d<>c : Plot(x2,y2,d) : EndIf : x2+1
            d=PeekL(*adr) : *adr+4 : If d<>c : Plot(x2,y2,d) : EndIf : x2+1
            d=PeekL(*adr) : *adr+4 : If d<>c : Plot(x2,y2,d) : EndIf 
         Next
      EndIf
      If modu>0
         For x3=x2 To x2+modu-1
            d=PeekL(*adr) : *adr+4 : If d<>c : Plot(x3,y2,d) : EndIf 
         Next
      EndIf
   Next

EndProcedure


; Does the whole procedure. Outside of the start-stopdrawing. As slow as it can get ;)
Procedure SlowTransparentImage(output,img,x,y,c)

   StartDrawing(ImageOutput(img))
   LoadSlowTransParentImage(*imagebuffer,0,0,ImageWidth(img),ImageHeight(img))
   StopDrawing()
   StartDrawing(output)
   DrawSlowTransparentImage(*imagebuffer,x,y,c)
   StopDrawing()

EndProcedure
It seems that oldstyle optimization helps but not much. I ended up with very similar solution to yours.
And I noticed that Linux seems to be faster with point & plot... atleast on this machine.

BTW: Ever thought of manipulating the imagedata directly? That would be fast. There was a code in some
archives how you could create bmp-image to memory and then use CatchImage... That might be pretty fast
and also platformindependent.
GBeebe
Enthusiast
Enthusiast
Posts: 263
Joined: Sat Oct 09, 2004 6:52 pm
Location: Franklin, PA - USA
Contact:

Re: DrawImage with transparent color?

Post by GBeebe »

I was thinking, Instead of saving the image to data, then writing the data over an image, I could possibly read the pixel data of one image and put it on another image's pixel data. I've done this with SDL sprites, but I don't know how to get the pointer to the pixel data of an image.

Also, Kapslok, I fail to understand why you are poking the same thing 8 times.
User avatar
Kapslok
User
User
Posts: 34
Joined: Tue Sep 01, 2009 2:29 pm
Location: Finland

Re: DrawImage with transparent color?

Post by Kapslok »

Also, Kapslok, I fail to understand why you are poking the same thing 8 times.
Back in days when even jumping in the code (such as for-next loop) took Cpu-cycles, it was necessary to reduce the for-next loop and add more operations inside it. This is a low-level optimization, but I didn't really see much improvement with it.

For TheAmount....
Movedata
next...

could be optimized to:

for TheAmount/4
Movedata
movedata
movedata
movedata
next

This way you reduce the amount of "next" instructions which the processor will go through. Only one fourth of the next instructions are executed.

But as I said, It doesn't seem to speed up much nowadays.
I was thinking, Instead of saving the image to data, then writing the data over an image, I could possibly read the pixel data of one image and put it on another image's pixel data. I've done this with SDL sprites, but I don't know how to get the pointer to the pixel data of an image.
Good idea, I'd go for that too. And there was a very simple way to access image data via a windows API function. It can't be much more complex on Linux. Is there anyone who knows how to do this?
akj
Enthusiast
Enthusiast
Posts: 665
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Re: DrawImage with transparent color?

Post by akj »

@Gbeebe:

I have enhanced your ImgDraw() routine in two ways:
1. If the source image is larger than the destination image, the program no longer crashes. Instead the image is clipped to size.
2. If the ClearColor is specified as a negative number, the transparent colour is set to that of one of the four corner pixels of the source image. For details see the comments in the enhanced procedure below.

Code: Select all

Procedure ImgDraw(srcImage, dstImage, x, y, ClearColor=-1)
; Draw image with a transparent colour
Protected dw, dh, w, h, *tmp, a, b, c.lProtected dw, dh, dw0, dh0, w, h, sw0, sh0, *tmp, a, b, c.l
StartDrawing(ImageOutput(srcImage))
w = OutputWidth(): h = OutputHeight()
; Determine the transparent colour
If ClearColor<0
  ; Use a corner pixel to set the transparent colour
  ; The ordering of corners (-1..-4) is anticlockwise from the top left
  Select ClearColor
  Case -2 ; Bottom left
    ClearColor = Point(0, h-1)
  Case -3 ; Bottom right
    ClearColor = Point(w-1, h-1)
  Case -4 ; Top right
    ClearColor = Point(w-1, 0)
  Default ; Top left
    ClearColor = Point(0, 0)
  EndSelect
EndIf
; If required, clip the image areas
dw = ImageWidth(dstImage): dh = ImageHeight(dstImage)
; Clip destination
If x>=0: dw0 = x: Else: dw0 = 0: EndIf
If y>=0: dh0 = y: Else: dh0 = 0: EndIf
; Clip source
If x>=0: sw0 = 0: Else: sw0 = -x: w + x: EndIf
If y>=0: sh0 = 0: Else: sh0 = -y: h + x: EndIf
If w>dw-dw0: w = dw-dw0: EndIf
If h>dh-dh0: h = dh-dh0: EndIf
If w<=0 Or h<=0: StopDrawing(): ProcedureReturn: EndIf
*tmp = AllocateMemory(w*h*4) ; Temporary memory for source image data
; Loop through the image to collect data
For a = 0 To w-1
  For b = 0 To h-1
    c = Point(a+sw0, b+sh0) ; Get the color
    PokeL(*tmp + (b*w+a)*4, c)    ; Save the color
  Next
Next
StopDrawing()
; Draw the temporary image data on the destination
StartDrawing(ImageOutput(dstImage))
For a = 0 To w-1
  For b = 0 To h-1
   c = PeekL(*tmp + (b*w+a)*4)    ; Read the color
   If c <> ClearColor
      Plot(a+dw0, b+dh0, c)
    EndIf
  Next
Next
StopDrawing()
FreeMemory(*tmp) ; Clean up
EndProcedure
Anthony Jordan
GBeebe
Enthusiast
Enthusiast
Posts: 263
Joined: Sat Oct 09, 2004 6:52 pm
Location: Franklin, PA - USA
Contact:

Re: DrawImage with transparent color?

Post by GBeebe »

I used a negative number for ignore clear color. So if one is not supplied then no color is used as the clear color.
When drawing falls off an image, the program shouldn't crash, the drawing should be ignored.
akj
Enthusiast
Enthusiast
Posts: 665
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Re: DrawImage with transparent color?

Post by akj »

@GBeebe:

It crashes in PB 4.40 when the 'drawing falls off an image' because of the way in which Point() and Plot() now work.
They are faster than in 4.30, but less robust.
Anthony Jordan
GBeebe
Enthusiast
Enthusiast
Posts: 263
Joined: Sat Oct 09, 2004 6:52 pm
Location: Franklin, PA - USA
Contact:

Re: DrawImage with transparent color?

Post by GBeebe »

Ah, I've been using 4.31... Good job.
Post Reply