Jump to content

AlexBelo

Members
  • Content Count

    33
  • Joined

  • Last visited

Posts posted by AlexBelo


  1. I don't know why you would prefer DDB when you're working with bitmaps that large. Use DIBs instead. They are backed by virtual memory.

     

    Exactly by reason of "my" virtual memory: DDB resides somewhere in GDI (out of my process); I simply has no memory to hold bmp data in my memory during subsequent operations.

     

    OK, further investigations have more academical interest because workaround (manual call of StretchBlt) is already found ...


  2. I've found the only related question (without answer) 

    GDI+ Bitmap size limitation? (December 1st, 2006)

    https://forums.codeguru.com/showthread.php?407837-GDI-Bitmap-size-limitation

     

    Quote

    It seems that bitmaps of the GDI+ Bitmap class are limited to a size of 32767 pixels in either direction (width, height).
    ...
    This limit is not documented, and I have not found anything on the topic on the net

    Also I've noticed that if I comment out 

    Image->Picture->Bitmap->PixelFormat=pfDevice;

    the problem exists only when initial bmp has pfDevice or pf32bit (the same as pfDevice, AFAIUI) format.

     

    Upd: CDC Class (MFC, not very relevant, but ...)

    https://docs.microsoft.com/en-us/cpp/mfc/reference/cdc-class?view=msvc-160

    Quote

    Under Windows 95/98, all screen coordinates are limited to 16 bits. Therefore, an int passed to a CDC member function must lie in the range -32768 to 32767.

     


  3. void TForm1::AdjImage(bool stretch)
    {
     if(stretch)
     {
      ScrollBox->VertScrollBar->Visible=false;
      ScrollBox->HorzScrollBar->Visible=false;
      Image->AutoSize=false;
      Image->Width=ScrollBox->ClientWidth;
      Image->Height=ScrollBox->ClientHeight;
      Image->Stretch=true;
     }
     else
     {
      Image->Stretch=false;
      Image->AutoSize=true;
      ScrollBox->VertScrollBar->Visible=true;
      ScrollBox->HorzScrollBar->Visible=true;
     }
    }
    
    void __fastcall TForm1::btnCreateBmpClick(TObject *Sender)
    {
     AdjImage(cbStretch->Checked); // preparing Image according to desired view
    
     unsigned int w=seW->AsInteger; // test dimensions
     unsigned int h=seH->AsInteger;
    
     TPixelFormat pf;
     if(rbDevice->Checked) pf=pfDevice; else
     if(rb8bit->Checked)   pf=pf8bit;   else
     if(rb24bit->Checked)  pf=pf24bit;  else
                           pf=pf32bit;
     TcppBitmap bmp;
     bmp->PixelFormat=pf;
     bmp->SetSize(w, h);
    
     TColor c;
     if(pf!=pf8bit) c=clRed;
     else c=clBlack;
    
     bmp->Canvas->Pen->Color=c; // some testing draw
     bmp->Canvas->Pen->Width=10;
     bmp->Canvas->MoveTo(5, 0); bmp->Canvas->LineTo(5, h);
     bmp->Canvas->MoveTo(0, 0); bmp->Canvas->LineTo(w, h);
    
     bmp->Canvas->Pen->Width=1;
     bmp->Canvas->MoveTo(0, 0);
     bmp->Canvas->LineTo(w, 0);
     bmp->Canvas->LineTo(w-1, 0);
     bmp->Canvas->LineTo(w-1, h-1);
     bmp->Canvas->LineTo(0, h-1);
     bmp->Canvas->LineTo(0, 0);
    
     Image->Picture->Assign(bmp); // show in Image
    
     Image->Picture->Bitmap->PixelFormat=pfDevice; // "move into GDI domain" (out of application's memory space)
     Image->Picture->Bitmap->FreeImage();          // deallocate DIB-section (if initial bmp was not pfDevice)
    
     if(pf!=pf8bit) c=clGreen;
     else c=clGray;
     // another test (on Image internal bitmap now)
     Image->Canvas->Pen->Color=c;
     Image->Canvas->Pen->Width=10;
     Image->Canvas->MoveTo(20, 0);
     Image->Canvas->LineTo(20, h);
    }

    Results: left - H<32768 (as expected), right H=32768 (usually random pieces of desktop).

     

    Sample.thumb.png.98e4e6ed0171398f50ac4ab939a713a9.png


  4. After some experiments:

    - if I do StretchBlt manually into intermediate bmp the result is always correct (i.e. this API call works as expected even with huge bmp ~1Gb);

    - if I set Image->Stretched=true and perform Image->Picture->Assign(bmp), the resulting picture in Image on a form is totally wrong when bmp->Width or Height is >32767; tracing into Graphics unit doesn't show anything suspicious (the same call of StretchBlt with correct parameters) ...

     

    So as workaround I have to create stretched image manually...


  5. > Graphics32

     

    Unfortunately I can not use 32bit images due to memory limits. As I mentioned above I use RAD2007 and 32bit compiler. Even on Win64 (where 32bit app can use nearly 4 Gb of memory) I have not enough continuous memory for 32bit image (24bit bmp is still workable in my case).


  6. Thank you for your response.

     

    Yes, I can create stretched bmp manually but for now I'd like to use a simple solution (if possible).

     

    huge (more than a CD for a single image)

    Wow. Of course, you have no chance to process such picture with any thinkable API/hardware. My images are much smaller (like 2k*150k) but even them cause "Out of resourses".  🙂


  7. Hi all.

     

    I have a problem when I try to show a bmp in TImage when Image->Stratched=true.

    All work as expected when any bmp dimension is less than 32767. But higher dimensions lead to garbage in Image.

     

    Is this known limitation of WinAPI (can not find any in docs and Google) or bug in Graphics unit of RAD2007?

     

    TIA.

    --

    Alex


  8. Hi all.

    Just for your information:

     

    IDE cannot find declaration with 32-bit clang compiler

    https://quality.embarcadero.com/browse/RSP-29732

     

     
    Quote

     

    Soren Seyfert added a comment - 16 minutes ago

    With the following settings Code Insight with 32-bit clang compiler works in our projects:

    • Open the project as standalone .cbproj, don't open a project-group, in project groups Code Insight doesn't work.
    • Project Options -> Project Properties -> General -> uncheck "Run C++ compiler in a separate process" (that makes CTRL + space to find methods etc. work).
    • Project Options -> C++ Compiler -> LSP -> check "Enable Project Indexing for Navigation/Tooltip support" (that makes "find declaration" work). Make sure that the option is checked for your current configuration or better set it for all configurations.
    • Save the project and close it.
    • Reopen the project -> you see in task manager that cquery.exe (child-process under RAD Studio) is working in heavy CPU and RAM usage. Depending on your project it takes a while (and uses a lot of RAM) but Code Insight should work now.

    Make sure that cquery.exe is working in task manager, otherwise Code Insight fails. We had this effect when RAM/disk space was low or when we opened a project-group.

    So for us it's a great improvement now but it would be great, if we can get it to work in project-groups. Also the label "CodeInsight: Stopped" in project status bar is shown all the time.
    We use Embarcadero® C++Builder 10.4 Version 27.0.40680.4203.

     

     


  9. 13 hours ago, Fr0sT.Brutal said:

    TFileStream ;D

    Hmm... Good option. 🙂

     

    13 hours ago, Fr0sT.Brutal said:

    from what I know mapping doesn't read-and-allocate the contents of the mapped file. Contrary, it allows working with the contents like it was allocated in memory

    As documentation states:

    MapViewOfFile function (memoryapi.h)

    Maps a view of a file mapping into the address space of a calling process.

     

    So mapped view is in "my" address space.

    AFAIUI, OS gives me (and others who use the same mapped file) access to some "external" pages in memory but I see these pages as array allocated in "my" memory. And big view will take big continuous piece of virtual memory in my process.

     

    About TFileStream. As documentation states:

     

    ... file views derived from any file mapping object that is backed by the same file are coherent or identical at a specific time. Coherency is guaranteed for views within a process and for views that are mapped by different processes.

     

    (Not surprising: data resides in the same pages in memory.)

    AFAIUI "normal" files don't have such property.


  10. I don't want to expand file but operate with big file via mapped view of reasonable size; mapping view of entire file is impossible.

     

    Take a look: 

    MapViewOfFile function

    https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile

     

    Mapping a file makes the specified portion of a file visible in the address space of the calling process.

    For files that are larger than the address space, you can only map a small portion of the file data at one time. When the first view is complete, you can unmap it and map a new view.


  11. Thank you for your responce.

     

    AFAICS both sources do not automatically process boundaries of currently mapped view during r/w operations . . . 

    I.e. if start of r/w data block is in current view but its end is not then operation will fail.

     

    But I wish to r/w stream without thinking about boundaries of current view; Read/Write methods should move view (of predefined size) automatically.

    Of course, I can modify Read/Write methods myself to achieve necessary functionality.


  12. 1 hour ago, Fr0sT.Brutal said:

    Are you sure

    No. 🙂

    My allegation about lists of objects is not right. (I investigated this problem too long ago; memory fail me.)

     

    More accurate info:

     

    unit Graphics;
    
    { FreeMemoryContexts is called by the VCL main winproc to release
      memory DCs after every message is processed (garbage collection).
      Only memory DCs not locked by other threads will be freed.
    }
    procedure FreeMemoryContexts;
    var
      I: Integer;
    begin
      with BitmapCanvasList.LockList do
      try
        for I := Count-1 downto 0 do
        with TBitmapCanvas(Items[I]) do
          if TryLock then
          try
            FreeContext;
          finally
            Unlock;
          end;
      finally
        BitmapCanvasList.UnlockList;
      end;
    end;
    
    
    
    unit Controls;
    
    procedure TWinControl.MainWndProc(var Message: TMessage);
    begin
      try
        try
          WindowProc(Message);
        finally
          FreeDeviceContexts;
          FreeMemoryContexts;
        end;
      except
        Application.HandleException(Self);
      end;
    end;

     

    So main thread (where MainWndProc works) fairly often deselects unlocked memory contexts. It causes all kinds of problems in background threads which use bitmaps without locking.

    • Thanks 1

  13. On 3/2/2021 at 6:53 PM, Yaron said:

    The canvas are all locked and the issue only seems related to brush colors.

    GDI objects like brushes are in global list. RTL browses this list in main thread on every idle event and deletes all unused objects; locking any canvas simply disables updating of the list. If you (or some 3-d party library) somewhere do not lock a canvas in backgrownd thread it is possible that some object (brush in your case) is already deleted or/and overwritten but your code is still using old element in list. As a result you can see erratic behaviour of any kind.


  14. 22 hours ago, Yaron said:

    Even though I'm calling Bitmap.Canvas.lock and no other thread is writing to the canvas, I rarely get a weird fill color issue.

     

    21 hours ago, Yaron said:

    I didn't paste the entire code for simplicity.

    If problem is not in skipped code then this is a bug.

     

    I suspect that you do something wrong with canvas(es) somewhere in your program. Locking canvas should work.

     

    BTW, Do you use  TJPEGImage.Draw in your threads? This method had a bug (no canvas lock) in old versions.

     

    Also, do you copy bmps in thread(s)? I know for sure (after a lot of experiments) that both canvases must be locked in this case. Moreover, to be sure that bmp is really copied in this "safe locked" state you need to modify target bmp (assign a pixel to itself for example); this creates real copy of data in target bmp (instead of reference on source data).


  15. 37 minutes ago, Markus Kinzler said:

    The community is here.

     🙂.

     

    But (IMHO) dropping of official forum was really wrong decision.

    In old days (since ~2000 year) I usually started my day from browsing of official newsgroups (in good old plain text and very handy tree format of messages) and I still have a huge collection of answers in "how to ..." style from famous specialists like Peter Below, Remy, and many others. After end of NG civilization there is no default place where I can get help from gurus and be well informed. Yes, you can say that there are many such places but "many" means "scattered" in this context ...

    • Like 2
×