Я написал простую программу на C++, которая захватывает экран с помощью BitBlt из Windows API и сохраняет его в файл, и некоторые разрешения, кажется, дают ошибки памяти, и я не могу найти шаблон/проблему в своем коде.
#include <iostream>
#include <windows.h>
#include <fstream>
BYTE* CaptureScreen(int x, int y, int width, int height);
bool CaptureScreenAndSaveToFile(int x, int y, int width, int height, const char* filename) {
BYTE* imageData = CaptureScreen(x, y, width, height);
if (imageData == nullptr) {
return false;
}
// Open file for writing
std::ofstream outFile(filename, std::ios::binary);
if (!outFile.is_open()) {
delete[] imageData; // Free allocated memory
return false;
}
// Write BMP file header
BITMAPFILEHEADER bmpFileHeader;
bmpFileHeader.bfType = 0x4D42; // 'BM'
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + width * height * 3; // Total file size
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // Offset to pixel data
outFile.write(reinterpret_cast<const char*>(&bmpFileHeader), sizeof(BITMAPFILEHEADER));
// Write BMP info header
BITMAPINFOHEADER bmpInfoHeader;
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfoHeader.biWidth = width;
bmpInfoHeader.biHeight = -height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 24; // 24 bits per pixel (RGB)
bmpInfoHeader.biCompression = BI_RGB;
bmpInfoHeader.biSizeImage = 0; // Size of the pixel data (can be set to 0 for BI_RGB compression)
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biClrImportant = 0;
outFile.write(reinterpret_cast<const char*>(&bmpInfoHeader), sizeof(BITMAPINFOHEADER));
// Write image data
outFile.write(reinterpret_cast<const char*>(imageData), width * height * 3);
// Close the file
outFile.close();
// Free allocated memory
delete[] imageData;
return true;
}
BYTE* CaptureScreen(int x, int y, int width, int height) {
BYTE* result = nullptr; // Initialize the result pointer to nullptr
HDC hdcTemp, hdc;
BYTE* bitPointer;
hdc = GetDC(HWND_DESKTOP);
if (hdc != NULL)
{
hdcTemp = CreateCompatibleDC(hdc);
if (hdcTemp != NULL)
{
BITMAPINFO bitmap;
bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
bitmap.bmiHeader.biWidth = width;
bitmap.bmiHeader.biHeight = -height; // Negative height to ensure the bitmap is top-down
bitmap.bmiHeader.biPlanes = 1;
bitmap.bmiHeader.biBitCount = 24;
bitmap.bmiHeader.biCompression = BI_RGB;
bitmap.bmiHeader.biSizeImage = 0;
bitmap.bmiHeader.biClrUsed = 0;
bitmap.bmiHeader.biClrImportant = 0;
HBITMAP hBitmap = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)&bitPointer, NULL, NULL);
if (hBitmap != NULL)
{
HBITMAP hPrevBitmap = (HBITMAP)SelectObject(hdcTemp, hBitmap); // Added explicit cast
BitBlt(hdcTemp, 0, 0, width, height, hdc, x, y, SRCCOPY); // Use x, y, width, height
// Allocate memory on the heap and copy the buffer
result = new BYTE[width * height * 3];
if (result != nullptr) {
memcpy(result, bitPointer, width * height * 3);
}
// Select and delete objects
SelectObject(hdcTemp, hPrevBitmap);
DeleteObject(hBitmap);
}
DeleteDC(hdcTemp);
}
ReleaseDC(HWND_DESKTOP, hdc);
}
return result;
}
int main() {
CaptureScreenAndSaveToFile(125, 125, 35, 35, "Hello.png");
}
Я заметил, что для некоторых разрешений сохраненный снимок экрана не доступен для просмотра, а когда я пытаюсь напрямую получить доступ к байт-буферу, выдается ошибка о недоступной памяти. Вот решения, которые я пробовал, но они не увенчались успехом:
Я уверен, что есть еще много значений ширины и высоты, которые «не работают», но я не могу найти здесь закономерность/проблему. Любая помощь будет оценена по достоинству.
Можете ли вы уточнить? Редактировать: Я понял это, тысм.
Ошибку, которой можно легко избежать, если не пытаться записывать файл изображения BMP, а позволить компоненту обработки изображений Windows сделать это за вас.





Как сказал @RbMm и отправил темы @drescherjm,
Это количество байтов, на которое рассчитывается каждая строка растрового изображения;
Изображение в оттенках серого (biBitCount=8)Цветное изображение (biBitCount=24)
bmpWidth — ширина растрового изображения, т. е. количество блоков пикселей в строке.
Если вы формируете, (n), разделенное на (n+i), равно 0, (n и i — натуральные числа)
Количество байтов в строке сохраненных данных изображения кратно 4.
Поэтому +3 – это страх не уложиться в кратное 4.
Если оно кратно 4, результат такой же, как если бы он не был +3.
Если оно не кратно 4, результат увеличивается на 1 позицию.
/4*4, разделенное на четыре, умноженное на четыре, дает данные, кратные 4. Если оно не кратно 4, остаток будет уменьшен. Например, в случае шейпинга 17/4 = 4 (в норме это 4 и 1/4), и компьютер напрямую вычисляет, что оно равно 4. Умножьте на четыре и получите 16. То есть классифицируем 17 как кратное 4 = 16;
каждая строка сканирования должна быть выровнена по 4 байта. итак
((3*width+3)&~3)