Flip/reverse image row order so first pixel is top-left

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

Flip/reverse image row order so first pixel is top-left

Post by Keya »

when you start modifying the buffer at DrawingBuffer() you start modifying from the bottom-left pixel (in Windows that is; its normal top-left in Linux/OSX, thanks wilbert!), but i needed the top-left pixel to be the first pixel (human order instead of machine order!) so row-flipping was required i guess??? I know you can simply read from the other end in reverse order instead, but flipped rows just makes things easier for some things. Its easy enough but i couldn't find any existing examples so here's what i came up with. Call twice to restore original order. Note it is a Horizontal Flip (not a 180° Rotation) - byte order is preserved and pixels remain left-to-right.

Sample image pixel bytes @ DrawingBuffer() in Windows for a 6x3 image. The 0 bytes exist at the end of each row if row widths aren't aligned, which is why the need for DrawingBufferPitch() instead of ImageWidth() to get the physical row width in bytes:

Code: Select all

Before:  13 14 15 16 17 18 0  0
         7  8  9  10 11 12 0  0
         1  2  3  4  5  6  0  0

After:   1  2  3  4  5  6  0  0
         7  8  9  10 11 12 0  0
         13 14 15 16 17 18 0  0
Image

Code: Select all

EnableExplicit

Procedure FlipBufferRows(hImg)
  Protected *pbuf, *psrc, *ptmp, *pdst, width, height, i 
  If StartDrawing(ImageOutput(hImg)) 
    *pbuf = DrawingBuffer()
    width = DrawingBufferPitch()
    height = ImageHeight(hImg) 
    *psrc = *pbuf
    *ptmp = AllocateMemory(width*height)       ;Temp buffer to write rows in reverse order
    If *ptmp
      *pdst = *ptmp + (width*height)-width
      For i = 0 To height-1
        CopyMemory(*psrc, *pdst, width)
        *pdst-width
        *psrc+width
      Next i
      CopyMemory(*ptmp, *pbuf, width*height)   ;Overwrite existing buffer with flipped buffer
      FreeMemory(*ptmp)                        ;Free temp buffer
    EndIf
    StopDrawing()
  EndIf
EndProcedure


Define hImgOrig, hImgFlip
If OpenWindow(0, 0, 0, 130, 90, "Flip Rows", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  hImgOrig = CreateImage(#PB_Any, 30, 30, 24, 0)
  StartDrawing(ImageOutput(hImgOrig))
  DrawingMode(#PB_2DDrawing_Gradient)      
  BackColor($000000)
  FrontColor($FFFFFF)
  LinearGradient(0, 0, 30, 30)    
  Box(0,0,30,30)
  StopDrawing()
  
  hImgFlip = CopyImage(hImgOrig, #PB_Any)  
  FlipBufferRows(hImgFlip)
  
  ImageGadget(0, 30, 30, 30, 30, ImageID(hImgOrig))
  ImageGadget(1, 70, 30, 30, 30, ImageID(hImgFlip))
  
  Repeat
  Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

Here is another version of the function, but for 8bit buffers:

Code: Select all

Procedure Flip8bitBufferRows(*pbuf, width, height)
  Protected *psrc, *ptmp, *pdst, i 
  *psrc = *pbuf
  *ptmp = AllocateMemory(width*height)       ;Temp buffer to write rows in reverse order
  If *ptmp
    *pdst = *ptmp + (width*height)-width
    For i = 0 To height-1
      CopyMemory(*psrc, *pdst, width)
      *pdst-width
      *psrc+width
    Next i
    CopyMemory(*ptmp, *pbuf, width*height)   ;Overwrite existing buffer with flipped buffer
    FreeMemory(*ptmp)                        ;Free temp buffer
  EndIf
EndProcedure
Last edited by Keya on Fri Mar 18, 2016 3:45 pm, edited 11 times in total.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Flip/reverse image row order so first pixel is top-left

Post by wilbert »

Keya wrote:when you start modifying the buffer at DrawingBuffer() you start modifying from the bottom-left pixel
Only Windows does this. OSX and Linux start from top-left pixel :)
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Flip/reverse image row order so first pixel is top-left

Post by Keya »

JUST SLIGHTLY IMPORTANT lol, good to now know thanks wilbert :)
User avatar
Michael Vogel
Addict
Addict
Posts: 2807
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Flip/reverse image row order so first pixel is top-left

Post by Michael Vogel »

Slightly modified the initial code from Keya to reduce memory usage. I'm quite sure this variant will be slower but shows what can be done with the Swap command (it is also useful to change from rgb to bgr format easily, therefore I kept the structure inside this code)...

Code: Select all

EnableExplicit

Structure rgbtype
	a.a
	r.a
	g.a
	b.a
EndStructure

Structure ColorType
	StructureUnion
		col.i
		rgb.rgbtype
	EndStructureUnion
EndStructure

Procedure FlipBufferRows(hImg)

	Protected *pbuf
	Protected *psrc.ColorType
	Protected *pdst.ColorType
	Protected width,height,bytes
	Protected i,j

	If StartDrawing(ImageOutput(hImg))
		*pbuf = DrawingBuffer()
		width = ImageWidth(hImg)
		bytes=width<<2
		height = ImageHeight(hImg)

		For i = 0 To height/2-1
			*psrc=*pbuf+i*bytes
			*pdst=*pbuf+(height-i-1)*bytes
			For j=0 To width-1
				Swap *psrc\col,*pdst\col
				*psrc+4
				*pdst+4
			Next j
		Next i
		StopDrawing()
	EndIf
EndProcedure

Define hImgOrig, hImgFlip
If OpenWindow(0, 0, 0, 130, 90, "Flip Rows", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	hImgOrig = CreateImage(#PB_Any, 30, 30, 32, 0)
	StartDrawing(ImageOutput(hImgOrig))
	DrawingMode(#PB_2DDrawing_Gradient)
	BackColor($000000)
	FrontColor($FFFFFF)
	LinearGradient(0, 0, 30, 30)
	Box(0,0,30,30)
	StopDrawing()

	hImgFlip = CopyImage(hImgOrig, #PB_Any)
	FlipBufferRows(hImgFlip)

	ImageGadget(0, 30, 30, 30, 30, ImageID(hImgOrig))
	ImageGadget(1, 70, 30, 30, 30, ImageID(hImgFlip))

	Repeat
	Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
Post Reply