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.platform.image;
16  
17  import java.io.IOException;
18  import java.io.InputStream;
19  import java.util.Iterator;
20  
21  import javax.imageio.ImageIO;
22  import javax.imageio.ImageReader;
23  import javax.imageio.stream.ImageInputStream;
24  
25  import org.htmlunit.platform.geom.IntDimension2D;
26  
27  /**
28   * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br>
29   *
30   * Wraps the ImageReader for an HtmlImage. This is necessary because an object with a finalize()
31   * method is only garbage collected after the method has been run. Which causes all referenced
32   * objects to also not be garbage collected until this happens. Because a HtmlImage references a lot
33   * of objects which could all be garbage collected without impacting the ImageReader it is better to
34   * wrap it in another class.
35   *
36   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
37   * @author David K. Taylor
38   * @author <a href="mailto:cse@dynabean.de">Christian Sell</a>
39   * @author Ahmed Ashour
40   * @author <a href="mailto:knut.johannes.dahle@gmail.com">Knut Johannes Dahle</a>
41   * @author Ronald Brill
42   * @author Frank Danek
43   * @author Carsten Steul
44   * @author Alex Gorbatovsky
45   */
46  public class ImageIOImageData implements ImageData {
47  
48      // private static final Log LOG = LogFactory.getLog(ImageIOImageData.class);
49  
50      private final ImageReader imageReader_;
51  
52      /**
53       * Ctor.
54       * @param inputStream the {@link InputStream} to read from
55       * @throws IOException in case of error
56       */
57      public ImageIOImageData(final InputStream inputStream) throws IOException {
58          final ImageInputStream iis = ImageIO.createImageInputStream(inputStream);
59          final Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);
60          if (!iter.hasNext()) {
61              iis.close();
62              throw new IOException("No image detected in response");
63          }
64          final ImageReader imageReader = iter.next();
65          imageReader.setInput(iis);
66  
67          imageReader_ = imageReader;
68  
69          // dispose all others
70          while (iter.hasNext()) {
71              iter.next().dispose();
72          }
73      }
74  
75      /**
76       * @return the {@link ImageReader}
77       */
78      public ImageReader getImageReader() {
79          return imageReader_;
80      }
81  
82      /**
83       * {@inheritDoc}
84       */
85      @Override
86      public IntDimension2D getWidthHeight() throws IOException {
87          return new IntDimension2D(imageReader_.getWidth(0), imageReader_.getHeight(0));
88      }
89  
90      /**
91       * {@inheritDoc}
92       */
93      @Override
94      protected void finalize() throws Throwable {
95          close();
96          super.finalize();
97      }
98  
99      @Override
100     @SuppressWarnings("PMD.UnusedLocalVariable")
101     public void close() throws IOException {
102         if (imageReader_ != null) {
103             try {
104                 try (ImageInputStream stream = (ImageInputStream) imageReader_.getInput()) {
105                     // nothing
106                 }
107             }
108             finally {
109                 imageReader_.setInput(null);
110                 imageReader_.dispose();
111             }
112         }
113     }
114 }