Скриншот экрана хранится в буфере в виде байт RGB. Нужно независимо от его исходных размеров привести его к разрешению 1280х720.
Как это сделать на С++ (на выходе тоже должен быть буфер с данными)?
Ну, можно отресайзить любой библиотекой, которая работает с графикой (opencv, ImageMagic, тысячи их). Можно отресайзить своей функцией - билинейная интерполяция пишется достаточно просто. Пример на opencv:
// допустим, картинка хранится в каком-нибудь std::string
std::string image_source = "...";
std::vector<unsigned char> bytes(image_source.data(), image_source.data() + image_source.size());
cv::Mat image = cv::imdecode(bytes, CV_LOAD_IMAGE_COLOR);
cv::resize(image, image, cv::Size(1280, 720));
// обратно в буфер
std::vector<unsigned char> resized;
cv::imencode(".png", image, resized);
Дополняю ответ.
По просьбе в комментарии привожу "ручную" реализацию билинейной интерполяции. Поскольку картинку в любом случае надо чем-то прочитать, я для простоты выбрал для этого libjpg.
Ошибки (для краткости) не обрабатываются.
Функции чтения картинки тоже приводятся, чтобы лучше было понятно, как именно картинка хранится в памяти (3 канала, одномерный массив).
Билинейная интерполяция - в функции im_scale_factor()
.
#include <jpeglib.h>
struct image_t{
image_t() : w(0), h(0), pixels(0) {}
unsigned char *pixels;
unsigned int w;
unsigned int h;
};
struct pixel_t {
unsigned char b;
unsigned char g;
unsigned char r;
};
bool read_jpg(const char *path, image_t *image)
{
FILE *file = fopen(path, "rb");
struct jpeg_decompress_struct info;
struct jpeg_error_mgr err;
info.err = jpeg_std_error( &err );
jpeg_create_decompress( &info );
jpeg_stdio_src( &info, file );
jpeg_read_header( &info, true );
jpeg_start_decompress( &info );
int w = info.output_width;
int h = info.output_height;
int numChannels = info.num_components; // 3 = RGB, 4 = RGBA
unsigned long dataSize = w * h * numChannels;
// read RGB(A) scanlines one at a time into data[]
unsigned char *data = (unsigned char *)malloc( dataSize );
unsigned char* rowptr;
while ( info.output_scanline < h )
{
rowptr = data + info.output_scanline * w * numChannels;
jpeg_read_scanlines( &info, &rowptr, 1 );
}
jpeg_finish_decompress( &info );
fclose( file );
image->pixels = data;
image->h = h;
image->w = w;
return true;
}
void write_jpg(const char *path, image_t *image)
{
struct jpeg_compress_struct cinfo;
jpeg_create_compress(&cinfo);
FILE *fp = fopen(path, "w+");
jpeg_stdio_dest(&cinfo, fp);
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
cinfo.image_width = image->w;
cinfo.image_height = image->h;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_start_compress(&cinfo, FALSE);
unsigned char *stride = (unsigned char *)malloc(image->w * 3);
unsigned char *data = (unsigned char*)image->pixels;
JSAMPROW row_pointer[1];
for (int i = 0; i < image->h; ++i) {
memcpy(stride, data + i * image->w * 3, image->w * 3);
row_pointer[0] = stride;
jpeg_write_scanlines(&cinfo, &stride, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
fclose(fp);
}
pixel_t pixel(image_t *im, int h, int w)
{
pixel_t p;
p.b = im->pixels[h*im->w*3 + w*3 + 0];
p.g = im->pixels[h*im->w*3 + w*3 + 1];
p.r = im->pixels[h*im->w*3 + w*3 + 2];
return p;
}
void im_scale_factor(image_t *src, image_t *dest, float h_factor, float w_factor)
{
for (int i = 0; i < dest->h; ++i) {
float fY = ((float) i) / h_factor;
int iY = (int) fY;
for (int j = 0; j < dest->w; ++j) {
float fX = ((float) j) / w_factor;
int iX = (int) fX;
pixel_t q11 = pixel(src, iY, iX);
pixel_t q12 = pixel(src, iY + 1, iX);
pixel_t q21 = pixel(src, iY, iX + 1);
pixel_t q22 = pixel(src, iY + 1, iX + 1);
unsigned char r1_b = (iX + 1 - fX)/(iX + 1 - iX)*q11.b + (fX - iX)/(iX + 1 - iX)*q21.b;
unsigned char r1_g = (iX + 1 - fX)/(iX + 1 - iX)*q11.g + (fX - iX)/(iX + 1 - iX)*q21.g;
unsigned char r1_r = (iX + 1 - fX)/(iX + 1 - iX)*q11.r + (fX - iX)/(iX + 1 - iX)*q21.r;
unsigned char r2_b = (iX + 1 - fX)/(iX + 1 - iX)*q12.b + (fX - iX)/(iX + 1 - iX)*q22.b;
unsigned char r2_g = (iX + 1 - fX)/(iX + 1 - iX)*q12.g + (fX - iX)/(iX + 1 - iX)*q22.g;
unsigned char r2_r = (iX + 1 - fX)/(iX + 1 - iX)*q12.r + (fX - iX)/(iX + 1 - iX)*q22.r;
unsigned char b = (iY + 1 - fY)/(iY + 1 - iY)*r1_b + (fY - iY)/(iY + 1 - iY)*r2_b;
unsigned char g = (iY + 1 - fY)/(iY + 1 - iY)*r1_g + (fY - iY)/(iY + 1 - iY)*r2_g;
unsigned char r = (iY + 1 - fY)/(iY + 1 - iY)*r1_r + (fY - iY)/(iY + 1 - iY)*r2_r;
dest->pixels[i*dest->w*3 + j*3 + 0] = b;
dest->pixels[i*dest->w*3 + j*3 + 1] = g;
dest->pixels[i*dest->w*3 + j*3 + 2] = r;
}
}
}
void im_scale(image_t *src, image_t *dest, int h, int w)
{
std::cerr << "scale to : " << w << " x " << h << "\n";
dest->h = h;
dest->w = w;
dest->pixels = (unsigned char*)malloc(h * w * 3);
float scale_x = w / (float)src->w;
float scale_y = h / (float)src->h;
im_scale_factor(src, dest, scale_y, scale_x);
}
int main(int argc, char *argv[])
{
if (argc < 3)
{
std::cerr << "Usage: " << argv[0] << " in out" << std::endl;
return -1;
}
image_t image;
read_jpg(argv[1], &image);
image_t result;
im_scale(&image, &result, 1280, 720);
write_jpg(argv[2], &result);
return 0;
}
Для использования потребуется libjpg:
g++ main.cpp -ljpeg
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
При добавлении спецификатора final мы запрещаем переопределять метод в базовом классеТогда зачем нам нужен в базовом классе создавать виртуальный...
Как мне в Qt5 настроить так чтобы на одном листе A4 печатать два формата A5?