drawing

Just starting out? Need help? Post your questions and find answers here.
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

drawing

Post by ZX80 »

Hello, all.

I'm looking for a way to copy the raw data memory buffer into the context StartDrawing(ImageOutput(ImageNr)). Is it possible? Something like BitBlt_
Before copying, I also wanted to clarify two points. Can I change the size of the StartDrawing(ImageOutput(ImageNr)) context buffer? Is it possible to select the buffer area/address where to copy the raw-data?

added:
I understand that the buffer size can be changed with

Code: Select all

hImage = CreateImage(ImageNr, Width, Height)
By resizing the canvas, you are changing the size of the buffer. Okay.
With

Code: Select all

*Buffer = DrawingBuffer()
you get the address of the buffer. Okay.
But how can I copy a piece of my raw-data to an arbitrary place there?
Last edited by ZX80 on Sun Mar 13, 2022 8:12 pm, edited 1 time in total.
User avatar
STARGÅTE
Addict
Addict
Posts: 2226
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: drawing

Post by STARGÅTE »

The context buffer can be received with DrawingBuffer().
You can read and write in it.
Additional commands like DrawingBufferPitch() or DrawingBufferPixelFormat() give you more informations about the buffer, like the buffer pitch and the pixel format.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: drawing

Post by ZX80 »

Good time, STARGÅTE.

Oh, while I completed my first post, you already answered. Thank you.
Yes, I know about these commands, thanks.
I'm guessing, I need to describe my task in more detail. I will try...

added:
I have to show it in code. I'm sorry, but I need to think. Although I have the base. Can we leave it until tomorrow? Now I have midnight (and another 30 minutes). Thank you.
Last edited by ZX80 on Sun Mar 13, 2022 8:30 pm, edited 1 time in total.
User avatar
STARGÅTE
Addict
Addict
Posts: 2226
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: drawing

Post by STARGÅTE »

ZX80 wrote: Sun Mar 13, 2022 7:21 pm But how can I copy a piece of my raw-data to an arbitrary place there?
If the pixel format and the pitch matches, you can use CopyMemory(*RawData, DrawingBuffer() + Offset, Size), while *RawData is you buffer, Offset is an arbitrary offset in the drawing buffer and Size the length of the copied data.
If the pixel format or the pitch do not match, the result is just nonsense.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: drawing

Post by ZX80 »

STARGÅTE,

thanks again for your help. This is useful. I'll try tomorrow and write a report here. I have updated my previous post. Again, I'm sorry I can't continue now. Didn't expect such a quick response.
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: drawing

Post by ZX80 »

Hello, all.
STARGÅTE, are you still here?

This is the first approximation. Hastily and dirty (not clean). But this example shows what I need. There is something wrong with my math. Could you take a look? I am attaching a screenshot of the problem.

That's what it's about:

Code: Select all

#max_number_of_frames = 5
Global.i FrameSize, *mem

Procedure MakeDesktopScreenshot(ImageNr, x, y, Width, Height, SnapshotNr)
  Protected hImage, hDC, hWnd, DeskDC
  Protected *Buffer, *mem_ptr, Pitch
  
  hImage = CreateImage(ImageNr, Width, Height)
  If hImage
    hDC = StartDrawing(ImageOutput(ImageNr))
    If hDC
      hWnd=GetDesktopWindow_()
      DeskDC = GetDC_(hWnd) 
      BitBlt_(hDC, 0, 0, Width, Height, DeskDC, x, y, #SRCCOPY) 
      
      *Buffer = DrawingBuffer()
      
      If SnapshotNr = 1
        Pitch = DrawingBufferPitch()
        FrameSize = Pitch * Height  ;ImageHeight(ImageNr)
        *mem = AllocateMemory(FrameSize * #max_number_of_frames)
      EndIf

      If *mem = 0
        hImage = 0
      Else
        *mem_ptr = *mem + (FrameSize * (#max_number_of_frames - SnapshotNr))
        CopyMemory(*Buffer, *mem_ptr, FrameSize)
      EndIf
      
      StopDrawing()
      ReleaseDC_(hWnd, DeskDC)
    Else
      FreeImage(ImageNr)
      hImage = 0
    EndIf
  EndIf
  
  ProcedureReturn hImage
EndProcedure

Procedure CreateFinalizeSnapshot(ImageNr, Width, Height, SnapshotNr)
  Protected *mem_ptr, hImage, hDC
  
  hImage = CreateImage(ImageNr, Width, Height * SnapshotNr)
  If hImage
    hDC = StartDrawing(ImageOutput(ImageNr))
    If hDC
      *mem_ptr = *mem + (FrameSize * (#max_number_of_frames - SnapshotNr))
      CopyMemory(*mem_ptr, DrawingBuffer(), FrameSize * SnapshotNr)
      StopDrawing()
    Else
      FreeImage(ImageNr)
      hImage = 0
    EndIf
  EndIf
  
  ProcedureReturn hImage
EndProcedure


#const_x = 264
#const_y = 183
#const_w = 1322
#const_h = 655

UsePNGImageEncoder()

Sleep_(1500)
If MakeDesktopScreenshot(0, #const_x, #const_y, #const_w, #const_h, 1)
  Beep_(2000, 400)
  Sleep_(5000) ;time to change screen
  If MakeDesktopScreenshot(0, #const_x, #const_y, #const_w, #const_h, 2)
    If CreateFinalizeSnapshot(0, #const_w, #const_h, 2)
      SaveImage(0, "c:\-\-\test.png", #PB_ImagePlugin_PNG)
    EndIf
  EndIf
EndIf
If *mem
  FreeMemory(*mem)
EndIf
P.S. This is not my ultimate goal. This is just the first step. I need more time to think about how to take the next step. I understand what needs to be done, but I don't know how. But first I need to fix my math. Please, HELP!

Thank you in advance.

P.S.2. Lines 33 and 34 in the picture are the border where the two frames "meet". It does not depend on me. There was enough time to scroll through the text.
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: drawing

Post by ZX80 »

Hello, all.

If someone has time, please take a look at the code. What's wrong here? I almost always get 'Addr' equal to zero. Why?
Only if I scroll the text a few lines do I get the address. But now I have almost 33 lines in the frame. And if you scroll the text by 30 lines, it no longer works. :shock:
Is my math really wrong? I just don't see where?

Code: Select all

#max_number_of_frames = 5
#overlap_lines = 3
Global.i FrameSize, *mem
Global.i SearchPatternSize, *SearchPattern

Procedure FindOverlap(*buff)
  Protected i, n, result
 
  n = FrameSize - SearchPatternSize
  For i = 0 To n
    If CompareMemory(*buff+i, *SearchPattern, SearchPatternSize)
      result = *buff+i
      Break
    EndIf
  Next i
  
  ProcedureReturn result
EndProcedure

Procedure MakeDesktopScreenshot(ImageNr, x, y, Width, Height, SnapshotNr)
  Protected hImage, hDC, hWnd, DeskDC, Addr
  Protected *Buffer, *mem_ptr, Pitch
  
  hImage = CreateImage(ImageNr, Width, Height)
  If hImage
    hDC = StartDrawing(ImageOutput(ImageNr))
    If hDC
      hWnd=GetDesktopWindow_()
      DeskDC = GetDC_(hWnd) 
      BitBlt_(hDC, 0, 0, Width, Height, DeskDC, x, y, #SRCCOPY) 
      
      *Buffer = DrawingBuffer()
      
      If SnapshotNr = 1
        Pitch = DrawingBufferPitch()
        FrameSize = Pitch * Height  ;ImageHeight(ImageNr)
        *mem = AllocateMemory(FrameSize * #max_number_of_frames)
        SearchPatternSize = Pitch * #overlap_lines
        *SearchPattern = AllocateMemory(SearchPatternSize)
      EndIf

      If *mem = 0 Or *SearchPattern = 0
        hImage = 0
      Else
        If SnapshotNr = 1
          *mem_ptr = *mem + (FrameSize * (#max_number_of_frames - SnapshotNr))
          CopyMemory(*Buffer, *mem_ptr, FrameSize)
          CopyMemory(*mem_ptr + FrameSize - SearchPatternSize, *SearchPattern, SearchPatternSize)
        Else
          Addr = FindOverlap(*Buffer)
          Debug Addr
        EndIf
      EndIf
      
      StopDrawing()
      ReleaseDC_(hWnd, DeskDC)
    Else
      FreeImage(ImageNr)
      hImage = 0
    EndIf
  EndIf
  
  ProcedureReturn hImage
EndProcedure


#const_x = 264
#const_y = 183
#const_w = 1322
#const_h = 655

Sleep_(1500)
If MakeDesktopScreenshot(0, #const_x, #const_y, #const_w, #const_h, 1)
  Beep_(2000, 400)
  Sleep_(5000) ;time to change frame
  If MakeDesktopScreenshot(0, #const_x, #const_y, #const_w, #const_h, 2)
    ; to do
  EndIf
EndIf
If *mem
  FreeMemory(*mem)
EndIf
If *SearchPattern
  FreeMemory(*SearchPattern)
EndIf
User avatar
STARGÅTE
Addict
Addict
Posts: 2226
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: drawing

Post by STARGÅTE »

I don't understand, what you want to try.
If you just want to draw multiple images into a larger one, just create multiple images (screenshots) and then use DrawImage() to draw them all into the larger one.
Using the DrawingBuffer can make a lot of trouble, if the buffer is Y-flipped (#PB_PixelFormat_ReversedY) or the pitches do not match.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: drawing

Post by ZX80 »

Good time, STARGÅTE.
If you just want to draw multiple images into a larger one, just create multiple images (screenshots) and then use DrawImage() to draw them all into the larger one.
This is not exactly what I need. I'm trying to merge two frames into one. To do this, I have to figure out where the border is. The second frame is taken with a small allowance. That is, the beginning of the second frame must contain a part from the end of the first frame. Overlay / overlap. I decided that three lines would be enough to reliably determine the boundary (no mistake). As a result, I try to glue or stitch two frames. No seams. This is something like a panorama, only vertical. This idea came to me from the 'HyperSnap' program.
Using the DrawingBuffer can make a lot of trouble, if the buffer is Y-flipped (#PB_PixelFormat_ReversedY) or the pitches do not match.
Do not worry. It's all right here. All frames will be of the same specified size and format. I just have problems with memory lookup, but I don't understand why?

added:
I don't want to save two separate files to disk before gluing them together to then once again save the resulting snapshot to disk. I prefer to work with raw data.
User avatar
JHPJHP
Addict
Addict
Posts: 2250
Joined: Sat Oct 09, 2010 3:47 am

Re: drawing

Post by JHPJHP »

Hi ZX80,

It seems like you may already have a viable solution, but I'll post this anyways... Stitch Images: SIFT.

NOTE: The free version may not fit your preference of working with raw data.

The free download includes both DLL and EXE examples that accomplish the same result, stitching images together.
In order to have a near seamless stitch, a Laplacian blending algorithm is applied during the stitch process.

While the free version cannot be modified from a horizontal stitch, it should be easy enough to first rotate the two images, stitch them together, then rotate the newly created stitched image to vertical.

Again, just a thought :)

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: drawing

Post by ZX80 »

Hello, dear JHPJHP.

Thanks for your reply. I really appreciate it.

Okay. Yes, it requires more work and external additional files. However, I checked your version but couldn't get it to work. I downloaded the free version from your site. Every time after running your code I get the same message: "icon file not found". And no matter what "StitchImages_DLL.pb", what "StitchImages_EXE.pb".

In fact, the task is simple: find given pattern in the buffer. And it works well with text('FindOverlap' procedure), I tested it. Why there are problems with snapshot, I do not understand. Only in this case, the pattern is not text, but a set of pixels. But if we are looking for pixels or text, what does it matter? In the end, it's just a part of memory.

As I said earlier, these are two pictures not from different places. This is just a screenshot of the same screen, but shifted one frame down. There is no need of complicated calculations, but simple memory search. Actually, it's absolutely clear even without any complex calculations. Therefore, I think your approach in this case is redundant and unnecessarily complicated. Sorry.

Thanks again for your answer.
User avatar
Demivec
Addict
Addict
Posts: 4259
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: drawing

Post by Demivec »

ZX80 wrote: Tue Mar 15, 2022 6:49 pm Hello, all.

If someone has time, please take a look at the code. What's wrong here? I almost always get 'Addr' equal to zero. Why?
Only if I scroll the text a few lines do I get the address. But now I have almost 33 lines in the frame. And if you scroll the text by 30 lines, it no longer works. :shock:
Is my math really wrong? I just don't see where?

In examining but not testing your code I see several potential problems. In looking at the FindOverlap() procedure, I've made comments in the procedure of some concerns:

Code: Select all

Procedure FindOverlap(*buff)
  Protected i, n, result
 
  n = FrameSize - SearchPatternSize
  ;Why advance the the search point byte by byte instead of line by line? 
  For i = 0 To n
    :The search pattern size includes possible padding
    :bytes (as part of the Pitch) which are undefined and 
    ;never guaranteed to match even though the pixel
    ;data portions do.
    ;SearchPatternSize = Pitch * #overlap_lines
    If CompareMemory(*buff+i, *SearchPattern, SearchPatternSize)
      result = *buff+i
      Break
    EndIf
  Next i
  
  ProcedureReturn 
  EndProcedure 
You are comparing image buffer data from two different images without any attempt to normalize them. For instance you don't take into account any information for them by using DrawingBufferPixelFormat(). You may be fortunate and the images may always be in the same format but then again it [could be a Wednesday] (insert your favorite joke here in place of the bracketed one).


MakeDesktopScreenshot() also contains at least a few issues. For one it reserves memory for #max_number_of_frames (based on the assumption that all frames have the same Pitch) but doesn't contain logic to handle more than 2. This is because it seems to compare every image after the first one to the first one to see if they overlap. If stitching is to occur I would think you would compare each image to the one immediately preceding it. I'm guessing you are always using it with two images.

In your debugging I recommend that you test your procedures separately. First the screen captures (save them to disk) then test the stitching of them by using the disk images. After that works eliminate the storage and loading from disk of the intermediate images.
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: drawing

Post by ZX80 »

Good day, Demivec.

Thanks for your reply.
I did a bit more research on this issue and came to the conclusion: raw data = BMP-file without header. Header size of BMP-file = 54 Bytes. But this is not the most important thing. What matters is how the raw data is written (BitMap Array). It turns out they are written from left to right and from bottom to top. I think this is the reason of the fatal error. So... start of the raw data is the end of the frame. Am I wrong again?
...doesn't contain logic to handle more than 2.
Please... This is just a sketch. And if I understand how to glue at least two of them, then no problems to continue.
If stitching is to occur I would think you would compare each image to the one immediately preceding it.
This is true. But at this stage, it doesn't matter. It will be in the future when I can glue at least two frames.
First the screen captures (save them to disk) then test the stitching of them by using the disk images.
Without using ImageGadget? Then you definitely need to know the structure of file for the selected image format (png, jpg). This will be required to manually edit the file header (when you change raw-content).
Why advance the the search point byte by byte instead of line by line?
Otherwise, the fish will pass through the seine. I think so...
User avatar
JHPJHP
Addict
Addict
Posts: 2250
Joined: Sat Oct 09, 2010 3:47 am

Re: drawing

Post by JHPJHP »

Hi ZX80,
ZX80 wrote:Every time after running your code I get the same message: "icon file not found".
Sorry, in the examples compiler options I had an icon set; download fixed, or just deselect the checkbox.
ZX80 wrote:I think your approach in this case is redundant and unnecessarily complicated.
I agree, but if you wanted to post a couple test images... no worries otherwise.

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: drawing

Post by ZX80 »

@JHPJHP

I unchecked the checkbox in compiler options, but now another problem. I see this message:

Code: Select all

title$ = "PureBasic_Compilation1.exe - System error"
text$ = "The program cannot start because MSVCP140.dll is missing" + #CRLF$ + "from the computer. Try reinstalling the program."

MessageRequester(title$, text$, #PB_MessageRequester_Error)
In any case, thanks for your point of view on this question.
Unfortunately, I can not find suitable shots that would have a large angle between themselves. Thank you!
Post Reply