From c7fd5b3dd9bbe25436c95e5a223ee8fe42ca6898 Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Thu, 3 Dec 2009 15:29:38 +0100 Subject: [PATCH] Fixed a bug related to transcoding images with indexed color (ie. GIF) to JPEG. Thanks to Rune Bremnes for pointing it out and providing a patch and sample image! --- .../image/ImageServletResponseImpl.java | 20 +- .../ImageServletResponseImplTestCase.java | 177 ++++++++++++------ .../com/twelvemonkeys/servlet/image/tux.gif | Bin 0 -> 5822 bytes 3 files changed, 125 insertions(+), 72 deletions(-) create mode 100644 twelvemonkeys-servlet/src/test/resources/com/twelvemonkeys/servlet/image/tux.gif diff --git a/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java b/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java index dc24d041..3a023428 100755 --- a/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java +++ b/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java @@ -131,9 +131,9 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima * @param pMimeType the content (MIME) type */ public void setContentType(final String pMimeType) { - // Throw exception is allready set + // Throw exception is already set if (mOriginalContentType != null) { - throw new IllegalStateException("ContentType allready set."); + throw new IllegalStateException("ContentType already set."); } mOriginalContentType = pMimeType; @@ -187,17 +187,13 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima getImage(); } - // This is stupid, but don't know how to work around... - // TODO: Test what types of images that work with JPEG, consider reporting it as a bug + // For known formats that don't support transparency, convert to opaque if (("image/jpeg".equals(outputType) || "image/jpg".equals(outputType) || "image/bmp".equals(outputType) || "image/x-bmp".equals(outputType)) && - mImage instanceof BufferedImage && ((BufferedImage) mImage).getType() == BufferedImage.TYPE_INT_ARGB) { + mImage.getColorModel().getTransparency() != Transparency.OPAQUE) { mImage = ImageUtil.toBuffered(mImage, BufferedImage.TYPE_INT_RGB); } - //System.out.println("Writing image, content-type: " + getContentType(outputType)); - //System.out.println("Writing image, outputType: " + outputType); - //System.out.println("Writing image: " + mImage); if (mImage != null) { Iterator writers = ImageIO.getImageWritersByMIMEType(outputType); if (writers.hasNext()) { @@ -218,10 +214,6 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima ImageOutputStream stream = ImageIO.createImageOutputStream(out); - //System.out.println("-ISR- Image: " + mImage); - //System.out.println("-ISR- ImageWriter: " + writer); - //System.out.println("-ISR- ImageOutputStream: " + stream); - writer.setOutput(stream); try { writer.write(null, new IIOImage(mImage, null, null), param); @@ -233,12 +225,10 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima finally { writer.dispose(); out.flush(); -// out.close(); } } else { mContext.log("ERROR: No writer for content-type: " + outputType); -// sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to encode image: No writer for content-type " + outputType); throw new IIOException("Unable to transcode image: No suitable image writer found (content-type: " + outputType + ")."); } } @@ -365,8 +355,6 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima // Fill bgcolor behind image, if transparent extractAndSetBackgroundColor(image); - //System.out.println("-ISR- Image: " + image); - // Set image mImage = image; } diff --git a/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTestCase.java b/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTestCase.java index fe4fc100..231ec787 100755 --- a/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTestCase.java +++ b/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTestCase.java @@ -26,13 +26,17 @@ import java.util.Arrays; public class ImageServletResponseImplTestCase extends MockObjectTestCase { private static final String CONTENT_TYPE_BMP = "image/bmp"; private static final String CONTENT_TYPE_FOO = "foo/bar"; + private static final String CONTENT_TYPE_GIF = "image/gif"; private static final String CONTENT_TYPE_JPEG = "image/jpeg"; private static final String CONTENT_TYPE_PNG = "image/png"; private static final String CONTENT_TYPE_TEXT = "text/plain"; - private static final String IMAGE_NAME = "12monkeys-splash.png"; + private static final String IMAGE_NAME_PNG = "12monkeys-splash.png"; + private static final String IMAGE_NAME_GIF = "tux.gif"; + + private static final Dimension IMAGE_DIMENSION_PNG = new Dimension(300, 410); + private static final Dimension IMAGE_DIMENSION_GIF = new Dimension(250, 250); - private static final Dimension IMAGE_DIMENSION = new Dimension(300, 410); private HttpServletRequest mRequest; private ServletContext mContext; @@ -43,15 +47,17 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { Mock mockRequest = mock(HttpServletRequest.class); mockRequest.stubs().method("getAttribute").will(returnValue(null)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); mRequest = (HttpServletRequest) mockRequest.proxy(); Mock mockContext = mock(ServletContext.class); - mockContext.stubs().method("getResource").with(eq("/" + IMAGE_NAME)).will(returnValue(getClass().getResource(IMAGE_NAME))); - mockContext.stubs().method("log").withAnyArguments(); // Just supress the logging + mockContext.stubs().method("getResource").with(eq("/" + IMAGE_NAME_PNG)).will(returnValue(getClass().getResource(IMAGE_NAME_PNG))); + mockContext.stubs().method("getResource").with(eq("/" + IMAGE_NAME_GIF)).will(returnValue(getClass().getResource(IMAGE_NAME_GIF))); + mockContext.stubs().method("log").withAnyArguments(); // Just suppress the logging mockContext.stubs().method("getMimeType").with(eq("file.bmp")).will(returnValue(CONTENT_TYPE_BMP)); mockContext.stubs().method("getMimeType").with(eq("file.foo")).will(returnValue(CONTENT_TYPE_FOO)); + mockContext.stubs().method("getMimeType").with(eq("file.gif")).will(returnValue(CONTENT_TYPE_GIF)); mockContext.stubs().method("getMimeType").with(eq("file.jpeg")).will(returnValue(CONTENT_TYPE_JPEG)); mockContext.stubs().method("getMimeType").with(eq("file.png")).will(returnValue(CONTENT_TYPE_PNG)); mockContext.stubs().method("getMimeType").with(eq("file.txt")).will(returnValue(CONTENT_TYPE_TEXT)); @@ -98,11 +104,11 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(mRequest, response, mContext); fakeResponse(mRequest, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); - assertEquals(IMAGE_DIMENSION.width, image.getWidth()); - assertEquals(IMAGE_DIMENSION.height, image.getHeight()); + assertEquals(IMAGE_DIMENSION_PNG.width, image.getWidth()); + assertEquals(IMAGE_DIMENSION_PNG.height, image.getHeight()); // Flush image to wrapped response imageResponse.flush(); @@ -136,7 +142,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { assertTrue("Content has no data", out.size() > 0); // Test that image data is untouched - assertTrue("Data differs", Arrays.equals(FileUtil.read(getClass().getResourceAsStream(IMAGE_NAME)), out.toByteArray())); + assertTrue("Data differs", Arrays.equals(FileUtil.read(getClass().getResourceAsStream(IMAGE_NAME_PNG)), out.toByteArray())); } // Transcode original PNG to JPEG with no other changes @@ -161,8 +167,67 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { // Test that image data is still readable BufferedImage outImage = ImageIO.read(new ByteArrayInputStream(out.toByteArray())); assertNotNull(outImage); - assertEquals(IMAGE_DIMENSION.width, outImage.getWidth()); - assertEquals(IMAGE_DIMENSION.height, outImage.getHeight()); + assertEquals(IMAGE_DIMENSION_PNG.width, outImage.getWidth()); + assertEquals(IMAGE_DIMENSION_PNG.height, outImage.getHeight()); + assertSimilarImage(ImageIO.read(mContext.getResource("/" + IMAGE_NAME_PNG)), outImage, 96f); + } + + @Test + public void testTranscodeResponseIndexedCM() throws IOException { + // Custom setup + Mock mockRequest = mock(HttpServletRequest.class); + mockRequest.stubs().method("getAttribute").will(returnValue(null)); + mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_GIF)); + mockRequest.stubs().method("getParameter").will(returnValue(null)); + HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); + + Mock mockResponse = mock(HttpServletResponse.class); + mockResponse.expects(once()).method("setContentType").with(eq(CONTENT_TYPE_JPEG)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + mockResponse.expects(once()).method("getOutputStream").will(returnValue(new OutputStreamAdapter(out))); + HttpServletResponse response = (HttpServletResponse) mockResponse.proxy(); + + ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); + fakeResponse(request, imageResponse); + + // Force transcode to JPEG + imageResponse.setOutputContentType("image/jpeg"); + + // Flush image to wrapped response + imageResponse.flush(); + + assertTrue("Content has no data", out.size() > 0); + + // Test that image data is still readable + BufferedImage outImage = ImageIO.read(new ByteArrayInputStream(out.toByteArray())); + assertNotNull(outImage); + assertEquals(IMAGE_DIMENSION_GIF.width, outImage.getWidth()); + assertEquals(IMAGE_DIMENSION_GIF.height, outImage.getHeight()); + assertSimilarImage(ImageIO.read(mContext.getResource("/" + IMAGE_NAME_GIF)), outImage, 96f); + } + + /** + * Makes sure images are the same, taking JPEG artifacts into account. + * + * @param pExpected the expected image + * @param pActual the actual image + * @param pArtifactThreshold the maximum allowed difference between the expected and actual pixel value + */ + private void assertSimilarImage(final BufferedImage pExpected, final BufferedImage pActual, final float pArtifactThreshold) { + for (int y = 0; y < pExpected.getHeight(); y++) { + for (int x = 0; x < pExpected.getWidth(); x++) { + int original = pExpected.getRGB(x, y); + int actual = pActual.getRGB(x, y); + + // Multiply in the alpha component + float alpha = ((original >> 24) & 0xff) / 255f; + + assertEquals(alpha * ((original >> 16) & 0xff), (actual >> 16) & 0xff, pArtifactThreshold); + assertEquals(alpha * ((original >> 8) & 0xff), (actual >> 8) & 0xff, pArtifactThreshold); + assertEquals(alpha * ((original) & 0xff), actual & 0xff, pArtifactThreshold); + } + } } public void testReplaceResponse() throws IOException { @@ -175,7 +240,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(mRequest, response, mContext); fakeResponse(mRequest, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); @@ -298,7 +363,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { mockRequest.stubs().method("getAttribute").withAnyArguments().will(returnValue(null)); mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_AOI)).will(returnValue(sourceRegion)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); @@ -311,7 +376,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); fakeResponse(request, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); assertEquals(sourceRegion.width, image.getWidth()); @@ -337,7 +402,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { mockRequest.stubs().method("getAttribute").withAnyArguments().will(returnValue(null)); mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_AOI)).will(returnValue(sourceRegion)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); @@ -350,7 +415,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); fakeResponse(request, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); assertEquals(sourceRegion.width, image.getWidth()); @@ -379,7 +444,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_AOI_UNIFORM)).will(returnValue(true)); mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_AOI)).will(returnValue(sourceRegion)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); @@ -392,24 +457,24 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); fakeResponse(request, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); assertEquals(sourceRegion.width, image.getWidth()); assertEquals(sourceRegion.height, image.getHeight()); - BufferedImage original = ImageIO.read(getClass().getResource(IMAGE_NAME)); + BufferedImage original = ImageIO.read(getClass().getResource(IMAGE_NAME_PNG)); // Sanity check assertNotNull(original); - assertEquals(IMAGE_DIMENSION.width, original.getWidth()); - assertEquals(IMAGE_DIMENSION.height, original.getHeight()); + assertEquals(IMAGE_DIMENSION_PNG.width, original.getWidth()); + assertEquals(IMAGE_DIMENSION_PNG.height, original.getHeight()); // Center sourceRegion.setLocation( - (int) Math.round((IMAGE_DIMENSION.width - sourceRegion.getWidth()) / 2.0), - (int) Math.round((IMAGE_DIMENSION.height - sourceRegion.getHeight()) / 2.0) + (int) Math.round((IMAGE_DIMENSION_PNG.width - sourceRegion.getWidth()) / 2.0), + (int) Math.round((IMAGE_DIMENSION_PNG.height - sourceRegion.getHeight()) / 2.0) ); // Test that we have exactly the pixels we should @@ -442,7 +507,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_AOI_UNIFORM)).will(returnValue(true)); mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_AOI)).will(returnValue(sourceRegion)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); @@ -455,49 +520,49 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); fakeResponse(request, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); // Flush image to wrapped response - imageResponse.flush(); + imageResponse.flush(); - assertTrue("Image wider than bounding box", IMAGE_DIMENSION.width >= image.getWidth()); - assertTrue("Image taller than bounding box", IMAGE_DIMENSION.height >= image.getHeight()); - assertTrue("Image not maximized to bounding box", IMAGE_DIMENSION.width == image.getWidth() || IMAGE_DIMENSION.height == image.getHeight()); + assertTrue("Image wider than bounding box", IMAGE_DIMENSION_PNG.width >= image.getWidth()); + assertTrue("Image taller than bounding box", IMAGE_DIMENSION_PNG.height >= image.getHeight()); + assertTrue("Image not maximized to bounding box", IMAGE_DIMENSION_PNG.width == image.getWidth() || IMAGE_DIMENSION_PNG.height == image.getHeight()); // Above tests that one of the sides equal, we now need to test that the other follows aspect double destAspect = sourceRegion.getWidth() / sourceRegion.getHeight(); - double srcAspect = IMAGE_DIMENSION.getWidth() / IMAGE_DIMENSION.getHeight(); + double srcAspect = IMAGE_DIMENSION_PNG.getWidth() / IMAGE_DIMENSION_PNG.getHeight(); if (srcAspect >= destAspect) { // Dst is narrower than src - assertEquals(IMAGE_DIMENSION.height, image.getHeight()); + assertEquals(IMAGE_DIMENSION_PNG.height, image.getHeight()); assertEquals( "Image width does not follow aspect", - Math.round(IMAGE_DIMENSION.getHeight() * destAspect), image.getWidth() + Math.round(IMAGE_DIMENSION_PNG.getHeight() * destAspect), image.getWidth() ); } else { // Dst is wider than src - assertEquals(IMAGE_DIMENSION.width, image.getWidth()); + assertEquals(IMAGE_DIMENSION_PNG.width, image.getWidth()); assertEquals( "Image height does not follow aspect", - Math.round(IMAGE_DIMENSION.getWidth() / destAspect), image.getHeight() + Math.round(IMAGE_DIMENSION_PNG.getWidth() / destAspect), image.getHeight() ); } - BufferedImage original = ImageIO.read(getClass().getResource(IMAGE_NAME)); + BufferedImage original = ImageIO.read(getClass().getResource(IMAGE_NAME_PNG)); // Sanity check assertNotNull(original); - assertEquals(IMAGE_DIMENSION.width, original.getWidth()); - assertEquals(IMAGE_DIMENSION.height, original.getHeight()); + assertEquals(IMAGE_DIMENSION_PNG.width, original.getWidth()); + assertEquals(IMAGE_DIMENSION_PNG.height, original.getHeight()); // Center sourceRegion.setLocation( - (int) Math.round((IMAGE_DIMENSION.width - image.getWidth()) / 2.0), - (int) Math.round((IMAGE_DIMENSION.height - image.getHeight()) / 2.0) + (int) Math.round((IMAGE_DIMENSION_PNG.width - image.getWidth()) / 2.0), + (int) Math.round((IMAGE_DIMENSION_PNG.height - image.getHeight()) / 2.0) ); sourceRegion.setSize(image.getWidth(), image.getHeight()); @@ -526,7 +591,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { mockRequest.stubs().method("getAttribute").withAnyArguments().will(returnValue(null)); mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_SIZE)).will(returnValue(size)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); @@ -539,7 +604,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); fakeResponse(request, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); @@ -549,10 +614,10 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { // Above tests that one of the sides equal, we now need to test that the other follows aspect if (size.width == image.getWidth()) { - assertEquals(Math.round(size.getWidth() * IMAGE_DIMENSION.getWidth() / IMAGE_DIMENSION.getHeight()), image.getHeight()); + assertEquals(Math.round(size.getWidth() * IMAGE_DIMENSION_PNG.getWidth() / IMAGE_DIMENSION_PNG.getHeight()), image.getHeight()); } else { - assertEquals(Math.round(size.getHeight() * IMAGE_DIMENSION.getWidth() / IMAGE_DIMENSION.getHeight()), image.getWidth()); + assertEquals(Math.round(size.getHeight() * IMAGE_DIMENSION_PNG.getWidth() / IMAGE_DIMENSION_PNG.getHeight()), image.getWidth()); } // Flush image to wrapped response @@ -576,7 +641,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_SIZE)).will(returnValue(size)); mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_SIZE_UNIFORM)).will(returnValue(false)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); @@ -589,7 +654,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); fakeResponse(request, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); assertEquals(size.width, image.getWidth()); @@ -618,7 +683,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_AOI)).will(returnValue(sourceRegion)); mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_SIZE)).will(returnValue(size)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); @@ -631,7 +696,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); fakeResponse(request, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); @@ -658,7 +723,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { assertEquals(image.getWidth(), outImage.getWidth()); assertEquals(image.getHeight(), outImage.getHeight()); } - + @Test public void testReadWithSourceRegionAndNonUniformResize() throws IOException { Rectangle sourceRegion = new Rectangle(100, 100, 200, 200); @@ -670,7 +735,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_SIZE)).will(returnValue(size)); mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_SIZE_UNIFORM)).will(returnValue(false)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); @@ -683,7 +748,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); fakeResponse(request, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); assertEquals(size.width, image.getWidth()); @@ -713,7 +778,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_AOI)).will(returnValue(sourceRegion)); mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_SIZE)).will(returnValue(size)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); @@ -726,7 +791,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); fakeResponse(request, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); @@ -774,7 +839,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_AOI)).will(returnValue(sourceRegion)); mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_SIZE)).will(returnValue(size)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); @@ -787,7 +852,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); fakeResponse(request, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); @@ -839,7 +904,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_AOI)).will(returnValue(sourceRegion)); mockRequest.stubs().method("getAttribute").with(eq(ImageServletResponse.ATTRIB_SIZE)).will(returnValue(size)); mockRequest.stubs().method("getContextPath").will(returnValue("/ape")); - mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME)); + mockRequest.stubs().method("getRequestURI").will(returnValue("/ape/" + IMAGE_NAME_PNG)); mockRequest.stubs().method("getParameter").will(returnValue(null)); HttpServletRequest request = (HttpServletRequest) mockRequest.proxy(); @@ -852,7 +917,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, mContext); fakeResponse(request, imageResponse); - // Make sure image is correctly loaedd + // Make sure image is correctly loaded BufferedImage image = imageResponse.getImage(); assertNotNull(image); diff --git a/twelvemonkeys-servlet/src/test/resources/com/twelvemonkeys/servlet/image/tux.gif b/twelvemonkeys-servlet/src/test/resources/com/twelvemonkeys/servlet/image/tux.gif new file mode 100644 index 0000000000000000000000000000000000000000..378cd229495ce7ce91396946fff568b990465ecd GIT binary patch literal 5822 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 BF%AF# literal 0 HcmV?d00001