【发布时间】:2020-01-16 00:34:43
【问题描述】:
在相机应用程序中,位图像素数组是从流式相机中检索的。 通过将像素数组写入命名管道来捕获像素数组,在管道的另一端,ffmpeg 检索它们并创建一个 AVI 文件。
我需要创建一个自定义帧(启用自定义文本),并将其像素作为生成影片中的第一帧。
问题是我如何使用 TBitmap(为了方便)来
从头开始创建 X x Y 单色(8 位)位图,使用 自定义文本。我希望背景为白色,文本为 变黑。 (主要是想出这一步,见下文。)
检索我可以发送/写入管道的像素数组
第 1 步:以下代码创建一个 TBitmap 并在其上写入文本:
int w = 658;
int h = 492;
TBitmap* bm = new TBitmap();
bm->Width = w;
bm->Height = h;
bm->HandleType = bmDIB;
bm->PixelFormat = pf8bit;
bm->Canvas->Font->Name = "Tahoma";
bm->Canvas->Font->Size = 8;
int textY = 10;
string info("some Text");
bm->Canvas->TextOut(10, textY, info.c_str());
以上步骤基本结束。
写入/管道代码需要一个带有位图像素的字节数组;例如
unsigned long numWritten;
WriteFile(mPipeHandle, pImage, size, &numWritten, NULL);
其中 pImage 是指向无符号字符缓冲区(位图像素)的指针,大小是此缓冲区的长度。
更新: 使用生成的 TBitmap 和 TMemoryStream 将数据传输到 ffmpeg 管道不会生成正确的结果。我得到一个扭曲的图像,上面有 3 条对角线。
我收到的相机帧缓冲区的缓冲区大小正好是 323736,等于图像中的像素数,即 658x492。 注意 我的结论是这个“位图”没有被填充。 658 不能被四整除。
不过,我将生成的位图转储到内存流后得到的缓冲区大小为 325798,比预期的大 2062 个字节。正如@Spektre 在下面指出的那样,这种差异可能是填充?
使用以下代码获取像素数组;
ByteBuffer CustomBitmap::getPixArray()
{
// --- Local variables --- //
unsigned int iInfoHeaderSize=0;
unsigned int iImageSize=0;
BITMAPINFO *pBitmapInfoHeader;
unsigned char *pBitmapImageBits;
// First we call GetDIBSizes() to determine the amount of
// memory that must be allocated before calling GetDIB()
// NB: GetDIBSizes() is a part of the VCL.
GetDIBSizes(mTheBitmap->Handle,
iInfoHeaderSize,
iImageSize);
// Next we allocate memory according to the information
// returned by GetDIBSizes()
pBitmapInfoHeader = new BITMAPINFO[iInfoHeaderSize];
pBitmapImageBits = new unsigned char[iImageSize];
// Call GetDIB() to convert a device dependent bitmap into a
// Device Independent Bitmap (a DIB).
// NB: GetDIB() is a part of the VCL.
GetDIB(mTheBitmap->Handle,
mTheBitmap->Palette,
pBitmapInfoHeader,
pBitmapImageBits);
delete []pBitmapInfoHeader;
ByteBuffer buf;
buf.buffer = pBitmapImageBits;
buf.size = iImageSize;
return buf;
}
所以最后的挑战似乎是获得一个与来自相机的字节数组大小相同的字节数组。如何从 TBitmap 代码中查找和删除填充字节??
【问题讨论】:
标签: c++ bitmap c++builder vcl