Page 1 of 1

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

Posted: Fri Mar 18, 2016 2:34 am
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

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

Posted: Fri Mar 18, 2016 6:08 am
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 :)

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

Posted: Fri Mar 18, 2016 7:11 am
by Keya
JUST SLIGHTLY IMPORTANT lol, good to now know thanks wilbert :)

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

Posted: Fri Nov 23, 2018 7:43 pm
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