先前已经能基于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. Docker入门-docker运行springboot应用(二)

    环境准备 jdk8 安装docker 镜像加速器配置 docker私有仓库 springboot工程的jar包 docker部署项目 dockfile Dockfile是一种被Docker程序解释的脚 ...

  2. Superset配置mysql数据源

    1.添加mysql数据源 测试连接的时候遇到 No module named 'MySQLdb'" 安装mysqlclient pip install mysqlclient 如果遇到 ER ...

  3. Node 脚本的调试工具

    2016年,Node 决定将 Chrome 浏览器的"开发者工具"作为官方的调试工具,使得 Node 脚本也可以使用图形界面调试 1.准备 创建目录 D:\nodejs>mk ...

  4. Python键盘按键模拟

    有时候我们需要使用python执行一些脚本,可能需要让程序自动按键或自动点击鼠标,下面的代码实现了对键盘的模拟按键, 需要安装pypiwin32,当然也可以直接用ctypes来实现. 输入:pip i ...

  5. obj.GetType().GetCustomAttributes

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  6. java内存模型,内存区域

    Java虚拟机内存区域总结:Java虚拟机相当于一个抽象的计算机操作系统, 其管理的内从区域大体上可以分为栈和堆,就像c或c++中对内存的分类一样, 但这样的分类对于Java虚拟机来说太过粗浅, 实际 ...

  7. 阿里云 安装docker

    转  https://www.jianshu.com/p/f02d63ee98e0

  8. VirtualBox 配置 CentOS7网卡信息

    在实际配置虚拟机的过程中,网络配置时候一个很繁琐的过程,经常一个点没注意到,就访问不了了.在此,做一个简单的教程以供后续使用时可以参考! 方法一: 使用NAT网络 1. 选择网卡 安装centos7的 ...

  9. 更改ubuntu桌面环境

    1.修改桌面环境 update-alternatives --config x-session-manager 2.卸载某一种ppa源下面的软件 sudo apt-get install ppa-pu ...

  10. js中Boolean类型和Number类型的一些常见方法

    Boolean类型 Boolean类型重写了valueOf() 方法, 返回基本布尔类型值true或false,重写了toString() 方法,返回基本字符串"true" 和 & ...