Page 1 of 1

Convert 32-bit image to 24-bit, dropping Alpha channel

Posted: Tue May 10, 2016 10:01 am
by Keya
plenty of room for improvement but i don't think it's too bad and i couldn't find any other routines for this (short of using SaveImage but i wanted a purely in-memory job that didn't require a codec). Only tested on Windows so far but should be multi-OS

Pseudo-usage:

Code: Select all

hImg32 = LoadImage(32bit image)
hImg24 = ConvertImage32to24(hImg32)
FreeImage(hImg32)
ImageGadget(ImageId(hImg24))

Code: Select all

EnableExplicit


Procedure.i ConvertImage32to24(hImg32)
  Protected width,height, stride32,stride24, hImg24, *buf32, *buf24, x,y, *p8_24.Ascii, *p8_32.Ascii
  If ImageDepth(hImg32) <> 32: ProcedureReturn 0: EndIf
  width = ImageWidth(hImg32)
  height = ImageHeight(hImg32)
  hImg24 = CreateImage(#PB_Any, width, height, 24)          ;Create empty 24bit image
  If hImg24 = 0: ProcedureReturn 0: EndIf  
  If StartDrawing(ImageOutput(hImg32)) = 0:
    FreeImage(hImg24)
    ProcedureReturn 0
  EndIf
  stride32 = DrawingBufferPitch()
  *buf32 = AllocateMemory(height*stride32)
  CopyMemory(DrawingBuffer(), *buf32, height*stride32)      ;Create copy of 32bit image buffer, may not be needed but its safe
  StopDrawing()
  If StartDrawing(ImageOutput(hImg24)) = 0:
    FreeMemory(*buf32):  FreeImage(hImg24)
    ProcedureReturn 0
  EndIf
  stride24 = DrawingBufferPitch()
  *buf24 = DrawingBuffer()
  For y = 0 To height-1                                     ;Copy RGB(skipping A) from 32bit buffer to 24bit buffer
    *p8_24 = *buf24 + (y * stride24)
    *p8_32 = *buf32 + (y * stride32)
    For x = 0 To width-1
      *p8_24\a = *p8_32\a  ;B
      *p8_24+1: *p8_32+1
      *p8_24\a = *p8_32\a  ;G
      *p8_24+1: *p8_32+1
      *p8_24\a = *p8_32\a  ;R
      *p8_24+1: *p8_32+2   ;A (skip)
    Next x
  Next y  
  StopDrawing()
  FreeMemory(*buf32)                                        ;Free copy of 32bit image buffer
  ProcedureReturn hImg24
EndProcedure



UsePNGImageDecoder()
Define hImg32 = LoadImage(#PB_Any, "C:\temp\beach32.png")
If hImg32
  Define hImg24 = ConvertImage32to24(hImg32)
  FreeImage(hImg32)
  If hImg24    
    If OpenWindow(0, 0, 0, 800, 600, "Convert 32bit image to 24bit", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
      ImageGadget(0, 0, 0, 800, 600, ImageID(hImg24))
      Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
    EndIf
    FreeImage(hImg24)
  Else
    MessageRequester("Error","Couldn't convert")
  EndIf
Else
  MessageRequester("Error","Couldn't load hImg32")
EndIf

Re: Convert 32-bit image to 24-bit, dropping Alpha channel

Posted: Tue May 10, 2016 10:14 am
by wilbert
How about simply draw the 32 bit image onto the 24 bit image ?

Re: Convert 32-bit image to 24-bit, dropping Alpha channel

Posted: Tue May 10, 2016 10:25 am
by Keya
It doesn't seem like you can just use CopyImage to do that - i know im not using #PB_Any properly with this call to CopyImage but you get the idea (it would just create/copy to a new 32bit image)

Code: Select all

Procedure.i ConvertImage32to24(hImg32)
  Protected width,height, stride32,stride24, hImg24, *buf32, *buf24, x,y, *p8_24.Ascii, *p8_32.Ascii
  If ImageDepth(hImg32) <> 32: ProcedureReturn 0: EndIf
  width = ImageWidth(hImg32)
  height = ImageHeight(hImg32)
  hImg24 = CreateImage(#PB_Any, width, height, 24)          ;Create empty 24bit image
  If hImg24 = 0: ProcedureReturn 0: EndIf  
  CopyImage(ImageID(hImg32), ImageID(hImg24))  ;error "The specified #Image isn't initialized"
  ProcedureReturn hImg24
EndProcedure
I hadn't thought of GrabImage etc but just having a quick try then it seems to be the same problem - can only copy to another 32bit image (it seems, but not 100% sure)
any ideas?
(hopefully none of the PB routines work for this or WON'T I LOOK A BIT STUPID, lol :))

Re: Convert 32-bit image to 24-bit, dropping Alpha channel

Posted: Tue May 10, 2016 10:33 am
by wilbert
What I meant was create a 24 bit image with CreateImage like you did and then use StartDrawing, DrawImage, StopDrawing to 'copy' the 32 bit image into the 24 bit image.
The default drawing mode should just copy the pixels and not blend them as far as I understand.

Re: Convert 32-bit image to 24-bit, dropping Alpha channel

Posted: Tue May 10, 2016 10:42 am
by Keya
ooh, you mean like this?

Code: Select all

Procedure.i ConvertImage32to24(hImg32)
  Protected width,height, hImg24
  If ImageDepth(hImg32) <> 32: ProcedureReturn 0: EndIf
  width = ImageWidth(hImg32)
  height = ImageHeight(hImg32)
  hImg24 = CreateImage(#PB_Any, width, height, 24)          ;Create empty 24bit image
  If hImg24 = 0: ProcedureReturn 0: EndIf  
  If StartDrawing(ImageOutput(hImg24)) = 0
    FreeImage(hImg24)
    ProcedureReturn 0
  EndIf
  DrawImage(ImageID(hImg32),0,0,width,height)
  StopDrawing()
  ProcedureReturn hImg24
EndProcedure
Yes, that works fine...... DAMNIT!
It appears to be 4x faster too. I go cry now :(

Re: Convert 32-bit image to 24-bit, dropping Alpha channel

Posted: Tue May 10, 2016 11:17 am
by wilbert
Keya wrote:Yes, that works fine...... DAMNIT!
It appears to be 4x faster too. I go cry now :(
That's indeed the method I meant :)
And no asm required this time to speed things up :wink: