Limits for PlgBlt_() ?

Just starting out? Need help? Post your questions and find answers here.
User avatar
Lord
Addict
Addict
Posts: 849
Joined: Tue May 26, 2009 2:11 pm

Limits for PlgBlt_() ?

Post by Lord »

Hello!

I tried a code for rotating an image which I found
here in the German Forum.
Is it true, that the used API routine PlgBlt_() has
a limit in size which it can handle or did I do some-
thing wrong?
In my observations it looks like the boundary is a
size of 2^23 pixel. On MSDN is no limit mentionend.
PlgBlt_() does not return an error.

I modified the original code a little bit to demonstrate
the limit.
There are now 2 images: one just below 2^23 and
a second just above this limit. The first image has
a square, the second a circle in the upper left corner.
The button in the middle switches between these
two images.

Code: Select all

Procedure Bilddrehen(image,rl)
  
  hh = ImageHeight(image)
  br = ImageWidth(image) 
  If hh > br
    tmp = CreateImage(#PB_Any,hh,hh)
  Else
    tmp = CreateImage(#PB_Any,br,br)
  EndIf
  
  Dim p.point(2)
  
  If rl 
    p(0)\x=hh
    p(0)\y=0
    p(1)\x=hh
    p(1)\y=br
    p(2)\x=0
    p(2)\y=0
  Else
    p(0)\x=0
    p(0)\y=br
    p(1)\x=0
    p(1)\y=0
    p(2)\x=hh 
    p(2)\y=br 
  EndIf
  
  dc = StartDrawing(ImageOutput(tmp))
  DrawImage(ImageID(image),0,0)
  debug PlgBlt_(dc,p(),dc,0,0,br,hh,0,0,0)
  StopDrawing()
  imgnr = GrabImage(tmp,#PB_Any,0,0,hh,br)
  FreeImage(tmp)
  
  ProcedureReturn imgnr
EndProcedure

; CreateImage(1, 3257, 2575)
; CreateImage(2, 3258, 2576)
CreateImage(1, 2896, 2896)
CreateImage(2, 2897, 2897)
StartDrawing(ImageOutput(1))
Box( 10,10,100,100, $ffffff)
StopDrawing()
StartDrawing(ImageOutput(2))
Circle( 60,60,50, $ffffff)
StopDrawing()

imgnr=1

OpenWindow(0,0,0,600,500,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)


ww = WindowWidth(0)

butL = ButtonGadget(#PB_Any, 20, 10, 80, 25, "left")
butR = ButtonGadget(#PB_Any, ww-100, 10, 80, 25, "right")
butS = ButtonGadget(#PB_Any, ww/2-40, 10, 80, 25, "Switch",#PB_Button_Toggle)

butI = ImageGadget(#PB_Any,10,45,0,0,ImageID(imgnr))
DisableGadget(butI,1)
Repeat
  
  event = WaitWindowEvent()
  
  If event = #PB_Event_Gadget Or Event = #PB_Event_Menu
    
    welcherButton = EventGadget() 
    
    Select welcherButton
        
      Case butL
        imgnr = Bilddrehen(imgnr,0)
        SetGadgetState(butI, ImageID(imgnr))
        
      Case butR
        
        imgnr = Bilddrehen(imgnr,1)
        SetGadgetState(butI, ImageID(imgnr))
        
      Case butS
        imgnr=GetGadgetState(butS)+1
        SetGadgetState(butI, ImageID(imgnr))
        
        
    EndSelect     
    
  EndIf
  
Until event = #PB_Event_CloseWindow

End
Image
User avatar
idle
Always Here
Always Here
Posts: 5098
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Limits for PlgBlt_() ?

Post by idle »

pb images have a limit 8192x8192 pixels
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
Lord
Addict
Addict
Posts: 849
Joined: Tue May 26, 2009 2:11 pm

Re: Limits for PlgBlt_() ?

Post by Lord »

idle wrote:pb images have a limit 8192x8192 pixels
Hi idle,

I think, this is not longer true. I already used bitmaps
larger than 8192x8192. And if you look, the questionable
size is way below that (2897x2897).

Edit:
I just found a statement by fred.
So the image limit depends on the windows version.
But this is not a reason for PlgBlt_() failing with 2897x2897.
Image
User avatar
idle
Always Here
Always Here
Posts: 5098
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Limits for PlgBlt_() ?

Post by idle »

Sorry I can't really help you with the plgBlt issue as I'm on Linux
Windows 11, Manjaro, Raspberry Pi OS
Image
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Limits for PlgBlt_() ?

Post by c4s »

Just don't use the API function. You can find some excellent codes for image rotation on here!
E.g. one from luis - it's quite fast, cross-platform and supports alpha channel.
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
Lord
Addict
Addict
Posts: 849
Joined: Tue May 26, 2009 2:11 pm

Re: Limits for PlgBlt_() ?

Post by Lord »

c4s wrote:Just don't use the API function.
...
Thank you for your answer. But...
That isn't that what I asked for. I just wanted to
know wether my observations are correct or not.
Maybe it's just a stupid error I'm making in using
the code in this way right now. Maybe there are
limititations stated somewhere on MSDN but I didn't
find it. :cry:
Image
User avatar
luis
Addict
Addict
Posts: 3876
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Limits for PlgBlt_() ?

Post by luis »

Your code works when the images are smaller, so I suppose the problem could be in that API function.

I don't know if it works through some kind of DMA transfer, but if that's the case probably has some hardware limit to the total number of bits it can transfer.

I didn't find any specific info looking on the Net.

EDIT: found this -> http://www.tech-archive.net/Archive/Dev ... 00084.html

The threshold is different though.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
Lord
Addict
Addict
Posts: 849
Joined: Tue May 26, 2009 2:11 pm

Re: Limits for PlgBlt_() ?

Post by Lord »

Hello luis!

I did read this too, but at that time it was the only
source which stated this questionable behaviour.

But I found another statement.
So there is a Windows bug - if I read this part correct:
Just a guess, but I wonder if this could have something to do with the
size limits when rotating a bitmap?

We have run into similar problems when using any bitmap rotation method,
StretchBlt with a rotation transform, PlgBlt, even BitBlt with a rotation
transform. In our scenario, we would run into an initial failure point
where the image data would be passed, but not show up, and then a
secondary failure point at a greater size where the data would fail to
even be passed. This occurred with any high res DC, such as a Printer or
EMF based on a printer.

A call to MS verified that this is a bug, and that there is no hard upper
limit to work off of. We just had to break the image down into chunks and
blit the smaller chunks, or rotate the bits ourselves.

P.S.
Overall memory does not seem to be the deciding factor. A 4GB machine was
failing at lower thresholds that a 1GB machine for us. It has more to do
with how much free space the internal OS processes that handle the bit
rotation have available at the given moment.
But i'm still wondering why this is not mentioned much
more often. It looks to me like the whole world knows
about this bug except me. :shock:
Image
MachineCode
Addict
Addict
Posts: 1482
Joined: Tue Feb 22, 2011 1:16 pm

Re: Limits for PlgBlt_() ?

Post by MachineCode »

idle wrote:pb images have a limit 8192x8192 pixels
That used to be true, but now it's 32000x32000 pixels.
Microsoft Visual Basic only lasted 7 short years: 1991 to 1998.
PureBasic: Born in 1998 and still going strong to this very day!
User avatar
luis
Addict
Addict
Posts: 3876
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Limits for PlgBlt_() ?

Post by luis »

Lord quoting another source wrote: It has more to do with how much free space the internal OS processes that handle the bit
rotation have available at the given moment.
If that's true it's somewhat strange I can reproduce the problem with exactly the same image size you are using in your code.

Probably the right thing to do would be to reverse engineering the API in question and see exactly what it does.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
Lord
Addict
Addict
Posts: 849
Joined: Tue May 26, 2009 2:11 pm

Re: Limits for PlgBlt_() ?

Post by Lord »

MachineCode wrote:
idle wrote:pb images have a limit 8192x8192 pixels
That used to be true, but now it's 32000x32000 pixels.
It's not a PureBasic limit, it's Windows limit.
luis wrote:...Probably the right thing to do would be to reverse engineering the API in question and see exactly what it does.
But that is far beyond my capabilities.
I'm just a hobby programmer, not a professional.

So I have to live with this and must have a closer
look at luis' code.
Image
User avatar
Lord
Addict
Addict
Posts: 849
Joined: Tue May 26, 2009 2:11 pm

Re: Limits for PlgBlt_() ?

Post by Lord »

Hi!

I just stumbled across this old thread of mine.
Maybe someone would like to know how I then "solved"
the problem with PlgBlt_() and can rotate images larger
than 2^23 or 2896x2896 pixel.
It's not as fast as I had hoped, but it worked.

Code: Select all

; RotateLeft90() and RotateRight90()
; Based on code by Ligatur and hjbremer
; https://www.purebasic.fr/german/viewtopic.php?f=16&t=18695
; Improved by Lord to overcome the limits for PlgBlt_()
; https://www.purebasic.fr/english/viewtopic.php?f=13&t=48002

EnableExplicit

Enumeration
  #MainWindow
EndEnumeration
Enumeration
  #ScrollArea
  #Canvas
EndEnumeration
Enumeration
  #Img1
  #Img2
  #Img3
EndEnumeration
Enumeration
  #Open
  #Left
  #Right
EndEnumeration
EnumerationBinary 128
  #BS128
  #BS256
  #BS512
  #BS1024
  #BS2048
EndEnumeration

#BlockSize=#BS512; A BlockSize of 512x512 turned out to be the fastest way to rotate a big image  

Define Event, Quit=#False

UseJPEGImageDecoder()

Procedure RotateLeft90()
  Protected iw, ih, x, y, dc
  iw=ImageWidth(#Img1):ih=ImageHeight(#Img1)
  If CreateImage(#Img2, ih, iw)
    Dim p.point(2)
    For y=0 To ih Step #BlockSize
      For x=0 To iw Step #BlockSize
        If GrabImage(#Img1, #Img3, x, y, #BlockSize, #BlockSize)
          p(0)\x=0
          p(0)\y=#BlockSize
          p(1)\x=0
          p(1)\y=0
          p(2)\x=#BlockSize
          p(2)\y=#BlockSize
          dc = StartDrawing(ImageOutput(#Img3))
            If dc
              PlgBlt_(dc, p(), dc, 0, 0, #BlockSize, #BlockSize, 0, 0, 0)
            EndIf
          StopDrawing()
          If StartDrawing(ImageOutput(#Img2))
              DrawImage(ImageID(#Img3), y, iw-x-#BlockSize)
            StopDrawing()
          EndIf
        EndIf
      Next
    Next
    CopyImage(#Img2, #Img1)
  EndIf
EndProcedure
Procedure RotateRight90()
  Protected iw, ih, x, y, dc
  iw=ImageWidth(#Img1):ih=ImageHeight(#Img1)
  If CreateImage(#Img2, ih, iw)
    Dim p.point(2)
    For y=0 To ih Step #BlockSize
      For x=0 To iw Step #BlockSize
        If GrabImage(#Img1, #Img3, x, y, #BlockSize, #BlockSize)
          p(0)\x=#BlockSize
          p(0)\y=0
          p(1)\x=#BlockSize
          p(1)\y=#BlockSize
          p(2)\x=0
          p(2)\y=0
          dc = StartDrawing(ImageOutput(#Img3))
            If dc
              PlgBlt_(dc,p(),dc,0,0,#BlockSize,#BlockSize,0,0,0)
            StopDrawing()
          EndIf
          If StartDrawing(ImageOutput(#Img2))
              DrawImage(ImageID(#Img3), ih-y-#BlockSize, x)
            StopDrawing()
          EndIf
        EndIf
      Next
    Next
    CopyImage(#Img2, #Img1)
  EndIf
EndProcedure
Procedure OpenImage()
  Protected I1W, I1H
  Protected Img.s
  Img=OpenFileRequester("Choose Image...", "", "JPG-Datei (*.jpg)|*.jpg", 0)
  If Img
    If LoadImage(#Img1, Img)
      I1W=ImageWidth(#Img1)
      I1H=ImageHeight(#Img1)
      SetGadgetAttribute(#ScrollArea, #PB_ScrollArea_InnerWidth, I1W)
      SetGadgetAttribute(#ScrollArea, #PB_ScrollArea_InnerHeight, I1H)
      ResizeGadget(#Canvas, #PB_Ignore, #PB_Ignore, I1W, I1H)
      SetGadgetAttribute(#Canvas, #PB_Canvas_Image, ImageID(#Img1))
    EndIf
  EndIf
EndProcedure
Procedure Rotate()
  Protected EventMenu
  EventMenu=EventMenu()
  Select EventMenu
    Case #Open
      OpenImage()
    Case #Left
      RotateLeft90()
    Case #Right
      RotateRight90()
  EndSelect
  If IsImage(#Img1)
    SetGadgetAttribute(#ScrollArea, #PB_ScrollArea_InnerWidth, ImageWidth(#Img1))
    SetGadgetAttribute(#ScrollArea, #PB_ScrollArea_InnerHeight, ImageHeight(#Img1))
    ResizeGadget(#Canvas, #PB_Ignore, #PB_Ignore, ImageWidth(#Img1), ImageHeight(#Img1))
    SetGadgetAttribute(#Canvas, #PB_Canvas_Image, ImageID(#Img1))
  EndIf
EndProcedure
Procedure myResize()
  ResizeGadget(#ScrollArea, #PB_Ignore, #PB_Ignore, WindowWidth(#MainWindow), WindowHeight(#MainWindow))
EndProcedure

OpenWindow(#MainWindow, 10, 10, 1024, 768, "Rotate90 test: [CTRL][O] select image, [L] rotate left, [R] rotate right", #PB_Window_SystemMenu|#PB_Window_SizeGadget)
ScrollAreaGadget(#ScrollArea, 0, 0, WindowWidth(#MainWindow), WindowHeight(#MainWindow), 0, 0)
CanvasGadget(#Canvas, 0, 0, 0, 0)
CloseGadgetList()

AddKeyboardShortcut(#MainWindow, #PB_Shortcut_Control|#PB_Shortcut_O, #Open)
AddKeyboardShortcut(#MainWindow, #PB_Shortcut_L, #left)
AddKeyboardShortcut(#MainWindow, #PB_Shortcut_R, #Right)

BindEvent(#PB_Event_Menu, @Rotate(), #MainWindow)
BindEvent(#PB_Event_SizeWindow, @myResize(), #MainWindow)


Repeat
  Event=WaitWindowEvent()
  Select Event
    Case #PB_Event_CloseWindow
      Quit=#True
  EndSelect
Until Quit=#True
Image
Post Reply