View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.html;
16  
17  import java.io.File;
18  import java.io.InputStream;
19  import java.net.URL;
20  import java.util.Collections;
21  
22  import org.apache.commons.io.FileUtils;
23  import org.apache.commons.io.IOUtils;
24  import org.htmlunit.Page;
25  import org.htmlunit.SimpleWebTestCase;
26  import org.htmlunit.junit.annotation.Alerts;
27  import org.htmlunit.util.MimeType;
28  import org.junit.jupiter.api.Test;
29  
30  /**
31   * Tests for {@link HtmlImage}.
32   *
33   * @author Marc Guillemot
34   * @author Ahmed Ashour
35   * @author Ronald Brill
36   */
37  public class HtmlImageTest extends SimpleWebTestCase {
38  
39      /**
40       * @throws Exception if the test fails
41       */
42      @Test
43      public void isMapClick() throws Exception {
44          isMapClick("img1", Boolean.FALSE, "?0,0", "?25,30");
45          isMapClick("img2", Boolean.FALSE, "", "");
46          isMapClick("img3", Boolean.TRUE, "", "");
47          isMapClick("img3", Boolean.TRUE, "", "");
48      }
49  
50      private void isMapClick(final String imgId, final Boolean samePage,
51              final String urlSuffixClick, final String urlSuffixClickXY) throws Exception {
52  
53          final URL urlImage = new URL(URL_FIRST, "img.jpg");
54          try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-jpg.img")) {
55              final byte[] directBytes = IOUtils.toByteArray(is);
56              getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
57          }
58  
59          final String htmlContent = DOCTYPE_HTML
60              + "<html>\n"
61              + "<head><title>foo</title></head>\n"
62              + "<body>\n"
63              + "  <a href='http://server/foo'>\n"
64              + "    <img id='img1' src='" + urlImage + "' ismap>\n"
65              + "    <img id='img2' src='" + urlImage + "'>\n"
66              + "  </a>\n"
67              + "  <img id='img3' src='" + urlImage + "' ismap>\n"
68              + "  <img id='img4' src='" + urlImage + "'>\n"
69              + "</body></html>";
70          final HtmlPage page = loadPage(htmlContent);
71  
72          final HtmlImage img = page.getHtmlElementById(imgId);
73  
74          final Page page2 = img.click();
75          assertEquals("same page after click", samePage, Boolean.valueOf(page == page2));
76          if (!samePage.booleanValue()) {
77              assertEquals("http://server/foo" + urlSuffixClick, page2.getUrl());
78          }
79  
80          final Page page3 = img.click(25, 30);
81          assertEquals("same page after click(25, 30)", samePage, Boolean.valueOf(page == page3));
82          if (!samePage.booleanValue()) {
83              assertEquals("http://server/foo" + urlSuffixClickXY, page3.getUrl());
84          }
85      }
86  
87      /**
88       * @throws Exception if the test fails
89       */
90      @Test
91      public void useMapClick() throws Exception {
92          useMapClick(0, 0, "/");
93          useMapClick(10, 10, "a.html");
94          useMapClick(19, 10, "a.html");
95          useMapClick(29, 10, "b.html");
96          useMapClick(50, 50, "/");
97      }
98  
99      /**
100      * @throws Exception if the test fails
101      */
102     private void useMapClick(final int x, final int y, final String urlSuffix) throws Exception {
103         final URL urlImage = new URL(URL_FIRST, "img.jpg");
104         try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-jpg.img")) {
105             final byte[] directBytes = IOUtils.toByteArray(is);
106             getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
107         }
108 
109         final String htmlContent = DOCTYPE_HTML
110             + "<html>\n"
111             + "<head><title>foo</title></head>\n"
112             + "<body>\n"
113             + "  <img id='myImg' src='" + urlImage + "' usemap='#map1'>\n"
114             + "  <map name='map1'>\n"
115             + "    <area href='a.html' shape='rect' coords='5,5,20,20'>\n"
116             + "    <area href='b.html' shape='circle' coords='25,10,10'>\n"
117             + "  </map>\n"
118             + "</body></html>";
119         final HtmlPage page = loadPage(htmlContent);
120 
121         final HtmlImage img = page.getHtmlElementById("myImg");
122 
123         final Page page2 = img.click(x, y);
124         final URL url = page2.getUrl();
125         assertTrue(url.toExternalForm(), url.toExternalForm().endsWith(urlSuffix));
126     }
127 
128     /**
129      * @throws Exception if the test fails
130      */
131     @Test
132     public void asXml() throws Exception {
133         final String content = DOCTYPE_HTML
134             + "<html><head><title>foo</title></head><body>\n"
135             + "<img id='img1' src='foo.png'>\n"
136             + "<img id='img2' name='testName' src='foo.png' alt='young'>\n"
137             + "<img id='img3' src='foo.png' width='11' height='17px'>\n"
138             + "<img id='img4' src='foo.png' width='11em' height='17%'>\n"
139             + "</body></html>";
140         final HtmlPage page = loadPage(content);
141 
142         HtmlImage img = page.getHtmlElementById("img1");
143         String expected = "<img id=\"img1\" src=\"foo.png\"/>";
144         assertEquals(expected, img.asXml());
145 
146         img = page.getHtmlElementById("img2");
147         expected = "<img id=\"img2\" name=\"testName\" src=\"foo.png\" alt=\"young\"/>";
148         assertEquals(expected, img.asXml());
149 
150         img = page.getHtmlElementById("img3");
151         expected = "<img id=\"img3\" src=\"foo.png\" width=\"11\" height=\"17px\"/>";
152         assertEquals(expected, img.asXml());
153 
154         img = page.getHtmlElementById("img4");
155         expected = "<img id=\"img4\" src=\"foo.png\" width=\"11em\" height=\"17%\"/>";
156         assertEquals(expected, img.asXml());
157     }
158 
159     /**
160      * Test case for issue #1833.
161      * Simply save the image without any parsing.
162      *
163      * @throws Exception if the test fails
164      */
165     @Test
166     public void saveAsNotSupportedImageType() throws Exception {
167         try (InputStream is = getClass().getClassLoader().
168                 getResourceAsStream("testfiles/not_supported_type.jpg")) {
169             final byte[] directBytes = IOUtils.toByteArray(is);
170             final URL urlImage = new URL(URL_FIRST, "img.jpg");
171             getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
172         }
173 
174         final String html = DOCTYPE_HTML
175             + "<html><head>\n"
176             + "</head>\n"
177             + "<body>\n"
178             + "  <img id='myImage' src='img.jpg' >\n"
179             + "</body></html>";
180 
181         final HtmlPage page = loadPage(html);
182 
183         final HtmlImage img = page.getHtmlElementById("myImage");
184         final File tempFile = File.createTempFile("img", ".tmp");
185         img.saveAs(tempFile);
186         FileUtils.deleteQuietly(tempFile);
187     }
188 
189     /**
190      * @throws Exception if the test fails
191      */
192     @Test
193     public void determineWidthHeightFromImage() throws Exception {
194         try (InputStream is = getClass().getClassLoader().
195                 getResourceAsStream("testfiles/4x7.jpg")) {
196             final byte[] directBytes = IOUtils.toByteArray(is);
197             final URL urlImage = new URL(URL_FIRST, "4x7.jpg");
198             getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
199         }
200         try (InputStream is = getClass().getClassLoader().
201                 getResourceAsStream("testfiles/tiny-jpg.img")) {
202             final byte[] directBytes = IOUtils.toByteArray(is);
203             final URL urlImage = new URL(URL_FIRST, "img.jpg");
204             getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
205         }
206 
207         final String html = DOCTYPE_HTML
208             + "<html><head>\n"
209             + "</head>\n"
210             + "<body>\n"
211             + "  <img id='myImage' src='4x7.jpg' >\n"
212             + "</body></html>";
213 
214         final HtmlPage page = loadPage(html);
215 
216         final HtmlImage img = page.getHtmlElementById("myImage");
217         assertEquals(4, img.getWidth());
218         assertEquals(7, img.getHeight());
219 
220         // source change has to force new determination
221         img.setAttribute("src", "img.jpg");
222         assertEquals(1, img.getWidth());
223         assertEquals(1, img.getHeight());
224     }
225 
226     /**
227      * @throws Exception on test failure
228      */
229     @Test
230     @Alerts(DEFAULT = {"16", "16", "2"},
231             FF = {"24", "24", "2"},
232             FF_ESR = {"24", "24", "2"})
233     public void retrieveImagePerDefault() throws Exception {
234         final String html = DOCTYPE_HTML
235                 + "<html>\n"
236                 + "<head></head>\n"
237                 + "<body>\n"
238                 + "  <img id='myImage' src='4x7.jpg' >\n"
239                 + "</body></html>";
240 
241         final int count = getMockWebConnection().getRequestCount();
242 
243         final HtmlPage page = loadPage(html);
244         final HtmlImage img = page.getHtmlElementById("myImage");
245         assertEquals(Integer.parseInt(getExpectedAlerts()[0]), img.getWidthOrDefault());
246         assertEquals(Integer.parseInt(getExpectedAlerts()[1]), img.getHeightOrDefault());
247 
248         assertEquals(Integer.parseInt(getExpectedAlerts()[2]), getMockWebConnection().getRequestCount() - count);
249     }
250 
251     /**
252      * @throws Exception on test failure
253      */
254     @Test
255     @Alerts({"4x7.jpg", "§§URL§§4x7.jpg"})
256     public void src() throws Exception {
257         final String html = DOCTYPE_HTML
258                 + "<html>\n"
259                 + "<head></head>\n"
260                 + "<body>\n"
261                 + "  <img id='myImage' src='4x7.jpg' >\n"
262                 + "</body></html>";
263 
264         final HtmlPage page = loadPage(html);
265         final HtmlImage img = page.getHtmlElementById("myImage");
266 
267         expandExpectedAlertsVariables(URL_FIRST);
268         assertEquals(getExpectedAlerts()[0], img.getSrcAttribute());
269         assertEquals(getExpectedAlerts()[1], img.getSrc());
270     }
271 
272     /**
273      * @throws Exception if the test fails
274      */
275     @Test
276     @Alerts({"8-8-18-18-", "10-15-18-18-"})
277     public void clickWithCoordinates() throws Exception {
278         try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-gif.img")) {
279             final byte[] directBytes = IOUtils.toByteArray(is);
280             final URL urlImage = new URL(URL_SECOND, "img.gif");
281             getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok",
282                     MimeType.IMAGE_GIF, Collections.emptyList());
283         }
284 
285         final String html = DOCTYPE_HTML
286             + "<html><head>\n"
287             + "<script>\n"
288             + "  function log(msg) { window.document.title += msg + '-';}\n"
289             + "  function clickImage(event) {\n"
290             + "    log(event.clientX);\n"
291             + "    log(event.clientY);\n"
292             + "    log(event.screenX);\n"
293             + "    log(event.screenY);\n"
294             + "  }\n"
295             + "</script>\n"
296             + "</head>\n"
297             + "<body>\n"
298             + "  <img id='myImage' src='" + URL_SECOND + "img.gif' "
299                     + "width='100px' height='42px' onclick='clickImage(event)'>\n"
300             + "</body>\n"
301             + "</html>";
302 
303         final HtmlPage page = loadPage(html);
304         final HtmlImage img = page.getHtmlElementById("myImage");
305 
306         img.click();
307         assertEquals(getExpectedAlerts()[0], page.getTitleText());
308 
309         img.click(2, 7);
310         assertEquals(getExpectedAlerts()[0] + getExpectedAlerts()[1], page.getTitleText());
311     }
312 }