Skip to content

Commit ec93b0b

Browse files
authored
Fix GH-23459: Improve imagegrabscreen() performance on Windows (#23485)
A roughly 814x optimization in total for the two function.
1 parent 25466f7 commit ec93b0b

2 files changed

Lines changed: 51 additions & 22 deletions

File tree

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,10 @@ PHP 8.6 UPGRADE NOTES
939939
- DOM:
940940
. Made splitText() faster and consume less memory.
941941

942+
- GD:
943+
. Improved performance of imagegrabscreen() and imagegrabwindow() on
944+
Windows.
945+
942946
- JSON:
943947
. Improve performance of encoding arrays and objects.
944948
. Improved performance of indentation generation in json_encode()

ext/gd/gd.c

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,51 @@ PHP_FUNCTION(imagecopyresampled)
10971097
/* }}} */
10981098

10991099
#ifdef PHP_WIN32
1100+
/* The bitmap must not be selected into a device context. */
1101+
static gdImagePtr php_gd_image_from_bitmap(HDC hdc, HBITMAP bitmap, int width, int height)
1102+
{
1103+
BITMAPINFO bitmap_info = {0};
1104+
RGBQUAD *pixels;
1105+
gdImagePtr im;
1106+
size_t num_pixels;
1107+
bool overflow;
1108+
int x, y;
1109+
1110+
bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1111+
bitmap_info.bmiHeader.biWidth = width;
1112+
/* Request a top-down DIB so its row order matches GD's. */
1113+
bitmap_info.bmiHeader.biHeight = -height;
1114+
bitmap_info.bmiHeader.biPlanes = 1;
1115+
bitmap_info.bmiHeader.biBitCount = 32;
1116+
bitmap_info.bmiHeader.biCompression = BI_RGB;
1117+
1118+
num_pixels = zend_safe_address((size_t) width, (size_t) height, 0, &overflow);
1119+
if (overflow) {
1120+
return NULL;
1121+
}
1122+
1123+
pixels = safe_emalloc(num_pixels, sizeof(*pixels), 0);
1124+
if (GetDIBits(hdc, bitmap, 0, (UINT) height, pixels, &bitmap_info, DIB_RGB_COLORS) != height) {
1125+
efree(pixels);
1126+
return NULL;
1127+
}
1128+
1129+
im = gdImageCreateTrueColor(width, height);
1130+
if (im) {
1131+
for (y = 0; y < height; y++) {
1132+
const RGBQUAD *src = pixels + (size_t) y * width;
1133+
int *dst = im->tpixels[y];
1134+
1135+
for (x = 0; x < width; x++) {
1136+
dst[x] = gdTrueColor(src[x].rgbRed, src[x].rgbGreen, src[x].rgbBlue);
1137+
}
1138+
}
1139+
}
1140+
1141+
efree(pixels);
1142+
return im;
1143+
}
1144+
11001145
/* {{{ Grab a window or its client area using a windows handle (HWND property in COM instance) */
11011146
PHP_FUNCTION(imagegrabwindow)
11021147
{
@@ -1144,18 +1189,8 @@ PHP_FUNCTION(imagegrabwindow)
11441189

11451190
PrintWindow(window, memDC, (UINT) client_area);
11461191

1147-
im = gdImageCreateTrueColor(Width, Height);
1148-
if (im) {
1149-
int x,y;
1150-
for (y=0; y <= Height; y++) {
1151-
for (x=0; x <= Width; x++) {
1152-
int c = GetPixel(memDC, x,y);
1153-
gdImageSetPixel(im, x, y, gdTrueColor(GetRValue(c), GetGValue(c), GetBValue(c)));
1154-
}
1155-
}
1156-
}
1157-
11581192
SelectObject(memDC,hOld);
1193+
im = php_gd_image_from_bitmap(hdc, memBM, Width, Height);
11591194
DeleteObject(memBM);
11601195
DeleteDC(memDC);
11611196
ReleaseDC( 0, hdc );
@@ -1198,18 +1233,8 @@ PHP_FUNCTION(imagegrabscreen)
11981233
hOld = (HBITMAP) SelectObject (memDC, memBM);
11991234
BitBlt( memDC, 0, 0, Width, Height , hdc, rc.left, rc.top , SRCCOPY );
12001235

1201-
im = gdImageCreateTrueColor(Width, Height);
1202-
if (im) {
1203-
int x,y;
1204-
for (y=0; y <= Height; y++) {
1205-
for (x=0; x <= Width; x++) {
1206-
int c = GetPixel(memDC, x,y);
1207-
gdImageSetPixel(im, x, y, gdTrueColor(GetRValue(c), GetGValue(c), GetBValue(c)));
1208-
}
1209-
}
1210-
}
1211-
12121236
SelectObject(memDC,hOld);
1237+
im = php_gd_image_from_bitmap(hdc, memBM, Width, Height);
12131238
DeleteObject(memBM);
12141239
DeleteDC(memDC);
12151240
ReleaseDC( 0, hdc );

0 commit comments

Comments
 (0)