2022/06/04(土) [n年前の日記]
#1 [xlib] Xlibについて勉強中その3
_昨日、
Pixmapを拡大縮小する関数を書いて実験していたけれど、本当に毎フレーム拡大縮小処理ができているのかが気になってきたので、見た目で分かるように処理を書き換えてみた。
環境は、Ubuntu Linux 20.04 LTS。Windows10 x64 21H2 + VMware Player 上で動かしている。
結果はこんな感じに。それなりの速度で拡大縮小できていることが視覚的にも分かった。
環境は、Ubuntu Linux 20.04 LTS。Windows10 x64 21H2 + VMware Player 上で動かしている。
結果はこんな感じに。それなりの速度で拡大縮小できていることが視覚的にも分かった。
◎ ソース。 :
ソースは以下。
_06scale3.c
使用画像は以下。
_bg01.xpm
_bg02.xpm
Makefileの例。
_Makefile
コンパイルは以下。実行バイナリ 06scale3 が生成される。
実行は以下。
_06scale3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include <math.h>
#include <time.h>
/* include xpm binary */
#include "bg01.xpm"
#define XPM_W 640
#define XPM_H 360
#define XPM_NAME bg01_xpm
/*
#include "bg02.xpm"
#define XPM_W 320
#define XPM_H 180
#define XPM_NAME bg02_xpm
*/
/* kind. 0: slow, 1: fast */
#define SCALING_KIND 1
#define WIN_X 0
#define WIN_Y 64
#define BORDER 0
#ifndef M_PI
#define M_PI 3.14159265358979
#endif
#define deg2rad(x) (x * M_PI / 180.0)
/* get a color value from a color name */
static unsigned long
get_color(Display *dpy, char *colorname)
{
Colormap cmap;
XColor near_color, true_color;
cmap = DefaultColormap(dpy, DefaultScreen(dpy));
XAllocNamedColor(dpy, cmap, colorname, &near_color, &true_color);
return near_color.pixel;
}
/* scale Pixmap */
static void
scale_pixmap(Display *dpy, Drawable win,
Pixmap *src, Pixmap *dst,
int src_w, int src_h, int dst_w, int dst_h)
{
GC gc;
float xscale, yscale;
int x, y;
struct timespec start, end;
double diff;
xscale = (float)src_w / dst_w;
yscale = (float)src_h / dst_h;
gc = XCreateGC(dpy, win, 0, 0);
XSetGraphicsExposures(dpy, gc, False);
timespec_get(&start, TIME_UTC);
switch (SCALING_KIND)
{
case 0:
/* slow */
for (y = 0; y < dst_h; y++)
{
int sy = (int)(y * yscale);
for (x = 0; x < dst_w; x++)
XCopyArea(dpy, *src, *dst, gc, (int)(x * xscale), sy, 1, 1, x, y);
}
break;
case 1:
/* fast */
for (x = dst_w - 1; x >= 0; x--)
XCopyArea(dpy, *src, *dst, gc, (int)(x * xscale), 0, 1, src_h, x, 0);
if (src_h <= dst_h)
{
for (y = dst_h - 1; y >= 0; y--)
XCopyArea(dpy, *dst, *dst, gc, 0, (int)(y * yscale), dst_w, 1, 0, y);
}
else
{
for (y = 0; y < dst_h; y++)
XCopyArea(dpy, *dst, *dst, gc, 0, (int)(y * yscale), dst_w, 1, 0, y);
}
break;
default:
break;
}
XFreeGC(dpy, gc);
timespec_get(&end, TIME_UTC);
diff = (end.tv_sec + (double)end.tv_nsec / 1000000000) - (start.tv_sec + (double)start.tv_nsec / 1000000000);
printf("%lf sec\n", diff);
}
/* update and draw */
static void
update(Display *dpy, Drawable win, GC gc,
Pixmap pix, Pixmap buf,
int new_w, int new_h)
{
XWindowAttributes xgwa;
int r, x, y;
int scrw, scrh;
/* get window attributes */
XGetWindowAttributes(dpy, win, &xgwa);
scrw = xgwa.width; /* window width */
scrh = xgwa.height; /* window height */
scale_pixmap(dpy, win, &pix, &buf, XPM_W, XPM_H, new_w, new_h);
/* centering */
x = scrw - ((scrw + new_w) / 2);
y = scrh - ((scrh + new_h) / 2);
/* clear window */
XClearWindow(dpy, win);
/* draw image (Pixmap) */
XSetGraphicsExposures(dpy, gc, False);
XCopyArea(dpy, buf, win, gc, 0, 0, new_w, new_h, x, y);
}
int main(void)
{
Display *dpy;
Window root;
Window win;
int screen;
int display_w, display_h;
XEvent evt;
unsigned long black, white;
XWindowAttributes xgwa;
GC gc;
Pixmap pix;
Pixmap buf;
int busy_loop;
double new_w, new_h;
double dx;
/* open display */
dpy = XOpenDisplay(NULL);
root = DefaultRootWindow(dpy);
screen = DefaultScreen(dpy);
/* get display size */
display_w = DisplayWidth(dpy, screen);
display_h = DisplayHeight(dpy, screen);
printf("Screen: %d x %d\n", display_w, display_h);
/* get color black and white */
white = WhitePixel(dpy, screen);
black = BlackPixel(dpy, screen);
/* create window */
win = XCreateSimpleWindow(dpy, root,
WIN_X, WIN_Y, display_w, display_h, BORDER,
white, black);
XSelectInput(dpy, win, KeyPressMask | ExposureMask);
XMapWindow(dpy, win);
/* wait display window */
do
{
XNextEvent(dpy, &evt);
} while (evt.type != Expose);
XMoveWindow(dpy, win, WIN_X, WIN_Y);
/* create graphics context */
gc = XCreateGC(dpy, win, 0, 0);
XSetGraphicsExposures(dpy, gc, False);
/* load image */
if (XpmCreatePixmapFromData(dpy, win, XPM_NAME, &pix, NULL, NULL))
{
fprintf(stderr, "Error not load xpm.");
return 1;
}
XSetForeground(dpy, gc, get_color(dpy, "green"));
XGetWindowAttributes(dpy, win, &xgwa);
buf = XCreatePixmap(dpy, win, display_w, display_h, xgwa.depth);
XFillRectangle(dpy, buf, gc, 0, 0, display_w, display_h);
new_w = display_w;
new_h = display_h;
dx = -6;
busy_loop = 1;
while (busy_loop)
{
/* event */
while (XPending(dpy))
{
XNextEvent(dpy, &evt);
switch (evt.type)
{
/*
case Expose:
if (evt.xexpose.count == 0)
{
}
break;
*/
case KeyPress:
busy_loop = 0;
break;
default:
break;
}
}
update(dpy, win, gc, pix, buf, new_w, new_h);
new_w += dx;
if (new_w <= 32)
{
new_w = 32;
dx *= -1;
}
if (new_w >= display_w)
{
new_w = display_w;
dx *= -1;
}
new_h = display_h * new_w / display_w;
XFlush(dpy);
usleep(16 * 1000); /* wait */
}
XFreePixmap(dpy, pix);
XFreePixmap(dpy, buf);
XFreeGC(dpy, gc);
XDestroyWindow(dpy, win);
XCloseDisplay(dpy);
return 0;
}
使用画像は以下。
_bg01.xpm
_bg02.xpm
Makefileの例。
_Makefile
コンパイルは以下。実行バイナリ 06scale3 が生成される。
gcc 06scale3.c -o 06scale3 -I /usr/include/X11 -lX11 -lXext -lm -lXpm
実行は以下。
./06scale3
◎ バグを見つけた。 :
_昨日、
書いた処理は、少しバグがあった。元画像より小さい縦サイズに縮小しようとすると、見た目がおかしなことになってしまう。
以下の処理では、(縦方向の)拡大はともかく、縮小はおかしなことになる。参照される部分を上書きコピーで破壊してしまう。
_05scale2.c
以下のように修正。拡大時と縮小時で処理を分けて、拡大時は下から上に向かってスキャン、縮小時は上から下に向かってスキャンしていけばおかしなことにはならない。
以下の処理では、(縦方向の)拡大はともかく、縮小はおかしなことになる。参照される部分を上書きコピーで破壊してしまう。
_05scale2.c
/* fast */
for (x = dst_w - 1; x >= 0; x--)
XCopyArea(dpy, *src, *dst, gc, (int)(x * xscale), 0, 1, src_h, x, 0);
for (y = dst_h - 1; y >= 0; y--)
XCopyArea(dpy, *dst, *dst, gc, 0, (int)(y * yscale), dst_w, 1, 0, y);
以下のように修正。拡大時と縮小時で処理を分けて、拡大時は下から上に向かってスキャン、縮小時は上から下に向かってスキャンしていけばおかしなことにはならない。
/* fast */
for (x = dst_w - 1; x >= 0; x--)
XCopyArea(dpy, *src, *dst, gc, (int)(x * xscale), 0, 1, src_h, x, 0);
if (src_h <= dst_h)
{
for (y = dst_h - 1; y >= 0; y--)
XCopyArea(dpy, *dst, *dst, gc, 0, (int)(y * yscale), dst_w, 1, 0, y);
}
else
{
for (y = 0; y < dst_h; y++)
XCopyArea(dpy, *dst, *dst, gc, 0, (int)(y * yscale), dst_w, 1, 0, y);
}
[ ツッコむ ]
以上です。