Flip/reverse image row order so first pixel is top-left
Posted: Fri Mar 18, 2016 2:34 am
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:

Here is another version of the function, but for 8bit buffers:
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

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