|
13 | 13 | */ |
14 | 14 | package org.geowebcache.service.wms; |
15 | 15 |
|
| 16 | +import static org.junit.Assert.assertArrayEquals; |
16 | 17 | import static org.junit.Assert.assertEquals; |
17 | 18 | import static org.junit.Assert.assertNotNull; |
18 | 19 | import static org.junit.Assert.assertNull; |
|
23 | 24 | import static org.mockito.Mockito.mock; |
24 | 25 | import static org.mockito.Mockito.times; |
25 | 26 |
|
| 27 | +import java.awt.Color; |
| 28 | +import java.awt.Graphics; |
| 29 | +import java.awt.Transparency; |
26 | 30 | import java.awt.image.BufferedImage; |
| 31 | +import java.awt.image.WritableRaster; |
27 | 32 | import java.io.ByteArrayInputStream; |
| 33 | +import java.io.ByteArrayOutputStream; |
28 | 34 | import java.io.File; |
29 | 35 | import java.util.Arrays; |
30 | 36 | import java.util.Collections; |
|
44 | 50 | import org.geowebcache.grid.GridSetBroker; |
45 | 51 | import org.geowebcache.grid.GridSubset; |
46 | 52 | import org.geowebcache.grid.GridSubsetFactory; |
| 53 | +import org.geowebcache.io.ByteArrayResource; |
47 | 54 | import org.geowebcache.io.FileResource; |
48 | 55 | import org.geowebcache.layer.TileLayer; |
49 | 56 | import org.geowebcache.layer.TileLayerDispatcher; |
@@ -389,4 +396,90 @@ private WMSLayer createWMSLayer() { |
389 | 396 |
|
390 | 397 | return layer; |
391 | 398 | } |
| 399 | + |
| 400 | + /** Tests writing a fused opaque image from transparent tiles */ |
| 401 | + @Test |
| 402 | + public void testOpaqueFromTransparent() throws Exception { |
| 403 | + // prepare a transparent image with a red half |
| 404 | + BufferedImage transparentImage = new BufferedImage(256, 256, BufferedImage.TYPE_4BYTE_ABGR); |
| 405 | + Graphics graphics = transparentImage.getGraphics(); |
| 406 | + graphics.setColor(Color.RED); |
| 407 | + graphics.fillRect(0, 0, 127, 256); |
| 408 | + graphics.dispose(); |
| 409 | + ByteArrayOutputStream imageStream = new ByteArrayOutputStream(); |
| 410 | + ImageIO.write(transparentImage, "png", imageStream); |
| 411 | + byte[] imageData = imageStream.toByteArray(); |
| 412 | + |
| 413 | + // request larger than -30.0,15.0,45.0,30 |
| 414 | + BoundingBox bounds = new BoundingBox(-36.0, 14.0, -26, 24); |
| 415 | + |
| 416 | + // One in between |
| 417 | + int width = (int) bounds.getWidth() * 25; |
| 418 | + int height = (int) bounds.getHeight() * 25; |
| 419 | + final TileLayer layer = createWMSLayer(); |
| 420 | + layer.getGridSubset(layer.getGridSubsets().iterator().next()); |
| 421 | + TileLayerDispatcher dispatcher = new TileLayerDispatcher(gridSetBroker, null) { |
| 422 | + |
| 423 | + @Override |
| 424 | + public TileLayer getTileLayer(String layerName) throws GeoWebCacheException { |
| 425 | + return layer; |
| 426 | + } |
| 427 | + }; |
| 428 | + |
| 429 | + MockHttpServletRequest request = new MockHttpServletRequest(); |
| 430 | + request.addParameter("layers", new String[] {"test:layer"}); |
| 431 | + request.addParameter("srs", new String[] {"EPSG:4326"}); |
| 432 | + request.addParameter("format", new String[] {"image/jpeg"}); |
| 433 | + request.addParameter("width", width + ""); |
| 434 | + request.addParameter("height", height + ""); |
| 435 | + request.addParameter("bbox", bounds.toString()); |
| 436 | + |
| 437 | + File temp = File.createTempFile("gwc", "wms"); |
| 438 | + temp.delete(); |
| 439 | + temp.mkdirs(); |
| 440 | + StorageBroker broker = new DefaultStorageBroker( |
| 441 | + new FileBlobStore(temp.getAbsolutePath()) { |
| 442 | + |
| 443 | + @Override |
| 444 | + public boolean get(TileObject stObj) throws StorageException { |
| 445 | + stObj.setBlob(new ByteArrayResource(imageData)); |
| 446 | + stObj.setCreated((new Date()).getTime()); |
| 447 | + stObj.setBlobSize(imageData.length); |
| 448 | + return true; |
| 449 | + } |
| 450 | + }, |
| 451 | + new TransientCache(100, 1024, 2000)); |
| 452 | + |
| 453 | + WMSTileFuser tileFuser = new WMSTileFuser(dispatcher, broker, request); |
| 454 | + tileFuser.setSecurityDispatcher(secDisp); |
| 455 | + |
| 456 | + // Selection of the ApplicationContext associated |
| 457 | + try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appContextTest.xml")) { |
| 458 | + tileFuser.setApplicationContext(context); |
| 459 | + MockHttpServletResponse response = new MockHttpServletResponse(); |
| 460 | + |
| 461 | + tileFuser.writeResponse(response, new RuntimeStats(1, Arrays.asList(1), Arrays.asList("desc"))); |
| 462 | + |
| 463 | + // check the result is a valid JPEG |
| 464 | + assertEquals("image/jpeg", response.getContentType()); |
| 465 | + BufferedImage image = ImageIO.read(new ByteArrayInputStream(response.getContentAsByteArray())); |
| 466 | + // and it's the expected size |
| 467 | + assertEquals(width, image.getWidth()); |
| 468 | + assertEquals(height, image.getHeight()); |
| 469 | + |
| 470 | + // check that the image is opaque |
| 471 | + assertEquals(Transparency.OPAQUE, image.getColorModel().getTransparency()); |
| 472 | + assertEquals(3, image.getColorModel().getNumColorComponents()); |
| 473 | + assertEquals(3, image.getSampleModel().getNumBands()); |
| 474 | + |
| 475 | + // the output image has two red stripes, the transparent pixels became white |
| 476 | + // in particular, it's white, red, white, red |
| 477 | + // red is not 255 because of JPEG compression |
| 478 | + WritableRaster raster = image.getRaster(); |
| 479 | + assertArrayEquals(new int[] {255, 255, 255}, raster.getPixel(30, 125, new int[3])); |
| 480 | + assertArrayEquals(new int[] {254, 0, 0}, raster.getPixel(90, 125, new int[3])); |
| 481 | + assertArrayEquals(new int[] {255, 255, 255}, raster.getPixel(150, 125, new int[3])); |
| 482 | + assertArrayEquals(new int[] {254, 0, 0}, raster.getPixel(210, 125, new int[3])); |
| 483 | + } |
| 484 | + } |
392 | 485 | } |
0 commit comments