2010-02-13 54 views
1

我試圖將URL中的JPEG圖像保存爲使用Java的文件。 URL:http://150.214.222.100//axis-cgi/mjpg/video.cgi?resolution=640x480&compression=1&duration=1&timeout=&dummy=garb如何將JPEG從URL保存到文件?

我嘗試以下: 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)不能< = 0」

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內容類型:圖像/ JPEG內容長度:38256 ....

不應該有在任何文本二進制文件。

問題是什麼?

+0

注意:第二種方法得到的是從URL中檢索的* full *內容 - 包括標題,其中包含信息關於服務器發回的內容。 (通常,我們使用瀏覽器查看互聯網上的項目,瀏覽器將解釋標題以供自己使用,並僅向我們顯示內容。) – Arkaaito 2010-02-13 09:09:43

+0

這些不是http標題,它們是mime標題。它們並不存在於絕大多數http響應中,但在這種情況下它們是http響應主體的一部分。請參閱下面的回覆。如果您的瀏覽器使用給定的URL顯示圖像,這是因爲它足夠聰明來解析MIME部分。 – 2010-02-13 09:32:35

回答

2

由於某些原因,請求該圖像時的http響應正文包含一個MIME部分(MIME部分對於將多個文件放入單個響應非常有用)。在這個迴應中,只有一個MIME部分,所以它幾乎是無用的。

javax.mail包中有代碼,如果需要,您可能可以使用它來正確解析此代碼,但它不是一個非常好的api,imho。

另外,有很多方法可以讓你自己修改代碼。由於只有一個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); 

編輯:廢話,而不是兩個\ -N,你會看到兩個\ r \ n或字節0X0D,0X0A,0X0D,0X0A。丟棄數據,直到看到這種模式,這是留給讀者的練習;)

+0

作品像一個魅力:) int two = in.read(); int three = in.read(); int four = in.read(); (two!= -1 &&!(one == 13 && two == 10 && three == 13 && four == 10)) \t \t one = two; \t \t two = three; \t \t三=四; \t \t four = in.read(); \t \t} – 2010-02-13 10:15:00

+0

@ M.R。不錯,但是這個操作太低級了。你通常想避免這種情況。 – Bozho 2010-02-13 12:19:52

1

試試下面的方法,用於將ImageBufferedImage

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; 
} 

(其中imageType是宣佈BufferedImage的一個常數。最有可能的TYPE_INT_RGB

否則,你的第一種方法是好的。

我會推薦第一個(高級別)方法,第二個(低級別)。