【问题标题】:Java get image extension/type using BufferedImage from URLJava 使用 BufferedImage 从 URL 获取图像扩展名/类型
【发布时间】:2012-07-11 22:04:46
【问题描述】:

我熟悉working with images。我retrieve/read an image from a URL,其中的 URL 没有文件扩展名。然后我想write/save the image到本地存储,但是我必须指定图像文件扩展名(即JPG,PNG等),我无法通过BufferedImage检索其扩展名。

请指出如何做到这一点? 任何其他方法都可以。

【问题讨论】:

    标签: java image


    【解决方案1】:

    如果对象是 URL,则使用 ImageIO.createImageInputStream(obj) 的建议将不起作用。

    另一种方法是使用 URLConnection.guessContentTypeFromStream(InputStream stream) 方法。此方法通过检查流的前 12 个字节来猜测内容类型。

    使用此方法的一个复杂之处是它需要将给定的流参数标记为支持,而 java url.openStream() 返回的流不标记为支持。

    此外,如果您想确定内容类型并将图像下载到 BufferedImage,那么最好解决方案只下载一次内容(而不是进行两次传递,一次确定内容类型和第二次下载图像)。

    一种解决方案是使用 PushbackInputStream。 PushbackInputStream 可用于下载第一个初始字节以确定内容类型。然后可以将字节推回流上,以便 ImageIO.read(stream) 可以完整地读取流。

    可能的解决方案:

    // URLConnection.guessContentTypeFromStream only needs the first 12 bytes, but
    // just to be safe from future java api enhancements, we'll use a larger number
    int pushbackLimit = 100;
    InputStream urlStream = url.openStream();
    PushbackInputStream pushUrlStream = new PushbackInputStream(urlStream, pushbackLimit);
    byte [] firstBytes = new byte[pushbackLimit];
    // download the first initial bytes into a byte array, which we will later pass to 
    // URLConnection.guessContentTypeFromStream  
    pushUrlStream.read(firstBytes);
    // push the bytes back onto the PushbackInputStream so that the stream can be read 
    // by ImageIO reader in its entirety
    pushUrlStream.unread(firstBytes);
    
    String imageType = null;
    // Pass the initial bytes to URLConnection.guessContentTypeFromStream in the form of a
    // ByteArrayInputStream, which is mark supported.
    ByteArrayInputStream bais = new ByteArrayInputStream(firstBytes);
    String mimeType = URLConnection.guessContentTypeFromStream(bais);
    if (mimeType.startsWith("image/"))
        imageType = mimeType.substring("image/".length());
    // else handle failure here
    
    // read in image
    BufferedImage inputImage = ImageIO.read(pushUrlStream);
    

    【讨论】:

      【解决方案2】:

      如果您从 URL 获取图像,这意味着您可以通过 InputStream 访问该图像。从中您可以使用ImageIO 获取图像类型(格式)并使用以下代码同时创建一个 BufferedImage。

      public static BufferedImageWrapper getImageAndTypeFromInputStream(InputStream is) {
      
          String format = null;
          BufferedImage bufferedimage = null;
          try (ImageInputStream iis = ImageIO.createImageInputStream(is);) {
      
            Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
      
            if (readers.hasNext()) {
      
              ImageReader reader = readers.next();
              format = reader.getFormatName();
              reader.setInput(iis);
              bufferedimage = reader.read(0);
            }
          } catch (IOException e) {
            logger.error("ERROR DETERMINING IMAGE TYPE!!!", e);
          }
      
          return new BufferedImageWrapper(format, bufferedimage);
        }
      
        public static class BufferedImageWrapper {
      
          private final String imageType;
          private final BufferedImage bufferedimage;
      
          /**
           * Constructor
           *
           * @param imageType
           * @param bufferedimage
           */
          public BufferedImageWrapper(String imageType, BufferedImage bufferedimage) {
            this.imageType = imageType;
            this.bufferedimage = bufferedimage;
          }
      
          public String getImageType() {
      
            return imageType;
          }
      
          public BufferedImage getBufferedimage() {
      
            return bufferedimage;
          }
      
        }
      

      【讨论】:

        【解决方案3】:

        这是通过输入 URL 对象(即图像)并返回文件扩展名来实现的

        它需要初始下载,到 java tmp 目录,然后在 ImageReader 尝试获取收集图像类型后将其删除

        public String getImageFileExtFromUrl(URL urlObject) throws URISyntaxException, IOException{
            System.out.println("IN DOWNLOAD FILE FROM URL METHOD");
            String tmpFolder = System.getProperty("java.io.tmpdir");
            String tmpFileStr = tmpFolder + "/" + new Date().getTime();
            Files.copy(urlObject.openStream(), Paths.get(tmpFileStr), StandardCopyOption.REPLACE_EXISTING);
            File download = new File(tmpFileStr);
            System.out.println("FILE DOWNLOAD EXISTS: " + download.exists() );
            try{
                ImageInputStream iis = ImageIO.createImageInputStream(download);
                Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);
        
                ImageReader reader = iter.next();
                String formatName = reader.getFormatName();
                System.out.println("FOUND IMAGE FORMAT :" + formatName);
                iis.close();
                return formatName;
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                Files.delete(Paths.get(tmpFileStr));
            }
            return null;
        
        
        
        }
        

        【讨论】:

          【解决方案4】:

          使用ImageReader.getFormatName()

          您可以使用ImageIO.getImageReaders(Object input) 获取文件的图像阅读器。

          我自己没有测试过,但是你可以试试这个:

          ImageInputStream iis = ImageIO.createImageInputStream(file);
          
          Iterator<ImageReader> imageReaders = ImageIO.getImageReaders(iis);
          
          while (imageReaders.hasNext()) {
              ImageReader reader = (ImageReader) imageReaders.next();
              System.out.printf("formatName: %s%n", reader.getFormatName());
          }
          

          【讨论】:

          • 您的 sn-p 与 Java Image I/O Guide 的组合帮助我解决了问题。
          • 下载图像时非常无用,您无法将其存储到文件中。此外,问题是关于 BufferedImage 而不是文件。为什么这会得到如此多的支持,这超出了我的理解。
          猜你喜欢
          • 2018-06-18
          • 2021-02-02
          • 1970-01-01
          • 1970-01-01
          • 2012-08-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多