先前已经能基于GDI显示png图像,但是窗口大小和图像尺寸并不一致。注意到opencv中的imshow的窗口和图像尺寸一致,这里进行设置。

原理

CreateWindow阶段并不能确定窗口大小,但是在窗口处理函数的绘制阶段可以重新调整窗口大小。具体步骤按先后顺序:

  • 首先读取图像(而不是像之前的博客中缩写的,每次窗口paint时都重新读取图像)

  • 注册窗口

  • CreateWindowEx时候随便设置一个窗口大小

  • case WM_PAINT:阶段判断一下,如果没有调整过窗口大小,就调整

代码

#include <stdio.h>
#include <stdbool.h>
#include <windows.h>
#include "png.h" #pragma comment(lib, "D:/work/libfc/lib/libpng.lib")
#pragma comment(lib, "D:/work/libfc/lib/zlib.lib")
//#pragma comment(lib, "msimg32.lib") // for png's alpha channel typedef struct MyWindow {
HDC dc;
//HGDIOBJ image;
HBITMAP hBmp;
unsigned char* imdata;
int im_width;
int im_height;
int win_pos_x; // window position, top left point's x coordinate
int win_pos_y; // window posttion, top left point's y coordinate
bool adjusted;
} MyWindow; MyWindow* my_window;
enum ImageType {BMP, PNG}; long ReadPngData(const char *szPath, int *pnWidth, int *pnHeight, unsigned char **cbData)
{
FILE *fp = NULL;
long file_size = 0, pos = 0, mPos = 0;
int color_type = 0, x = 0, y = 0, block_size = 0; png_infop info_ptr;
png_structp png_ptr;
png_bytep *row_point = NULL; fp = fopen(szPath, "rb");
if (!fp) return -1; //文件打开错误则返回 FILE_ERROR png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); //创建png读取结构
info_ptr = png_create_info_struct(png_ptr); //png 文件信息结构
png_init_io(png_ptr, fp); //初始化文件 I\O
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0); //读取png文件 *pnWidth = png_get_image_width(png_ptr, info_ptr); //获得图片宽度
*pnHeight = png_get_image_height(png_ptr, info_ptr); //获得图片高度
color_type = png_get_color_type(png_ptr, info_ptr); //获得图片色彩深度
file_size = (*pnWidth) * (*pnHeight) * 4; //计算需要存储RGB(A)数据所需的内存大小
*cbData = (unsigned char *)malloc(file_size); //申请所需的内容, 并将 *cbData 指向申请的这块内容 row_point = png_get_rows(png_ptr, info_ptr); //读取RGB(A)数据 block_size = color_type == 6 ? 4 : 3; //根据是否具有a通道判断每次所要读取的数据大小, 具有Alpha通道的每次读4位, 否则读3位 //将读取到的RGB(A)数据按规定格式读到申请的内存中
for (x = 0; x < *pnHeight; x++)
for (y = 0; y < *pnWidth*block_size; y += block_size)
{
(*cbData)[pos++] = row_point[x][y + 2]; //B
(*cbData)[pos++] = row_point[x][y + 1]; //G
(*cbData)[pos++] = row_point[x][y + 0]; //R
(*cbData)[pos++] = row_point[x][y + 3]; //alpha
} png_destroy_read_struct(&png_ptr, &info_ptr, 0);
fclose(fp); return file_size;
} //int DEFAULT_WIDTH, DEFAULT_HIGHT;
void SetWindowSize(HWND hWnd)
{
if (my_window->adjusted == false) {
RECT WindowRect;
RECT ClientRect;
GetWindowRect(hWnd, &WindowRect);
GetClientRect(hWnd, &ClientRect);
WindowRect.right += (my_window->im_width - ClientRect.right);
WindowRect.bottom += (my_window->im_height - ClientRect.bottom);
MoveWindow(hWnd, WindowRect.left, WindowRect.top, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, true);
} my_window->adjusted = true;
} LRESULT __stdcall WindowProcedure(HWND window, unsigned int msg, WPARAM wp, LPARAM lp)
{
int image_type = PNG;
switch (msg)
{
case WM_CREATE:
if (image_type == BMP) {
my_window->hBmp = (HBITMAP)LoadImage(NULL, "D:/work/libfc/imgs/lena512.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
else if (image_type == PNG) {
//
my_window->hBmp = CreateBitmap(my_window->im_width, my_window->im_height, 32, 1, my_window->imdata);
}
if (my_window->hBmp == NULL)
MessageBox(window, "Could not load image!", "Error", MB_OK | MB_ICONEXCLAMATION);
break; case WM_PAINT:
{
SetWindowSize(window);
BITMAP bm;
PAINTSTRUCT ps; HDC hdc = BeginPaint(window, &ps);
SetStretchBltMode(hdc, COLORONCOLOR); my_window->dc = CreateCompatibleDC(hdc);
HBITMAP hbmOld = SelectObject(my_window->dc, my_window->hBmp); GetObject(my_window->hBmp, sizeof(bm), &bm); #if 1
//原样拷贝,不支持拉伸
BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, my_window->dc, 0, 0, SRCCOPY);
//AlphaBlend(hdc, 100, 0, bm.bmWidth, bm.bmHeight, my_window->dc, 0, 0, bm.bmWidth, bm.bmHeight, bf);
#else
RECT rcClient;
GetClientRect(window, &rcClient);//获得客户区的大小
int nWidth = rcClient.right - rcClient.left;//客户区的宽度
int nHeight = rcClient.bottom - rcClient.top;//客户区的高度
StretchBlt(hdc, 0, 0, nWidth, nHeight, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);//拉伸拷贝
#endif SelectObject(my_window->dc, hbmOld);
DeleteDC(my_window->dc); EndPaint(window, &ps);
}
break; case WM_DESTROY:
printf("\ndestroying window\n");
PostQuitMessage(0);
return 0L; case WM_LBUTTONDOWN:
printf("\nmouse left button down at (%d, %d)\n", LOWORD(lp), HIWORD(lp)); // fall thru
default:
//printf(".");
return DefWindowProc(window, msg, wp, lp);
}
} const char* szWindowClass = "myclass"; ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
/* Win 3.x */
wc.style = CS_DBLCLKS;
wc.lpfnWndProc = WindowProcedure;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(0);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = 0;
wc.lpszClassName = szWindowClass;
/* Win 4.0 */
wc.hIconSm = LoadIcon(0, IDI_APPLICATION); return RegisterClassEx(&wc);
} BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
my_window->win_pos_x = 600;
my_window->win_pos_y = 300; DWORD defStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU; HWND hwnd = CreateWindowEx(0, szWindowClass, "title",
defStyle, my_window->win_pos_x, my_window->win_pos_y,
my_window->im_width, my_window->im_height, 0, 0, hInstance, 0); if (!hwnd)
{
return FALSE;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd); return TRUE;
} void create_my_window(MyWindow** _my_window) {
MyWindow* my_window = (MyWindow*)malloc(sizeof(MyWindow));
my_window->dc = NULL;
my_window->imdata = NULL;
my_window->hBmp = NULL; my_window->adjusted = false; *_my_window = my_window; // write back
} void destroy_my_window(MyWindow* my_window) {
if (my_window) {
free(my_window);
}
} int main()
{
printf("hello world!\n"); create_my_window(&my_window); int im_width, im_height;
unsigned char* imdata;
ReadPngData("D:/work/libfc/imgs/op.png", &im_width, &im_height, &imdata);
my_window->im_width = im_width;
my_window->im_height = im_height;
my_window->imdata = imdata; HINSTANCE hInstance = GetModuleHandle(0);
int nCmdShow = SW_SHOWDEFAULT; MyRegisterClass(hInstance); if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
} MSG msg;
while (GetMessage(&msg, 0, 0, 0)) {
DispatchMessage(&msg);
} destroy_my_window(my_window);
free(imdata); return 0; }

参考

设置窗口客户区大小的一种办法

GDI显示图像时设定窗口大小为图像大小的更多相关文章

  1. C# (GDI+相关) 图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果) (转)

    C#图像处理   (各种旋转.改变大小.柔化.锐化.雾化.底片.浮雕.黑白.滤镜效果)     一.各种旋转.改变大小   注意:先要添加画图相关的using引用.   //向右旋转图像90°代码如下 ...

  2. Matlab绘图基础——图形绘制的插值  以及 图像大小的重采样

    使用说明:图形绘制时的插值 interp1   %1-D data interpolation interpft  %使用fft算法插值     %将原数据x转换到频率域,再逆转换回来更密集的数据采样 ...

  3. [译]Android调整图像大小的一些方法

    翻译自 某大神在Stack Overflow里的自问自答 (一般我们将Bitmap翻译为位图,但为了更好理解,在本文中我将它翻译成图像): 我们在开发的时候,经常需要从服务器中加载图像到客户端中,但有 ...

  4. AForge,Emgu.CV抓拍图像大小

    原文:AForge,Emgu.CV抓拍图像大小 2017年,忙忙碌碌地过去了,象往年一样,依然没有时间上CSDN,博客园. 这一年是打工以来最辛苦的一年. 这一年用了不少自己没有接触过的东西.如人脸识 ...

  5. CSS 是怎样确定图像大小的?

    本文转自奇舞周刊学习使用侵权删 先来看个例子,热热身. 上面这张图像的原始尺寸是:宽 54px 高 49px. 那么,在以下代码中,每张图像显示的最终尺寸是多少? https://p1.ssl.qhi ...

  6. python 修改图像大小和分辨率

    1 概念: 分辨率,指的是图像或者显示屏在长和宽上各拥有的像素个数.比如一张照片分辨率为1920x1080,意思是这张照片是由横向1920个像素点和纵向1080个像素点构成,一共包含了1920x108 ...

  7. 如何在 HTML 中调整图像大小?

    了解在 HTML 中调整图像大小的不同技术.何时应避免在浏览器端调整大小,以及在 Web 上操作和提供图像的正确方法. 如果您的图像不适合布局,您可以在 HTML 中调整其大小.在 HTML 中调整图 ...

  8. C#中如何调整图像大小

    在本篇文章中,我将介绍如何在C#中来调整你想要的图像大小.要实现这一目标,我们可以采取以下几个步骤: 1.首先要获取你想要调整大小的图像: string path = Server.MapPath(& ...

  9. VC++ 在使用 CImage 的Draw 输入一个图像时,有时候会造成图像失真严重,解决的方法如下

    VC++  在使用 CImage 的Draw 输入一个图像时,有时候会造成图像失真严重,解决的方法如下 失真主要是由于变形造成的.只要设置一下变形的模式就可以了 ::SetStretchBltMode ...

随机推荐

  1. 011-MySQL Query Cache 查询缓存设置操作

    一.概述 MySQL Query Cache 会缓存select 查询,安装时默认是开启的,但是如果对表进行INSERT, UPDATE, DELETE, TRUNCATE, ALTER TABLE, ...

  2. 【jmeter】使用csv文件生成用户名和密码列表

    介绍 在[jmeter]使用jmeter进行测试-示例 中介绍了jmeter的基本使用,本文将介绍如何使用csv文件生成多个用户名. 应用场景 实际测试中,经常需要模拟多个用户进行负载测试,而用户名和 ...

  3. intellij查找接口的实现类

    拿MyBatis的SqlSession为例 第一步:先找到这个接口 第二步:右击选择 再选择 第三步: 会得到如下 右击Closeable,因为SqlSession实现了它,选择Show Inplem ...

  4. Nexus上传npm包

    1.创建npm仓库 私服仓库npm-hosted 代理仓库npm-proxy npm-group 创建成功 在工程的根目录下创建文件 .npmrc registry=http://xxx:8081/n ...

  5. android文件分享在android7.0以上版本报错的解决方案

    最近在使用蓝牙进行文件分享时,出现了一个奇怪的问题.同样的代码在android5.1上可以顺利运行,但是在android7.0上就运行失败.出现如下的错误: Caused by: android.os ...

  6. .NET Core 之 Nancy 基本使用

    Nancy简介 Nancy是一个轻量级的独立的框架,下面是官网的一些介绍: Nancy 是一个轻量级用于构建基于 HTTP 的 Web 服务,基于 .NET 和 Mono 平台,框架的目标是保持尽可能 ...

  7. javascript中 for in 、for 、forEach 、for of 、Object.keys().

    一 .for ..in 循环 使用for..in循环时,返回的是所有能够通过对象访问的.可枚举的属性,既包括存在于实例中的属性,也包括存在于原型中的实例.这里需要注意的是使用for-in返回的属性因各 ...

  8. 图论 --- 三维空间bfs

    <传送门> [题目大意] 给你一个三维的迷宫,让你计算从入口走到出口最少步数. [题目分析] 其实和二维迷宫还是一样的,还是用队列来做,由于BFS算法一般是不需要回溯的,所以我们就用不着还 ...

  9. LeetCode 5214. 最长定差子序列(Java)HashMap

    题目: 5214. 最长定差子序列 给你一个整数数组 arr 和一个整数 difference,请你找出 arr 中所有相邻元素之间的差等于给定 difference 的等差子序列,并返回其中最长的等 ...

  10. Python-MySQL学习

    内容来源(有删改):https://blog.csdn.net/hzw6991/article/details/87893761 上面链接同步视频地址:https://www.bilibili.com ...