【问题标题】:How can I save a JPEG from a URL to a file?如何将 JPEG 从 URL 保存到文件?
【发布时间】:2011-01-16 10:49:10
【问题描述】:

我正在尝试使用 Java 将 JPEG 图像从 URL 保存到文件中。 网址:http://150.214.222.100//axis-cgi/mjpg/video.cgi?resolution=640x480&compression=1&duration=1&timeout=&dummy=garb

我尝试了以下方法: 1)

Image image = fetchImage(urlNorthView);

saveImage2Disk(image);

public static Image fetchImage( URL u ) throws MalformedURLException, IOException   {
      Toolkit tk = Toolkit.getDefaultToolkit();
      return tk.createImage(u );
}

private void saveImage2Disk(Image Image) throws IOException{
        File outputFile = new File("urlNorthView"+Calendar.getInstance().getTimeInMillis()+".jpg");

        BufferedImage bufferedImage = new BufferedImage(Image.getWidth(null),Image.getHeight(null), BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = bufferedImage.createGraphics();
        g2.drawImage(Image, null, null);
        ImageIO.write(bufferedImage, "jpg", outputFile);
    }

=> 例外:“宽度 (-1) 和高度 (-1) 不能

2)

inputStream2Disk((InputStream) urlNorthView.getContent());

private void inputStream2Disk(InputStream in) throws Exception{
        File outputFile = new File("urlNorthView"+Calendar.getInstance().getTimeInMillis()+".jpg");
        OutputStream out=new FileOutputStream(outputFile);
        byte buf[]=new byte[1024];
        int len;
        while((len=in.read(buf))>0)
        out.write(buf,0,len);
        out.close();
        in.close();
    }

文件以某种方式损坏。当我用Kate 打开它时,我可以阅读:

--myboundary Content-Type: image/jpeg Content-Length: 38256 ....

二进制文件中不应有任何文本。

可能是什么问题?

【问题讨论】:

  • 注意:您使用第二种方法得到的是从 URL 检索到的 full 内容 - 包括标头,其中包含有关服务器发回的信息的信息。 (通常我们使用浏览器查看互联网上的项目,浏览器会解释标题以供自己使用并仅向我们显示内容。)
  • 那些不是 http 标头,它们是 mime 标头。它们不存在于绝大多数 http 响应中,但在这种情况下它们是 http 响应主体的一部分。请参阅下面的回复。如果您的浏览器使用给定的 url 显示图像,那是因为它足够聪明,可以解析 mime 部分。

标签: java image url jpeg


【解决方案1】:

尝试以下方法将Image 转换为BufferedImage

private static BufferedImage getBufferedImage(Image img, int imageType) {
    if (img instanceof BufferedImage) {
        return (BufferedImage) img;
    }

     BufferedImage bi = new BufferedImage(img.getWidth(null), img
             .getHeight(null), imageType);

     Graphics2D g = (Graphics2D) bi.getGraphics();
     g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
             RenderingHints.VALUE_ANTIALIAS_ON);

     g.drawImage(img, 0, 0, null);
     g.dispose();

     return bi;
 }

(其中imageTypeBufferedImage 声明的常量之一。很可能是TYPE_INT_RGB

否则你的第一种方法很好。

我推荐第一种(高级)方法而不是第二种(低级)。

【讨论】:

    【解决方案2】:

    由于某种原因,请求该图像时的 http 响应正文包含 mime 部分(mime 部分对于将多个文件放入单个响应中很有用)。在这个响应中,只有一个 mime 部分,所以它几乎没有用。

    javax.mail 包中有代码,如果需要,您可以使用它来正确解析它,但它不是一个很好的 api,恕我直言。

    或者,您可以通过多种方式自行在代码中修复此问题。由于只有一个 mime 部分,您可以从输入流的开头丢弃数据,直到您看到一行中的两个换行符(字节等于 10)。这应该可以工作,因为 mime 标头应该是 7 位 ascii、iirc,因此无需担心字符编码。

    这里是一些示例代码:

    URLConnection conn = urlNorthView.openConnection();
    InputStream in = conn.getInputStream();
    String contentType = conn.getHeaderField("Content-Type");
    if (!"image/jpeg".equals(contentType)) {
        // hack: assuming it's mime if not a raw image
        int one = in.read();
        if (one == -1) {
            // stop??
        }
        int two = in.read();
        while (two != -1 && !(two == 10 && one == 10)) {
            one = two;
            two = in.read();
        }
    }
    // if it was mime, we've stripped off the mime headers
    // and should now get the image
    inputStream2Disk(in);
    

    编辑:废话,你会看到两个\r\n,而不是两个\n,或者字节0x0d、0x0a、0x0d、0x0a。在您看到这种模式之前丢弃数据作为练习留给读者;)

    【讨论】:

    • 像魅力一样工作:) int two = in.read(); int 三 = in.read(); int 四 = in.read(); while (二 != -1 && !(一 == 13 && 二 == 10 && 三 == 13 && 四 == 10 )) { 一 = 二;二 = 三;三 = 四;四= in.read(); }
    • @M.R.很好,但这是太低级的操作。您通常希望避免这种情况。
    猜你喜欢
    • 2016-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多