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

Share your advanced PureBasic knowledge/code with the community.
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

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

Post 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
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

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

Post by wilbert »

How about simply draw the 32 bit image onto the 24 bit image ?
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

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

Post 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 :))
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

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

Post 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.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

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

Post 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 :(
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

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

Post 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:
Windows (x64)
Raspberry Pi OS (Arm64)
Post Reply