Делаю параграмму на С++ которая через интернет будет передавать скриншот рабочого стола и сохранять на другом компе.
Пока что питаюсь просто сделать скриншот и сохранить в форматах bmp и tga, но изображение в перфом формате выходит какое то волнистое, а во втором косое, помогите пожалуйста исправить.
#include<Windows.h>
#include<stdio.h>
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
// Определение контекстов
HDC ScreenDC = GetDC(0);
HDC MemoryDC = CreateCompatibleDC(ScreenDC);
// Фиксация размеров экрана
int ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
// Создание и частичное заполнение структуры формата
BITMAPINFO BMI;
BMI.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BMI.bmiHeader.biWidth = ScreenWidth;
BMI.bmiHeader.biHeight = -ScreenHeight; // Отрицательное значение высоты, чтобы изображение не было перевёрнутым
BMI.bmiHeader.biSizeImage = ScreenWidth * ScreenHeight * 3; // Ширина * Высота * Количество_цветов_на_пиксель
BMI.bmiHeader.biCompression = BI_RGB;
BMI.bmiHeader.biBitCount = 24;
BMI.bmiHeader.biPlanes = 1;
DWORD ScreenshotSize;
ScreenshotSize = BMI.bmiHeader.biSizeImage; // ScreenshotSize - глобальная переменная типа int, может меняться в ходе выполнения программы
unsigned char *ImageBuffer; // Указатель на блок данных BGR, управляемый HBITMAP (да, именно BGR - не RGB)
HBITMAP hBitmap = CreateDIBSection(ScreenDC,&BMI,DIB_RGB_COLORS,(void**)&ImageBuffer,0,0);
SelectObject(MemoryDC, hBitmap);
BitBlt(MemoryDC, 0, 0, ScreenWidth, ScreenHeight, ScreenDC , 0, 0, SRCCOPY);
// Контексты больше не нужны
DeleteDC(MemoryDC);
ReleaseDC(NULL, ScreenDC);
// Если требуется RGB вместо BGR - следующий цикл перевернёт нужные байты
for(int i = 0; i < ScreenshotSize; i += 3){
unsigned char ColorValue = ImageBuffer[i];
ImageBuffer[i] = ImageBuffer[i + 2];
ImageBuffer[i + 2] = ColorValue;
}
//bmp========================================================
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFOHEADER));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biHeight = GetSystemMetrics(SM_CYSCREEN);
bmi.bmiHeader.biWidth = GetSystemMetrics(SM_CXSCREEN);
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage =ScreenWidth * ScreenHeight * 3 ;
FILE *F=fopen("screen.bmp","w");
int nBitsOffset = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
LONG lImageSize = ScreenWidth * ScreenHeight * 3;
LONG lFileSize = nBitsOffset + lImageSize;
BITMAPFILEHEADER bmfh;
bmfh.bfType = 'B'+('M'<<8);
bmfh.bfOffBits = nBitsOffset;
bmfh.bfSize = lFileSize;
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
UINT nWrittenFileHeaderSize = fwrite(&bmfh,1,sizeof(BITMAPFILEHEADER),F);
UINT nWrittenInfoHeaderSize = fwrite(&bmi,1,sizeof(BITMAPINFOHEADER),F);
UINT nWrittenDIBDataSize =fwrite(ImageBuffer,1,ScreenWidth * ScreenHeight * 3,F);
UINT total=nWrittenDIBDataSize +nWrittenInfoHeaderSize+nWrittenFileHeaderSize ;
fclose(F);
//tga====================================================================================================8888888888888888888888888888888
//
// Теперь нужно записать полученные данные в файл Screen.tga.
//
FILE *sFile = 0; // Дескриптор файла
// Обьявляем переменные, которые понадобятся нам в дальнейшем:
unsigned char tgaHeader[12] = {0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned char header[6];
unsigned char tempColors = 0;
// Открываем файл скриншота
sFile = fopen("Screen.tga", "wb");
// Проверяем, правильно ли произошло открытие
if(!sFile){
return 0;
}
// Записываем ширину и высоту:
header[0] = ScreenWidth % 256;
header[1] = ScreenWidth / 256;
header[2] = ScreenHeight % 256;
header[3] = ScreenHeight / 256;
header[4] = BMI.bmiHeader.biBitCount;
header[5] = 0;
// Записываем хидеры в начало файла:
fwrite(tgaHeader, sizeof(tgaHeader), 1, sFile);
fwrite(header, sizeof(header), 1, sFile);
// Записываем данные изображения:
fwrite(ImageBuffer, BMI.bmiHeader.biSizeImage, 1, sFile);
// Закрываем файл
fclose(sFile);
// Удаляем ненужные теперь данные
// Используем ImageBuffer как нам хочется... после удаляем его хендлер (HBITMAP) для избежания утечки памяти
DeleteObject(hBitmap);
}
bmp в этот раз не волнистое
tga
Новая ошибка
В HBITMAP
каждая строка пикселей выравнивается до границы, кратной 4-м байтам. Поэтому нельзя просто так брать и писать
fwrite(ImageBuffer,1,ScreenWidth * ScreenHeight * 3,F)
Если вам не критично, можете принудительно уменьшать ScreenWidth
до величины, кратной 4-м, а потом делать скриншот:
int ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
ScreenWidth = ((ScreenWidth - 1) / 4 + 1) * 4;
Либо сохранять по одной линии, отступая каждый раз необходимое количество байт.
P.S. Чтобы убедиться в том, что я говорю, сделайте разрешение экрана кратное 4-м.
P.P.S. У Вас там картинка перевернута
Вы не проверяете результаты вызова большинства функций.
После BitBlt
необходимо вернуть контекст в первоначальное состояние, выбрав в него исходный битмап.
::HBITMAP const initial_bitmap_handle(::SelectObject(MemoryDC, hBitmap));
assert(NULL != blt_result);
::BOOL const blt_result(::BitBlt(MemoryDC, 0, 0, ScreenWidth, ScreenHeight, ScreenDC , 0, 0, SRCCOPY));
assert(FALSE != blt_result);
::HBITMAP const deselected_bitmap_handle(::SelectObject(MemoryDC, old_bitmap_handle));
assert(deselected_bitmap_handle == hBitmap);
::BOOL const delete_dc_result(::DeleteDC(MemoryDC));
assert(FALSE != delete_dc_result);
b
: FILE *F=fopen("screen.bmp","wb");
Вот результат с bmp то же что и сначала, а tga всё идиально
#include<Windows.h>
#include<stdio.h>
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
// Определение контекстов
HDC ScreenDC = GetDC(0);
HDC MemoryDC = CreateCompatibleDC(ScreenDC);
// Фиксация размеров экрана
//int ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
int ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
ScreenWidth = ((ScreenWidth - 1) / 4 + 1) * 4;
// Создание и частичное заполнение структуры формата
BITMAPINFO BMI;
BMI.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BMI.bmiHeader.biWidth = ScreenWidth;
BMI.bmiHeader.biHeight = ScreenHeight; // Отрицательное значение высоты, чтобы изображение не было перевёрнутым
BMI.bmiHeader.biSizeImage = ScreenWidth * ScreenHeight * 3; // Ширина * Высота * Количество_цветов_на_пиксель
BMI.bmiHeader.biCompression = BI_RGB;
BMI.bmiHeader.biBitCount = 24;
BMI.bmiHeader.biPlanes = 1;
DWORD ScreenshotSize;
ScreenshotSize = BMI.bmiHeader.biSizeImage; // ScreenshotSize - глобальная переменная типа int, может меняться в ходе выполнения программы
unsigned char *ImageBuffer; // Указатель на блок данных BGR, управляемый HBITMAP (да, именно BGR - не RGB)
HBITMAP hBitmap = CreateDIBSection(ScreenDC,&BMI,DIB_RGB_COLORS,(void**)&ImageBuffer,0,0);
SelectObject(MemoryDC, hBitmap);
BitBlt(MemoryDC, 0, 0, ScreenWidth, ScreenHeight, ScreenDC , 0, 0, SRCCOPY);
// Контексты больше не нужны
DeleteDC(MemoryDC);
ReleaseDC(NULL, ScreenDC);
// Если требуется RGB вместо BGR - следующий цикл перевернёт нужные байты
//for(int i = 0; i < ScreenshotSize; i += 3){
// unsigned char ColorValue = ImageBuffer[i];
// ImageBuffer[i] = ImageBuffer[i + 2];
// ImageBuffer[i + 2] = ColorValue;
//}
//bmp========================================================
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFOHEADER));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biHeight = ScreenHeight;
bmi.bmiHeader.biWidth = ScreenWidth;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage =ScreenWidth * ScreenHeight * 3 ;
FILE *F=fopen("screen.bmp","w");
int nBitsOffset = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
LONG lImageSize = ScreenWidth * ScreenHeight * 3;
LONG lFileSize = nBitsOffset + lImageSize;
BITMAPFILEHEADER bmfh;
bmfh.bfType = 'B'+('M'<<8);
bmfh.bfOffBits = nBitsOffset;
bmfh.bfSize = lFileSize;
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
UINT nWrittenFileHeaderSize = fwrite(&bmfh,1,sizeof(BITMAPFILEHEADER),F);
UINT nWrittenInfoHeaderSize = fwrite(&bmi,1,sizeof(BITMAPINFOHEADER),F);
UINT nWrittenDIBDataSize =fwrite(ImageBuffer,1,ScreenWidth * ScreenHeight * 3,F);
UINT total=nWrittenDIBDataSize +nWrittenInfoHeaderSize+nWrittenFileHeaderSize ;
fclose(F);
//tga====================================================================================================8888888888888888888888888888888
//
// Теперь нужно записать полученные данные в файл Screen.tga.
//
FILE *sFile = 0; // Дескриптор файла
// Обьявляем переменные, которые понадобятся нам в дальнейшем:
unsigned char tgaHeader[12] = {0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned char header[6];
unsigned char tempColors = 0;
// Открываем файл скриншота
sFile = fopen("Screen.tga", "wb");
// Проверяем, правильно ли произошло открытие
if(!sFile){
return 0;
}
// Записываем ширину и высоту:
header[0] = ScreenWidth % 256;
header[1] = ScreenWidth / 256;
header[2] = ScreenHeight % 256;
header[3] = ScreenHeight / 256;
header[4] = BMI.bmiHeader.biBitCount;
header[5] = 0;
// Записываем хидеры в начало файла:
fwrite(tgaHeader, sizeof(tgaHeader), 1, sFile);
fwrite(header, sizeof(header), 1, sFile);
// Записываем данные изображения:
fwrite(ImageBuffer, BMI.bmiHeader.biSizeImage, 1, sFile);
// Закрываем файл
fclose(sFile);
// Удаляем ненужные теперь данные
// Используем ImageBuffer как нам хочется... после удаляем его хендлер (HBITMAP) для избежания утечки памяти
DeleteObject(hBitmap);
}
Запечатал всё в функции , подозреваю что параграмма может не работать если глубина цвета экрана будет изменена на экране пользователя. Потерь памяти нет.
#include<Windows.h>
#include<stdio.h>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
struct ScrenData
{
int ScreenWidth,
ScreenHeigh;
unsigned char *ImageBuffer;
};
bool Scren(bool (*OBR)(ScrenData &SDt,char* url),char* url)
{
ScrenData SDt;
// Определение контекстов
HDC ScreenDC = GetDC(0);
HDC MemoryDC = CreateCompatibleDC(ScreenDC);
// Фиксация размеров экрана
//int ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
SDt.ScreenHeigh = GetSystemMetrics(SM_CYSCREEN);
SDt.ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
SDt.ScreenWidth = ((SDt.ScreenWidth - 1) / 4 + 1) * 4;
// Создание и частичное заполнение структуры формата
BITMAPINFO BMI;
BMI.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BMI.bmiHeader.biWidth = SDt.ScreenWidth;
BMI.bmiHeader.biHeight = SDt.ScreenHeigh; // Отрицательное значение высоты, чтобы изображение не было перевёрнутым
BMI.bmiHeader.biSizeImage = SDt.ScreenWidth * SDt.ScreenHeigh * 3; // Ширина * Высота * Количество_цветов_на_пиксель
BMI.bmiHeader.biCompression = BI_RGB;
BMI.bmiHeader.biBitCount = 24;
BMI.bmiHeader.biPlanes = 1;
DWORD ScreenshotSize;
ScreenshotSize = BMI.bmiHeader.biSizeImage; // ScreenshotSize - глобальная переменная типа int, может меняться в ходе выполнения программы
//unsigned char *ImageBuffer; // Указатель на блок данных BGR, управляемый HBITMAP (да, именно BGR - не RGB)
HBITMAP hBitmap = CreateDIBSection(ScreenDC,&BMI,DIB_RGB_COLORS,(void**)&SDt.ImageBuffer,0,0);
SelectObject(MemoryDC, hBitmap);
BitBlt(MemoryDC, 0, 0, SDt.ScreenWidth, SDt.ScreenHeigh, ScreenDC , 0, 0, SRCCOPY);
bool ret = OBR(SDt,url); //Отправить даные в функцыю оброботки
// Контексты больше не нужны
DeleteDC(MemoryDC);
ReleaseDC(NULL, ScreenDC);
DeleteObject(hBitmap);
//delete [] SDt.ImageBuffer;
return ret;
}
bool SaveTga(ScrenData &SDt,char* url)
{
//
// Теперь нужно записать полученные данные в файл Screen.tga.
//
FILE *sFile = 0; // Дескриптор файла
// Обьявляем переменные, которые понадобятся нам в дальнейшем:
unsigned char tgaHeader[12] = {0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned char header[6];
unsigned char tempColors = 0;
// Открываем файл скриншота
sFile = fopen(url, "wb");
// Проверяем, правильно ли произошло открытие
if(!sFile){
return 0;
}
// Записываем ширину и высоту:
header[0] = SDt.ScreenWidth % 256;
header[1] = SDt.ScreenWidth / 256;
header[2] = SDt.ScreenHeigh % 256;
header[3] = SDt.ScreenHeigh / 256;
header[4] = 24;
header[5] = 0;
// Записываем хидеры в начало файла:
fwrite(tgaHeader, sizeof(tgaHeader), 1, sFile);
fwrite(header, sizeof(header), 1, sFile);
// Записываем данные изображения:
fwrite(SDt.ImageBuffer, SDt.ScreenWidth * SDt.ScreenHeigh * 3, 1, sFile);
// Закрываем файл
fclose(sFile);
// Удаляем ненужные теперь данные
return 1;
}
bool OBR1(ScrenData &SDt,char* url)
{
//Тут можна отправить кудато даные или передать в функцыю сохранения
return SaveTga(SDt,url);
}
int main()
{
/*
std::string url;
int i = 0;
while(1)
{
{
url = "Scren";
char D[10];
itoa(i,D,10);
url += D;
url += ".tga";
Scren(OBR1,(char*)url.c_str()); //Сделать скриншот и даные отправить в функцыю OBR можна сразу отправлять в SaveTga
i++;
}
}
*/
Scren(OBR1,"scren.tga"); //Сделать скриншот и даные отправить в функцыю OBR можна сразу отправлять в SaveTga
// Используем ImageBuffer как нам хочется... после удаляем его хендлер (HBITMAP) для избежания утечки памяти
//DeleteObject(hBitmap);
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Как связать QML интерфейс и некий гибрид MVC паттерна ? Суть в том, что есть класс Model и в нем поля string и bool и методы get/setДля контроля моделями создается...
ЗдравствуйтеНедавно получил задание от друга, создать простую программу, которая поможет работать ему с другой программой
Доброго времени сутокЕсть задание: реализовать программу, которая меняет местами последнюю строку и первый столбик квадратной матрицы