Macos Mac OS X Quartz CGWindowListCreateImage以1366x768分辨率对图像进行置乱 我在Mac OS X的C++项目中实现了以下代码,用于捕获桌面屏幕: int ScreenCaptureRoutines::CaptureImage(int width, int height) { CGRect captureRect; captureRect.origin.x = 0; captureRect.origin.y = 0; captureRect.size.width = width; captureRect.size.height = height; CGImageRef img = CGWindowListCreateImage(captureRect, kCGWindowListOptionOnScreenOnly, kCGNullWindowID, kCGWindowImageDefault); if(img == NULL) { fprintf(stderr, "CGWindowListCreateImage failed\n!"); return -1; } /* get pixels */ CGDataProviderRef provider = CGImageGetDataProvider(img); CFDataRef dataRef = CGDataProviderCopyData(provider); uint8_t* pixels = (uint8_t*)CFDataGetBytePtr(dataRef); BitmapUtility::SaveBitmapToFile(pixels, width, height, 32, "/Users/Main/test32.bmp"); }
该代码在分辨率为1024x768、1280x1024、1280x960、1280x768等的情况下运行良好,但它完全扰乱了1366x768的图像 这是用于保存像素的SaveBitmapFile方法:Macos Mac OS X Quartz CGWindowListCreateImage以1366x768分辨率对图像进行置乱 我在Mac OS X的C++项目中实现了以下代码,用于捕获桌面屏幕: int ScreenCaptureRoutines::CaptureImage(int width, int height) { CGRect captureRect; captureRect.origin.x = 0; captureRect.origin.y = 0; captureRect.size.width = width; captureRect.size.height = height; CGImageRef img = CGWindowListCreateImage(captureRect, kCGWindowListOptionOnScreenOnly, kCGNullWindowID, kCGWindowImageDefault); if(img == NULL) { fprintf(stderr, "CGWindowListCreateImage failed\n!"); return -1; } /* get pixels */ CGDataProviderRef provider = CGImageGetDataProvider(img); CFDataRef dataRef = CGDataProviderCopyData(provider); uint8_t* pixels = (uint8_t*)CFDataGetBytePtr(dataRef); BitmapUtility::SaveBitmapToFile(pixels, width, height, 32, "/Users/Main/test32.bmp"); },macos,resolution,quartz-graphics,distortion,Macos,Resolution,Quartz Graphics,Distortion,该代码在分辨率为1024x768、1280x1024、1280x960、1280x768等的情况下运行良好,但它完全扰乱了1366x768的图像 这是用于保存像素的SaveBitmapFile方法: void BitmapUtility::SaveBitmapToFile(u8* pBitmapBits, long lWidth, long lHeight, unsigned short wBitsPerPixel, char* lpszFileName) { BITMAPINFOHE
void BitmapUtility::SaveBitmapToFile(u8* pBitmapBits, long lWidth, long lHeight, unsigned short wBitsPerPixel, char* lpszFileName)
{
BITMAPINFOHEADER bmpInfoHeader = {0};
bmpInfoHeader.biSize = sizeBITMAPINFOHEADER;
bmpInfoHeader.biBitCount = wBitsPerPixel;
bmpInfoHeader.biClrImportant = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biCompression = BI_RGB;
bmpInfoHeader.biHeight = lHeight;
bmpInfoHeader.biWidth = lWidth;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biSizeImage = lWidth* lHeight * (wBitsPerPixel / 8);
BITMAPFILEHEADER bfh = {0};
bfh.bfType=0x4D42;
bfh.bfOffBits = sizeBITMAPINFOHEADER + sizeBITMAPFILEHEADER;
bfh.bfSize = bfh.bfOffBits + bmpInfoHeader.biSizeImage;
//Creating bitmap file
int fileDescriptor = open(lpszFileName, O_CREAT | O_WRONLY);
if (fileDescriptor == -1)
{
//returning if error encountered when opening file
return;
}
ByteBufferOutputStream bufferInfoHeader;
bufferInfoHeader.write(&bmpInfoHeader.biSize, 4);
bufferInfoHeader.write(&bmpInfoHeader.biWidth, 4);
bufferInfoHeader.write(&bmpInfoHeader.biHeight, 4);
bufferInfoHeader.write(&bmpInfoHeader.biPlanes, 2);
bufferInfoHeader.write(&bmpInfoHeader.biBitCount, 2);
bufferInfoHeader.write(&bmpInfoHeader.biCompression, 4);
bufferInfoHeader.write(&bmpInfoHeader.biSizeImage, 4);
bufferInfoHeader.write(&bmpInfoHeader.biXPelsPerMeter, 4);
bufferInfoHeader.write(&bmpInfoHeader.biYPelsPerMeter, 4);
bufferInfoHeader.write(&bmpInfoHeader.biClrUsed, 4);
bufferInfoHeader.write(&bmpInfoHeader.biClrImportant, 4);
ByteBufferOutputStream bufferFileHeader;
bufferFileHeader.write(&bfh.bfType, 2);
bufferFileHeader.write(&bfh.bfSize, 4);
bufferFileHeader.write(&bfh.bfReserved1, 2);
bufferFileHeader.write(&bfh.bfReserved2, 2);
bufferFileHeader.write(&bfh.bfOffBits, 4);
//Writing bitmap to file
ssize_t bytesWritten = write(fileDescriptor, bufferFileHeader.get()->getData(), sizeBITMAPFILEHEADER);
bytesWritten = write(fileDescriptor, bufferInfoHeader.get()->getData(), sizeBITMAPINFOHEADER);
bytesWritten = write(fileDescriptor, pBitmapBits, bmpInfoHeader.biSizeImage);
//Closing bitmap file
close(fileDescriptor);
}
SaveBitmapToFile方法仅用于测试,在实际场景中,我实际上是通过libavcodec传递捕获的像素,以将帧转换并保存为FLV格式,但最终结果是相同的,图像被置乱
有人知道为什么代码不适用于1366x768(或其他非标准的4:3或16:9分辨率)吗?首先,您应该尝试在捕获后立即将CGImageRef呈现到屏幕上,以确保数据有效 查看捕获的bmp文件。如果图像看起来像伪随机噪声,则说明像素格式错误。您需要调用CGImageGetWidth、CGImageGetHeight和CGImageGetBitsPerPixel(以及中的其他函数),以确保像素格式正确 如果您仍然可以分辨出一些像素,但行没有对齐,那么您的字节步长是错误的。1024和1280是32、64和128的倍数。1366另一方面,2除数的最大幂是2。驱动程序通常使用64字节对齐的像素步长,因为这是常见的缓存线大小。步幅等于宽度+零填充。调用CGImageGetBytesPerRow获取上一行起始地址到下一行起始地址的字节偏移量 使用跨步写入图像的伪代码:
ptr = pixels
bytesPerRow = CGImageGetBytesPerRow()
bytesPerPixel = (CGImageGetBitsPerPixel() + 7) / 8
for row = 0 to height:
write(ptr, width*bytesPerPixel)
ptr += bytesPerRow
谢谢@ErdiChen,我认为你的答案是正确的,我最终在我的应用程序中使用了以下代码:
width=width&0xfffff0代码>。不管怎样,你的回答似乎抓住了问题的本质。谢谢二地的精彩解释。它解决了我遇到的一个问题。:)