【发布时间】:2020-09-13 15:12:06
【问题描述】:
同样的问题发生在 Borland C++Builder 6 和 Embarcadero C++Builder 2010 中。
当我尝试反转图像时,表单冻结了大约 5 秒钟,但没有任何反应。当我再次点击时,图像在眨眼之间反转,再次,再次......
要重现,请使用以下代码创建一个包含 TImage 和两个 TButton 的表单:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <jpeg.hpp>
#pragma hdrstop
#pragma package(smart_init)
#pragma resource "*.dfm"
#include "Unit1.h"
TForm1 *Form1;
Graphics::TBitmap *CurrentBitmap;
bool bLoaded = false;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
CurrentBitmap = new Graphics::TBitmap;
}
//---------------------------------------------------------------------------
bool __fastcall Invert( TImage *img ) {
if( bLoaded ) {
double Scale, ScaleW, ScaleH;
Graphics::TBitmap *bmp = new Graphics::TBitmap;
bmp->Assign( CurrentBitmap );
DWORD **pixel = new DWORD*[bmp->Height];
for( long y=0; y<bmp->Height; y++ ) {
pixel[y] = (DWORD*)(bmp->ScanLine[y]);
for( long x=0; x<bmp->Width; x++ ) {
if( pixel[y][x] == clBlack ) {
pixel[y][x] = clWhite;
} else if( pixel[y][x] == clWhite ) {
pixel[y][x] = clBlack;
}
}
}
delete[] pixel;
ScaleW = (double)bmp->Width / img->ClientWidth;
ScaleH = (double)bmp->Height / img->ClientHeight;
if( ScaleW > ScaleH ) {
Scale = ScaleW;
} else {
Scale = ScaleH;
}
CurrentBitmap->Assign( bmp );
img->Picture->Bitmap->Canvas->StretchDraw(Rect(0, 0, bmp->Width/Scale, bmp->Height/Scale), bmp );
delete bmp;
return true;
} else {
return false;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender) {
TJPEGImage *jpg = new TJPEGImage();
jpg->LoadFromFile( "V:\\CBuilder\\BCB10\\GerberTest\\Testdata\\GerberTest.dpi2400.mskcmp.jpg" );
CurrentBitmap->Width = jpg->Width;
CurrentBitmap->Height = jpg->Height;
CurrentBitmap->Canvas->StretchDraw(Rect(0, 0, jpg->Width, jpg->Height), jpg );
bLoaded = true;
double Scale, ScaleW, ScaleH;
ScaleW = (double)jpg->Width / Image1->ClientWidth;
ScaleH = (double)jpg->Height / Image1->ClientHeight;
if( ScaleW > ScaleH ) {
Scale = ScaleW;
} else {
Scale = ScaleH;
}
Image1->Canvas->StretchDraw(Rect(0, 0, jpg->Width/Scale, jpg->Height/Scale), jpg );
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender) {
Invert( Image1 );
}
我无法解释为什么应用程序会冻结,或者代码在 5 秒延迟期间做了什么。
【问题讨论】:
-
听起来是学习如何使用 profiler 来确定代码实际花费时间的好时机。但是,我会说
Button1Click仅在第一次调用时为CurrentBitmap分配新内存,然后在后续调用中重用该内存。而且它还泄露了TJPEGImage对象... -
...
Invert()正在分配一个新的DWORD*[]数组,它实际上并不需要或有效使用。指向当前scanline的单个DWORD*就足够了。并且无需将CurrentBitmap复制到临时TBitmap之后再将其复制回来。您可以直接修改CurrentBitmap。Invert()假设始终使用 32 位像素,但您的代码没有做任何事情来确保这一点。您应该设置PixelFormat=pf32bit来强制这样做。 -
Remy Lebeau,不用担心内存泄漏。我在 15 分钟内创建了一个测试应用程序,以便为反转功能提供一个可用的项目。 invert 函数是一个更大项目的一部分,我想保持它的小且可重复,以便将其发布在此处。使用 DWORD* 指针是一个非常好的主意。在将运行时间从 5 秒提高到 100 毫秒后,我没有想到进一步优化 :-)
-
我用于测试的图像有 32 位像素,但我仍然不明白为什么当像素数据被寻址为 8 位或 24 位或更小尺寸时会出现延迟(并且根本没有处理)超过 32 位。由于内存处理不当,我预计图像会失真。我已经找到了 PixelFormat 属性并消除了延迟。此外,在我遇到程序崩溃并在更改像素时访问冲突之后,我不得不使用 Width 和 Height 属性(即使在像素数据的“Assign()”之后)。
-
不确定我在做什么,每次我从位图开始时都会执行这些行 ``` bitmap->Width =
;位图->高度 = ;位图->HandleType = bmDIB;位图->PixelFormat = pf32bit; ```
标签: image c++builder timage scanline