Page 2 of 2

Posted: Fri Sep 09, 2005 1:16 pm
by MadMax
Isn't it possible to copy the memory backwards?
It's perfectly possible, you only need to read and dump the x positions in reverse order.

Posted: Sat Sep 10, 2005 3:54 am
by Fou-Lu
Then there's no problem in mirroring a sprite. Now we just need someone who knows how to do that... :roll:

Posted: Thu Oct 06, 2005 5:46 pm
by zikitrake
What fails in this code?? ( I'm using 16bits ImageDeph(), with 32bits works fine )

When I push Vertical Flip, the image turn in black.

If I push Horizontal Flip, the image appears distorted
fweil wrote:AJirenius,

Here is a sample code that allow to H/V flip an image.

The main part manages the H/V flip by pushing H and V keyboard keys.

It uses API image structures for a fast memory dump of theprocefore image bessing pixels in memory instead of using Point() and Plot() commands.

This is easy to use with any image, gadget image or sprite.

Code: Select all

Enumeration
  #Window_Main
  #Gadget_Image
  #Image
EndEnumeration

Procedure Create_Image(ImageWidth, ImageHeight)
  ImageID = CreateImage(#Image, ImageWidth, ImageHeight)
  StartDrawing(ImageOutput())
    Box(0, 0, ImageWidth, ImageHeight, #Black)
    For i = 0 To 10000
      Plot(Random(ImageWidth), Random(ImageHeight), Random($FFFFFF))
    Next
    DrawingMode(1)
    BackColor(0, 0, 0)
    FrontColor(255, 255, 255)
    Locate(20, 20)
    DrawText("Image sample")
  StopDrawing()
  ProcedureReturn ImageID
EndProcedure

Procedure Image_To_Memory(Image, ImageWIdth, ImageHeight, ImageDepth, Address)
  hBmp = UseImage(Image)
  hDC = StartDrawing(ImageOutput())
    bmi.BITMAPINFO
    bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
    bmi\bmiheader\biWidth = ImageWidth
    bmi\bmiheader\biHeight = ImageHeight
    bmi\bmiheader\biPlanes = 1
    bmi\bmiheader\biBitCount = ImageDepth
    bmi\bmiheader\biCompression = #BI_RGB
    GetDIBits_(hDC, hBmp, 1, ImageHeight, Address, bmi, #DIB_RGB_COLORS)
    Dim Undo(ImageWidth, ImageHeight)
    CopyMemory(Address, @Undo(), (ImageWidth * ImageHeight - 1) * 4)
  StopDrawing()
EndProcedure

Procedure Memory_To_Image(Address, Image, ImageWIdth, ImageHeight, ImageDepth)
  hBmp = CreateImage(Image, ImageWidth, ImageHeight)
  hDC = StartDrawing(ImageOutput())
    bmi.BITMAPINFO
    bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
    bmi\bmiheader\biWidth = ImageWidth
    bmi\bmiheader\biHeight = ImageHeight
    bmi\bmiheader\biPlanes = 1
    bmi\bmiheader\biBitCount = ImageDepth
    bmi\bmiheader\biCompression = #BI_RGB
    SetDIBits_(hDC, hBmp, 1, ImageHeight, Address, bmi, #DIB_RGB_COLORS)
  StopDrawing()
  ProcedureReturn hBmp
EndProcedure

;
; An horizontal flip consists in flipping the array
; For a fast rendering and a short source code, I prefer to use a set of two arrays
;
Procedure Image_Horizontal_Flip(Image.l)
  UseImage(Image)
  ImageWidth = ImageWidth()
  ImageHeight = ImageHeight()
  ImageDepth = ImageDepth()
  Dim Pixels1(ImageHeight - 1, ImageWidth - 1)
  Dim Pixels2(ImageHeight - 1, ImageWidth - 1)
  Image_To_Memory(Image, ImageWidth, ImageHeight, ImageDepth, @Pixels1())
  For x = 0 To ImageWidth - 1
    For y = 0 To ImageHeight - 1
      Pixels2(y, x) = Pixels1(y, ImageWidth - 1 - x)
    Next
  Next
  ProcedureReturn Memory_To_Image(@Pixels2(), Image, ImageWidth, ImageHeight, ImageDepth)
EndProcedure

;
; A vertical flip consists in flipping the array
; As for horizontal flip, for a fast rendering and a short source code, I prefer to use a set of two arrays
;
Procedure Image_Vertical_Flip(Image.l)
  UseImage(Image)
  ImageWidth = ImageWidth()
  ImageHeight = ImageHeight()
  ImageDepth = ImageDepth()
  Dim Pixels1(ImageHeight - 1, ImageWidth - 1)
  Dim Pixels2(ImageHeight - 1, ImageWidth - 1)
  Image_To_Memory(Image, ImageWidth, ImageHeight, ImageDepth, @Pixels1())
  For x = 0 To ImageWidth - 1
    For y = 0 To ImageHeight - 1
      Pixels2(y, x) = Pixels1(ImageHeight - 1 - y, x)
    Next
  Next
  ProcedureReturn Memory_To_Image(@Pixels2(), Image, ImageWidth, ImageHeight, ImageDepth)
EndProcedure


  WindowWidth = 640
  WindowHeight = 480
  ImageWidth = WindowWidth - 20
  ImageHeight = WindowHeight - 20
  If OpenWindow(#Window_Main, 0, 0, WindowWidth, WindowHeight, #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget | #PB_Window_TitleBar | #PB_Window_ScreenCentered, "MyWindow")
      AddKeyboardShortcut(#Window_Main, #PB_Shortcut_Escape, #PB_Shortcut_Escape)
      AddKeyboardShortcut(#Window_Main, #PB_Shortcut_H, #PB_Shortcut_H)
      AddKeyboardShortcut(#Window_Main, #PB_Shortcut_V, #PB_Shortcut_V)
      If CreateGadgetList(WindowID(#Window_Main))
          ImageGadget(#Gadget_Image, 10, 10, ImageWidth, ImageHeight, Create_Image(ImageWidth, ImageHeight))
      EndIf
      Quit = #False
      Repeat
        Select WaitWindowEvent()
          Case #PB_Event_CloseWindow
            Quit = #True
          Case #PB_Event_Menu
            Select EventMenuID()
              Case #PB_Shortcut_Escape
                Quit = #True
              Case #PB_Shortcut_H
                SetGadgetState(#Gadget_Image, Image_Horizontal_Flip(#Image))
              Case #PB_Shortcut_V
                SetGadgetState(#Gadget_Image, Image_Vertical_Flip(#Image))
            EndSelect
        EndSelect
      Until Quit
  EndIf
  
  CallDebugger
End

Posted: Thu Oct 06, 2005 11:37 pm
by blueznl
i think i posted it before... anyway...

Code: Select all

; purebasic survival guide - pb3.93
; graphics 6.pb - 27.02.2005 ejn (blueznl)
; http://www.xs4alnl/~bluez/datatalk/pure1.htm
;
; - mirroring a bitmap in memory
; - reading a bitmap file structure without purebasic commands
; - using images in a datasection
;
w_main_nr = 1
w_main_h = OpenWindow(w_main_nr,10,10,245,200,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"test")
;
; remember, reading from a file or from memory is basically the same thing, now if the image
; is already in memory, i can rotate it in memory, at least that's the theory :-)
; 
; let's draw something first
;
image1_h = CatchImage(2,?image1_data)
StartDrawing(WindowOutput())
DrawImage(image1_h,10,10)
StopDrawing()
;
;
; checking the size of the image told me, that it was exactly the same size as the file, as expected :-)
;
;   Debug ?image2_data_end - ?image2_data
;
; now the trick is: what's inside that file ie. inside that bitmap? a little search on the internet
; showed the following...
;
; a bitmap is always build up with four parts:
;
; - bitmapfileheader
; - bitmapinfoheader
; - rgbquad
; - byte
;
; let's start with the file header
;
*bitmapfileheader.BITMAPFILEHEADER            ; actually, i only care about the offset
*bitmapfileheader = ?image1_data
;
; Debug *bitmapfileheader\bfType              ; should always report 19778
; size = *bitmapfileheader\bfSize             ; size of whole structure including headers
;
offset = *bitmapfileheader\bfOffBits          ; this is where bitmap data is supposed to be
;
*bitmapinfoheader.BITMAPINFOHEADER            
*bitmapinfoheader = *bitmapfileheader+SizeOf(BITMAPFILEHEADER)
; 
; If *bitmapinfoheader\biCompression = 0      ; check for compressed images
; EndIf                                       ; not implemented 
;
image1_width = *bitmapinfoheader\biWidth      ; size
image1_height = *bitmapinfoheader\biHeight    ; 
bits_pixel = *bitmapinfoheader\biBitCount     ; bits per pixel
bytes_pixel = bits_pixel/8                    ; bytes per pixel
bytes_row = image1_width*bytes_pixel          ; bytes per row (unadjusted)
bytes_row = bytes_row+(bytes_row % 4)         ; padd to multiples of 4
;
; colour table size depends on the number of bits per pixel
;
; - 1     - colour table has two entries
; - 4     - colour table has 16 entries
; - 8     - colour table has 256 entries
; - 24    - colour table has no entries
;
; Select pixel_bits
;   Case 24
;     colourtable_size = 0    
;   Default
;     colourtable_size = Pow(2,pixel_bits) * 4
; EndSelect
; offset = 54+colourtable_size
;
; you can calculate the position of the first pixel, or use the value we found before
;
; so the first pixel must be at image2_data+offset
; well we now know where it is so we can change it!
;
; let's give the image a blue stripe on one side, why not?
;
*p = *bitmapfileheader+offset
For y = 0 To image1_width-1
  For x = 0 To image1_width / 2
    PokeB(*p+y*bytes_row+x*bytes_pixel,255)
  Next x
Next y
;
; and show it...
;
image1_h = CatchImage(2,?image1_data)
StartDrawing(WindowOutput())
DrawImage(image1_h,90,10)
StopDrawing()
;
; note that i draw directly on the window, so the displayed contents will be overwritten if i move another window over it
; unless i take care of refresh myself... which i do not here :-)
;
; now let's mirror it
;
For y = 0 To image1_height-1
  For x = 0 To Int(image1_width/2)
    Select bits_pixel
      Case 1                              ; you add the variants yourself
      Case 2
      Case 4
      Case 8
      Case 24                             ; 24 bits rgb
        ;
        ; where are those darn pixels
        ;
        *p1.BYTE = *p+y*bytes_row+x*3
        *p2.BYTE = *p+y*bytes_row+(image1_width-x-1)*3
        ;
        ; now swap 'm... blue...
        ;
        b = *p1\b
        *p1\b = *p2\b
        *p2\b = b
        ;
        ; green...
        ;
        g = *p1\b
        *p1\b = *p2\b
        *p2\b = g
        ;
        ; and red...
        ;
        r = *p1\b
        *p1\b = *p2\b
        *p2\b = r
        ;
    EndSelect
  Next x
Next y
;
; and show it one more time
;
image1_h = CatchImage(2,?image1_data)
StartDrawing(WindowOutput())
DrawImage(image1_h,170,10)
StopDrawing()
;
Repeat
  event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow Or event = 513
;
; store the image in a datasection
;
DataSection
;
image1_data:
IncludeBinary("graphics\lightcircle.bmp")
image1_data_end:
;
EndDataSection


Posted: Fri Oct 07, 2005 7:52 am
by zikitrake
Hi Blueznl, thank you for your code... but... I want to use IMAGE_TO_MEMORY() procedure to store a image in an array IMAGE(width,height) format.

Any idea?

Thank you again.