Jump to content
AlexBelo

Stratched image is wrong if bmp dimention >32767 (RAD2007)

Recommended Posts

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

Share this post


Link to post

I don't know if it will help you but recently I wrote an application to display radiography images which are huge (more than a CD for a single image). I had to load the image in a 2D array much like BMP does and then handle parts of that bitmap according to the zoom factor selected by user (mouse wheel or button or keyboard, doesn't matter) and pan (mouse drag, cursor keys, doesn't matter). The computation shrink or stretch the part of selected image to create a bitmap that can fit on screen. I made a CPU computation (works well but not that fast for the gigantic images) and also on GPU (Stay fast).

 

I must admit that this is not simple code. Nor it is very complex.That's more or less what Google is doing for its satellite images.

 

Unfortunately I can't share the code since it is copyrighted. But I can discuss the topic if you have questions.

Share this post


Link to post

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".  🙂

Share this post


Link to post
4 minutes ago, AlexBelo said:

My images are much smaller (like 2k*150k) but even them cause "Out of resourses". 

Try Graphics32: Use a TBitmap32 with a memory backend (instead of a GDI backend) and display it with a TImage32/TImgView32 control.

That of course requires that the bitmap is 32-bit or that it's feasible to convert it to 32-bit in order to display it.

  • Like 2

Share this post


Link to post

> 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).

Share this post


Link to post

If you can't avail yourself of 64 bit address space then perhaps you will be best chopping the image up into tiles. 

  • Like 1

Share this post


Link to post

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...

Share this post


Link to post

If the api function use the header of a Bitmap, no image more than 4 Gb may be used, because the size of the raw bitmap is mainteined in a 4 byte data, either in 32 bit OS or 64 bit OS:

 

32768 x 32768 x 24 bit ---> 3 Gb

32768 x 32768 x 32 bit ---> 4 GB

 

Depends wich functions "stretch" setting call (StretcBlt or StretchDIBits) some different things may happens.

 

Also I remember something about api optimized in GDI that sometimes used always the 32 bit rappresentation for bitmap manipulation.

This is the original last struct definition for the BITMAPHEADER (should be defined somewhere in the system "pas" files) 
typedef struct { 
  DWORD        bV5Size; 
  LONG         bV5Width; 
  LONG         bV5Height; 
  WORD         bV5Planes; 
  WORD         bV5BitCount; 
  DWORD        bV5Compression; 
  DWORD        bV5SizeImage; 
  LONG         bV5XPelsPerMeter; 
  LONG         bV5YPelsPerMeter; 
  DWORD        bV5ClrUsed; 
  DWORD        bV5ClrImportant; 
  DWORD        bV5RedMask; 
  DWORD        bV5GreenMask; 
  DWORD        bV5BlueMask; 
  DWORD        bV5AlphaMask; 
  DWORD        bV5CSType; 
  CIEXYZTRIPLE bV5Endpoints; 
  DWORD        bV5GammaRed; 
  DWORD        bV5GammaGreen; 
  DWORD        bV5GammaBlue; 
  DWORD        bV5Intent; 
  DWORD        bV5ProfileData; 
  DWORD        bV5ProfileSize; 
  DWORD        bV5Reserved; 
} BITMAPV5HEADER, *PBITMAPV5HEADER;
Edited by DelphiUdIT

Share this post


Link to post

32768 x 32768 x 24 bit ---> 3 Gb

 

No, I mean any dimention (not both) like 1024*32768.

 

I suspect that somewhere in VCL some "size parameter" is word (not cardinal).

 

It would be nice to check this issue in current version. 

 

Share this post


Link to post
3 hours ago, AlexBelo said:

I suspect that somewhere in VCL some "size parameter" is word (not cardinal).

I don't think the problem is in the VCL. As far as I can see the calculations done by TImage, TBitmap & TCanvas are correct and should not overflow.

 

It would help if you could show what the problem looks like.

Share this post


Link to post
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

Share this post


Link to post

I try (before your last post) with an image of 49200 x 6000 pixel 24 bit with stretch and no stretch and no problem arise at runtime.

 

Only in the Rad Studio there are some memory errors cause the 32 bit Rad Studio process.

 

I look at your last answer after lunch.

 

Bye

Share this post


Link to post

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.

 

Edited by AlexBelo

Share this post


Link to post
9 minutes ago, AlexBelo said:

GDI+ Bitmap size limitation?

Hardly relevant since it's about GDI+.

 

2 minutes ago, AlexBelo said:

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.

They are not the same. pfDevice creates a DDB while all the other create DIBs.

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.

 

There are way too many unrelated things going on in your example for me to investigate it. Instead of juggling different bitmaps just size TImage->Picture->Bitmap and draw on that.

Share this post


Link to post

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 ...

Share this post


Link to post

Back in the day 16 bit Windows GDI used 16 bit coordinates, so the issue could very easily be a hang over from code written in that era. Either in the Windows API or in the VCL.

Share this post


Link to post

AFAIR, there was QC (old borland quality control system) report about 16bit API calls in VCL (in some components if memory serves).

Share this post


Link to post

Since 1996 all the bitmap relevant data is mapped on 4 bytes (included size, width and height).

So I think that really in 2007 (release year of the Rad Studio version concerned) it is not likely that there was any bug about it.

 

It is possible that what happens is related to the management of the memory linked to the bitmap (for example umpteenth temporary copies in memory) and above all linked to the use of pfdevice with modern hardware.
In fact, currently with the trivial use of a TImage all this works very well.

 

Be carefull that by now, the use of MSPaint or the Rad Studio designer with big picture is not possible, and is related to memory management not to Windows Api or VCL api.

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×