How to clear a bitmap that was declared in the .cpp as follows:
Graphics::TBitmap * Bitmap1 = new Graphics::TBitmap;
All the examples I find are for Firemonkey and there it seems quite simple
MyBitmap = new TBitmap(0,0);
...
MyBitmap->Clear(claWhite);
or
MyBitmap->ClearRect(MyRect);
But Clear() and ClearRect() are not members of TBitmap in VCL
I expect I should delete Bitmap1; in order to clear it, but then how to re-declare it, so that it is still global to all methods in the form?
Thanks in advance.
You don't need to delete and recreate the TBitmap. Simply draw a new image over top of it, for instance by using its Canvas->FillRect() method (that is essentially what the FMX examples are doing), eg:
Bitmap1->Brush->Color = clWhite;
Bitmap1->Canvas->FillRect(Rect(0, 0, Bitmap1->Width, Bitmap1->Height));
Related
I am welcoming Embarcaderos efforts to make TListView more dynamically, and was exited to see Sarina Duponts post here where you could just link the imageindex to the TListView properties in LiveBindings Designer, and even the image property to a datafield (integer) when using DynamicAppearance and TImageObjectAppearance.
But... I tried, and did almost succeed.
In my challenge I have an application where I use TFDMemTable with TREST* function to populate the TFDMemTable. All works well if I don't use the DynamicAppearance and use i.e. ImageListItem and links the datafield I want to use to the imageindex property in TListView using LiveBindings Designer.
With DynamicApperance though, there are no imageindex property to link to, but Sarina Dupont says in here post that you could link the integer field directly to the image property (and IDE/compiler will figure it out).
Well... I figured following out: My data fields (semicreated from TREST* and TFDMemTable) are not neccesserely what they seems to be. Since I am using REST/JSON, the fieldtypes are "anonymized" to WideString, actually the FieldDefs->'dataitem'->DataType is set to "ftWideString". I tried to change this value to ftInteger in hope that this would help, but I did just get this errormessage: "FDMemtTable1: Type mismatch in field for 'datafield', exepecting: WideString actual: Integer".
So... I was nearly there, and I really want to use DynamicAppearance and view several images and textfields for each TListViewItem...
...or is it easier to make a ListViewItem 'Template' dynamically and populate it with data instead, and what is the best way to do that ?
I usually try to avoid LiveBindings. The fastest, most stable and easiest way is to add items using code.
ListView1->BeginUpdate();
try {
for (int i = 0; i < arrayOfThings->item.Length; i++) {
TListViewItem* item = ListView1->Items->Add();
item->Text = arrayOfThings->item[i]->item_name;
item->Data["itemName"] = TValue::From<UnicodeString>( arrayOfThings->item[i]->item_name);
item->Data["itemId"] = TValue::From<UnicodeString>( IntToStr( arrayOfThings->item[i]->id ));
item->Data["itemDate"] = TValue::From<UnicodeString>(arrayOfThings->item[i]->item_date);
// adding the image - imgClock is name of the image field [TImageObjectAppearance ] added to items in ItemAppearance in the TListView object that uses DynamicAppereance
const UnicodeString imgClock = L"imgClock";
dynamic_cast<TListItemImage*>(item->Objects->FindDrawable(imgClock))->Bitmap = //bitmap source;
}
} catch (...) {
}
ListView1->EndUpdate();
I'm trying to use the TWICImage class in C++builder to save an in-memory bitmap to TIFF file. However, any attempt to use the Assign() method on TWICImage gives an access error.
For example:
TBitmap* bmp = new TBitmap();
TWICImage* wic = new TWICImage();
wic->Assign( bmp );
gives the access violation on the third line.
After a bit more digging, the following gives an error on the second and subsequent assignments:
TBitmap* bmp = new TBitmap();
for (int i=0; i<10; ++i) {
std::unique_ptr<TWICImage> wic( new TWICImage() );
wic->Assign( bmp );
}
However, if I make the TWICImage pointer static, it all works as expected. So it looks like there is something odd going on in the TWICImage destructor.
The question is very similar to this, but that one didn't get answered yet. My question is, I have a D2D DXGI RenderTarget from d2dfactory->CreateDxgiSurfaceRenderTarget(), and I want to save its content to an image file using WIC. I was just reading this and this, so it looks to me that I can not just create a ID2D1Bitmap on a WIC render target and use ID2D1Bitmap::CopyFromRenderTarget() to copy from the input render target I want to save, because they are using different resources. So here is what I came up with using ID2D1RenderTarget::CreateSharedBitmap():
HRESULT SaveRenderTargetToFile(
ID2D1RenderTarget* pRTSrc,
LPCWSTR uri
)
{
HRESULT hr = S_OK;
ComPtr<IWICBitmap> spWICBitmap;
ComPtr<ID2D1RenderTarget> spRT;
ComPtr<IWICBitmapEncoder> spEncoder;
ComPtr<IWICBitmapFrameEncode> spFrameEncode;
ComPtr<IWICStream> spStream;
//
// Create WIC bitmap to save and associated render target
//
UINT bitmapWidth = static_cast<UINT>(pRTSrc->GetSize().width + .5f);
UINT bitmapHeight = static_cast<UINT>(pRTSrc->GetSize().height + .5f);
HR(m_spWICFactory->CreateBitmap(
bitmapWidth,
bitmapHeight,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapCacheOnLoad,
&spWICBitmap
));
D2D1_RENDER_TARGET_PROPERTIES prop = D2D1::RenderTargetProperties();
prop.pixelFormat = D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_PREMULTIPLIED
);
prop.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
prop.usage = D2D1_RENDER_TARGET_USAGE_NONE;
HR(m_spD2D1Factory->CreateWicBitmapRenderTarget(
spWICBitmap,
prop,
&spRT
));
//
// Create a shared bitmap from this RenderTarget
//
ComPtr<ID2D1Bitmap> spBitmap;
D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();
bp.pixelFormat = prop.pixelFormat;
HR(spRT->CreateSharedBitmap(
__uuidof(IWICBitmap),
static_cast<void*>(spWICBitmap.GetRawPointer()),
&bp,
&spBitmap
)); // <------------------------- This fails with E_INVALIDARG
//
// Copy the source RenderTarget to this bitmap
//
HR(spBitmap->CopyFromRenderTarget(nullptr, pRTSrc, nullptr));
//
// Draw this bitmap to the output render target
//
spRT->BeginDraw();
spRT->Clear(D2D1::ColorF(D2D1::ColorF::GreenYellow));
spRT->DrawBitmap(spBitmap);
HR(spRT->EndDraw());
//
// Save image to file
//
HR(m_spWICFactory->CreateStream(&spStream));
WICPixelFormatGUID format = GUID_WICPixelFormat32bppPBGRA;
HR(spStream->InitializeFromFilename(uri, GENERIC_WRITE));
HR(m_spWICFactory->CreateEncoder(GUID_ContainerFormatPng, nullptr, &spEncoder));
HR(spEncoder->Initialize(spStream, WICBitmapEncoderNoCache));
HR(spEncoder->CreateNewFrame(&spFrameEncode, nullptr));
HR(spFrameEncode->Initialize(nullptr));
HR(spFrameEncode->SetSize(bitmapWidth, bitmapHeight));
HR(spFrameEncode->SetPixelFormat(&format));
HR(spFrameEncode->WriteSource(spWICBitmap, nullptr));
HR(spFrameEncode->Commit());
HR(spEncoder->Commit());
HR(spStream->Commit(STGC_DEFAULT));
done:
return hr;
}
Anything wrong with this code? (I'm sure there's a lot :)) Somewhere on MSDN it says that WIC render target only supports software mode, while DXGI render target only supports hardware mode. Is this the reason why the above call to CreateSharedBitmap() fails? How should I save a DXGI surface content to an image file with D2D then?
With some limitations, you can use D3DX11SaveTextureToFile. Use QI on your surface to get the ID3D11Resource.
On the same page they are recommending DirectXTex library as a replacement, CaptureTexture then SaveToXXXFile (where XXX is WIC, DDS, or TGA). So that's another option.
Also, if your surface has been created as GDI compatible, you can use IDXGISurface1::GetDC. (Use QI on your IDXGISurface to get the IDXGISurface1). Saving DC to a file is left as an exercise to the reader.
Remember to use the Debug Layer for help with cryptic return codes like E_INVALIDARG.
You could try this (I haven't):
Make your old DXGISurface.
Make an auxiliary ID2D1DeviceContext render target.
Use ID2D1DeviceContext::CreateBitmapFromDxgiSurface to create an ID2D1Bitmap1 associated to the DXGI surface.
Draw on your DXGISurface. You should get the same on the ID2D1Bitmap1.
Use ID2D1Bitmap1::Map to get a memory pointer to the pixeldata.
Copy the pixeldata to file, or to a wicbitmap for encoding (jpeg, tiff, etc.)
Perhaps this:(succeed running)
D2DFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperies(D2D1_RENDER_TARGET_TYPE_SOFTWARE,D2D1::Pixel Format(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_PREMULTIPLIED)), ……)
your RenderTarget should be set the static of SOFTWARE the same as WICRenderTarget.
I have a TListView that gets populated with data collected over a network. To collect all the data takes around 50ms, to add it to the list takes around 5 seconds. My initial guess was that it was redrawing after every addition or something like that. What should I do to get the TListView to update as quickly as possible?
Columns and items are all added via code.
I tried using BeginUpdate and EndUpdate on the items of the list but that didn't make much difference. There are around 2000 entries that are added to the list.
Without seeing your actual code, there is no way to know for sure why your updates are that slow. However, if speed is an issue for you, especially with a lot of list items, you should put the TListView into virtual mode instead (set its OwnerData property to true) and store your status information elsewhere, not in the TListView itself (2000 items is a lot of overhead for a non-virtual ListView to handle). Then, simply call the ListView's Invalidate() or UpdateItems() method when needed to trigger repaints, and use the OnData event to provide the status data to TListView whenever it asks you for it. For example:
struct MyStatusInfo
{
String Status;
...
};
MyStatusInfo StatusItems[2000];
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
...
ListView1->Items->Count = 2000; // you don't use Add() with a virtual ListView
...
}
void __fastcalll TForm1::UpdateStatus(int Index, const String &Status, ...)
{
MyStatusInfo &Info = StatusItems[Item->Index];
Info.Status = Status;
...
ListView1->UpdateItems(Index, Index);
}
void __fastcall TForm1::ListView1Data(TObject *Sender, TListItem *Item)
{
MyStatusInfo &Info = StatusItems[Item->Index];
Item->Caption = Info.Status;
...
}
I'm not sure if that helps, since BeginUpdate didn't, but it worth trying:
1) Try filling it while Enabled = false, then enable it
2) Try building a TListItems and assign it directly to the TListView's Items properties
There's a TImage component on a form in my program.
In some situation, the program must test:
If "there is an image assigned to the picture property of the TImage component" then ...
How can I do this?
if Image1.Picture.Graphic = NIL
then ShowMessage("There is no image.")
else ShowMessage("Image found.");
If working with bitmaps, you can also do this:
if Image.Picture.Bitmap.Empty then ShowMessage("There is no spoon");
Better late than never!
The right way is:
if Assigned(Image1.Picture.Graphic) then ...
You don't say, but I'll assume you're talking about Delphi.
You can check whether there's a bitmap in the TImage control by testing:
if Image.Picture.Bitmap.Width > 0 then
// do whatever