From 3e42bcc22cac9e93c20f3a4b71c62d1fdf3b8938 Mon Sep 17 00:00:00 2001 From: arunjose696 Date: Thu, 25 Sep 2025 18:39:30 +0200 Subject: [PATCH] Add drawImage API that takes only a destination rectangle Introduces a new method that draws the full image into a specified destination rectangle without requiring source bounds. Consumers no longer need to call image.getBounds() to determine image dimensions, unlike the existing drawImage method (Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight), which required knowing the image size in advance. --- .../swt/custom/CTabFolderRenderer.java | 7 +- .../cocoa/org/eclipse/swt/graphics/GC.java | 56 ++++++++++++ .../gtk/org/eclipse/swt/graphics/GC.java | 60 ++++++++++++- .../win32/org/eclipse/swt/graphics/GC.java | 65 +++++++++++++- .../Test_org_eclipse_swt_graphics_GC.java | 87 ++++++++++--------- 5 files changed, 228 insertions(+), 47 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java index 9edf33fbf84..4cf29174520 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java @@ -698,8 +698,7 @@ void drawBackground(GC gc, int[] shape, int x, int y, int width, int height, Col // draw the background image in shape gc.setBackground(defaultBackground); gc.fillRectangle(x, y, width, height); - Rectangle imageRect = image.getBounds(); - gc.drawImage(image, imageRect.x, imageRect.y, imageRect.width, imageRect.height, x, y, width, height); + gc.drawImage(image, x, y, width, height); } else if (colors != null) { // draw gradient if (colors.length == 1) { @@ -1646,9 +1645,7 @@ void drawUnselected(int index, GC gc, Rectangle bounds, int state) { int imageY = y + (height - imageHeight) / 2; imageY += parent.onBottom ? -1 : 1; int imageWidth = imageBounds.width * imageHeight / imageBounds.height; - gc.drawImage(image, - imageBounds.x, imageBounds.y, imageBounds.width, imageBounds.height, - imageX, imageY, imageWidth, imageHeight); + gc.drawImage(image, imageX, imageY, imageWidth, imageHeight); xDraw += imageWidth + INTERNAL_SPACING; } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java index 6120e1f3cc9..31d122d55c0 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java @@ -1189,11 +1189,67 @@ public void drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeig drawImage(image, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, false); } +/** + * Draws the full source image into a specified rectangular area in the + * receiver. The image will be stretched or shrunk as needed to exactly fit the + * destination rectangle. + * + * @param image the source image + * @param destX the x coordinate in the destination + * @param destY the y coordinate in the destination + * @param destWidth the width in points of the destination rectangle + * @param destHeight the height in points of the destination rectangle + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + * @exception SWTError + * + * @since 3.132 + */ +public void drawImage(Image image, int destX, int destY, int destWidth, int destHeight) { + if (handle == null) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (destWidth == 0 || destHeight == 0) { + return; + } + if (destWidth < 0 || destHeight < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (image == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (image.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + drawImage(image, 0, 0, 0, 0, destX, destY, destWidth, destHeight, false); +} + void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) { NSImage imageHandle = srcImage.handle; NSSize size = imageHandle.size(); int imgWidth = (int)size.width; int imgHeight = (int)size.height; + if (srcWidth == 0 && srcHeight == 0) { + srcWidth = imgWidth; + srcHeight = imgHeight; + } if (simple) { srcWidth = destWidth = imgWidth; srcHeight = destHeight = imgHeight; diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java index d57191f04c1..1bf1da0dcba 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java @@ -861,9 +861,61 @@ public void drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeig } if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - Rectangle destRect = new Rectangle(destX, destY, destWidth, destHeight); - drawImage(image, srcX, srcY, srcWidth, srcHeight, destRect.x, destRect.y, destRect.width, destRect.height, false); + drawImage(image, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, false); } + +/** + * Draws the full source image into a specified rectangular area in the + * receiver. The image will be stretched or shrunk as needed to exactly fit the + * destination rectangle. + * + * @param image the source image + * @param destX the x coordinate in the destination + * @param destY the y coordinate in the destination + * @param destWidth the width in points of the destination rectangle + * @param destHeight the height in points of the destination rectangle + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + * @exception SWTError + * + * @since 3.132 + */ +public void drawImage(Image image, int destX, int destY, int destWidth, int destHeight) { + if (handle == 0) { + SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + } + if (destWidth == 0 || destHeight == 0) { + return; + } + if (destWidth < 0 || destHeight < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (image == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (image.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + drawImage(image, 0, 0, 0, 0, destX, destY, destWidth, destHeight, false); +} + void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) { /* Refresh Image as per zoom level, if required. */ srcImage.refreshImageForZoom (); @@ -871,6 +923,10 @@ void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, ImageData srcImageData = srcImage.getImageData(); int imgWidth = srcImageData.width; int imgHeight = srcImageData.height; + if (srcWidth == 0 && srcHeight == 0) { + srcWidth = imgWidth; + srcHeight = imgHeight; + } if (simple) { srcWidth = destWidth = imgWidth; srcHeight = destHeight = imgHeight; diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java index c62445ebb1e..33b7ad7d4f4 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java @@ -1109,6 +1109,58 @@ public void drawImage (Image image, int srcX, int srcY, int srcWidth, int srcHei storeAndApplyOperationForExistingHandle(new DrawScalingImageToImageOperation(image, new Rectangle(srcX, srcY, srcWidth, srcHeight), new Rectangle(destX, destY, destWidth, destHeight))); } +/** + * Draws the full source image into a specified rectangular area in the + * receiver. The image will be stretched or shrunk as needed to exactly fit the + * destination rectangle. + * + * @param image the source image + * @param destX the x coordinate in the destination + * @param destY the y coordinate in the destination + * @param destWidth the width in points of the destination rectangle + * @param destHeight the height in points of the destination rectangle + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + * @exception SWTError + * + * @since 3.132 + */ +public void drawImage(Image image, int destX, int destY, int destWidth, int destHeight) { + checkNonDisposed(); + if (destWidth == 0 || destHeight == 0) { + return; + } + if (destWidth < 0 || destHeight < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (image == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (image.isDisposed()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + + storeAndApplyOperationForExistingHandle(new DrawScalingImageToImageOperation(image, new Rectangle(0, 0, 0, 0), + new Rectangle(destX, destY, destWidth, destHeight))); +} + void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) { storeAndApplyOperationForExistingHandle(new DrawImageToImageOperation(srcImage, new Rectangle(srcX, srcY, srcWidth, srcHeight), new Rectangle(destX, destY, destWidth, destHeight), simple)); } @@ -1213,7 +1265,10 @@ private void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int src long img = gdipImage[0]; int imgWidth = Gdip.Image_GetWidth(img); int imgHeight = Gdip.Image_GetHeight(img); - + if (srcWidth == 0 && srcHeight == 0) { + srcWidth = imgWidth; + srcHeight = imgHeight; + } if (simple) { srcWidth = destWidth = imgWidth; srcHeight = destHeight = imgHeight; @@ -1315,6 +1370,10 @@ private void drawIcon(long imageHandle, int srcX, int srcY, int srcWidth, int sr OS.GetObject(hBitmap, BITMAP.sizeof, bm); int iconWidth = bm.bmWidth, iconHeight = bm.bmHeight; if (hBitmap == srcIconInfo.hbmMask) iconHeight /= 2; + if (srcWidth == 0 && srcHeight == 0) { + srcWidth = iconWidth; + srcHeight = iconHeight; + } if (simple) { srcWidth = destWidth = iconWidth; @@ -1410,6 +1469,10 @@ private void drawBitmap(Image srcImage, long imageHandle, int srcX, int srcY, in OS.GetObject(imageHandle, BITMAP.sizeof, bm); int imgWidth = bm.bmWidth; int imgHeight = bm.bmHeight; + if (srcWidth == 0 && srcHeight == 0) { + srcWidth = imgWidth; + srcHeight = imgHeight; + } if (simple) { srcWidth = destWidth = imgWidth; srcHeight = destHeight = imgHeight; diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java index 7b0233fad94..1bcb0c9ada2 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java @@ -308,12 +308,28 @@ public void test_drawFocusIIII() { gc.drawFocus(1, 1, 50, 25); } -@Test -public void test_drawImageLorg_eclipse_swt_graphics_ImageII() { +private static class TestImages { + final Image normal; + final Image transparent; + final Image alpha; + + TestImages(Image normal, Image transparent, Image alpha) { + this.normal = normal; + this.transparent = transparent; + this.alpha = alpha; + } + + void dispose() { + normal.dispose(); + transparent.dispose(); + alpha.dispose(); + } +} + +private TestImages createTestImages(Display display) { Color c1 = new Color(255, 0, 0); Color c2 = new Color(0, 0, 0); Color c3 = new Color(255, 255, 0); - PaletteData paletteData = new PaletteData(c1.getRGB(), c2.getRGB(), c3.getRGB()); ImageData data = new ImageData(30,30, 8, paletteData); for (int y = 0; y < data.height; y++) { @@ -334,50 +350,43 @@ public void test_drawImageLorg_eclipse_swt_graphics_ImageII() { } } Image imageAlpha = new Image(display, data); + c1.dispose(); + c2.dispose(); + c3.dispose(); + return new TestImages(image, imageTransparent, imageAlpha); +} - gc.drawImage(image, 100, 100); - gc.drawImage(imageTransparent, 130, 100); - gc.drawImage(imageAlpha, 160, 100); + +@Test +public void test_drawImageLorg_eclipse_swt_graphics_ImageII() { + TestImages images = createTestImages(display); + + gc.drawImage(images.normal, 100, 100); + gc.drawImage(images.transparent, 130, 100); + gc.drawImage(images.alpha, 160, 100); assertThrows(IllegalArgumentException.class, () -> gc.drawImage(null, 100, 100)); - image.dispose(); - imageTransparent.dispose(); - imageAlpha.dispose(); + images.dispose(); } @Test public void test_drawImageLorg_eclipse_swt_graphics_ImageIIIIIIII() { - Color c1 = new Color(255, 0, 0); - Color c2 = new Color(0, 0, 0); - Color c3 = new Color(255, 255, 0); + TestImages images = createTestImages(display); + gc.drawImage(images.normal, 10, 5, 20, 15, 100, 120, 50, 60); + gc.drawImage(images.transparent, 10, 5, 20, 15, 100, 120, 10, 10); + gc.drawImage(images.alpha, 10, 5, 20, 15, 100, 120, 20, 15); + assertThrows(IllegalArgumentException.class, () -> gc.drawImage(null, 10, 5, 20, 15, 100, 120, 50, 60)); + images.dispose(); +} - PaletteData paletteData = new PaletteData(c1.getRGB(), c2.getRGB(), c3.getRGB()); - ImageData data = new ImageData(30,30, 8, paletteData); - for (int y = 0; y < data.height; y++) { - for (int x = 0; x < data.width; x++) { - if (x > y) data.setPixel(x, y, paletteData.getPixel(c1.getRGB())); - else if (x < y) data.setPixel(x, y, paletteData.getPixel(c2.getRGB())); - else data.setPixel(x, y, paletteData.getPixel(c3.getRGB())); - } - } - Image image = new Image(display, data); - data = image.getImageData(); - data.transparentPixel = paletteData.getPixel(c1.getRGB()); - Image imageTransparent = new Image(display, data); - data.transparentPixel = -1; - for (int y = 0; y < data.height; y++) { - for (int x = 0; x < data.width; x++) { - data.setAlpha(x, y, 127); - } - } - Image imageAlpha = new Image(display, data); - gc.drawImage(image, 10, 5, 20, 15, 100, 120, 50, 60); - gc.drawImage(imageTransparent, 10, 5, 20, 15, 100, 120, 10, 10); - gc.drawImage(imageAlpha, 10, 5, 20, 15, 100, 120, 20, 15); - assertThrows(IllegalArgumentException.class, () -> gc.drawImage(null, 10, 5, 20, 15, 100, 120, 50, 60)); - image.dispose(); - imageAlpha.dispose(); - imageTransparent.dispose(); +@Test +public void test_drawImageLorg_eclipse_swt_graphics_ImageIIII() { + TestImages images = createTestImages(display); + gc.drawImage(images.normal, 100, 120, 50, 60); + gc.drawImage(images.transparent, 100, 120, 10, 10); + gc.drawImage(images.alpha, 100, 120, 20, 15); + assertThrows(IllegalArgumentException.class, () -> gc.drawImage(null, 100, 120, 50, 60)); + images.dispose(); } @Test