Java圖片處理:ico格式轉 PNG/JPG等格式
- 2019 年 10 月 3 日
- 筆記
一. 什麼是ico圖標?
ico
是一種圖標格式,大量應用於網站,各個軟體的logo或圖標展示。
我們在進入某個網站或網頁,它們上方標題左側各自都帶有logo圖標。
這就是favicon.ico
圖標,它可以讓瀏覽器的收藏夾中除顯示相應的標題外,還可以用圖標的方式區別不同的網站。
二. ico圖標的特點
一張ico圖標里,有可能只有一張或包含多張的圖片資訊,圖片的清晰度越來越高。
三. 用Java來處理ico, 並轉換成其他格式圖片
做這種ico格式的圖片轉換功能,並不是特別容易,是有區別於普通圖片格式轉換,我經過不斷嘗試,調試,得到了一個自己還比較滿意的結果。
我們在看程式碼之前,還是先看看我自己對這個功能的需求理解:
-
i. 需要有工具類能夠讀取ico的圖片流。
-
ii. 對ico進行放大操作,儘可能地解決圖片因為放大而出現模糊及毛刺。
-
iii. 能夠將ico圖片轉換成其他格式的圖片保存。
為了實現以上的3點功能,我需要藉助這三個優秀的jar來實現此功能:
image4j.jar
主要讀取ico圖片java-image-scaling-0.8.6.jar
主要縮放,修改圖片大小filters-2.0.235-1.jar
是image-scaling的依賴包
3.1 image4j.jar 主要讀取ico圖片
JDK沒有提供讀取ico圖片的相關工具類,所以我們需要先解決讀取ico格式的圖片問題。
這裡我找了相關的jar, 經過測試,image4j.jar中能讀取。
image4j.jar
中涉及的主要類:ICODecoder
類
上面標記的四個方法中, 返回的是為什麼是List集合?這裡回到ICO的特點中來說,一張ICO圖片包含一張或多張圖片資訊(取到圖片後,看到圖片主要是清晰度不同)
下面我是從發送http請求,從響應的圖片流解析ICO圖片
/** * 獲取ICO圖片 * @param surl * @return */ public static List<ICOImage> getICOImageByUrl(String surl) { HttpURLConnection httpURLConnection = null; List<ICOImage> list = new ArrayList<>(); try { URL url = new URL(surl); // https證書 checkQuietly(); httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.setInstanceFollowRedirects(false); httpURLConnection.setRequestMethod("GET"); httpURLConnection.setConnectTimeout(30000); httpURLConnection.setReadTimeout(30000); httpURLConnection.setDoOutput(true); httpURLConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"); httpURLConnection.setRequestProperty("Charset", "UTF-8"); httpURLConnection.setRequestProperty("Accept", "*/*"); httpURLConnection.setRequestProperty("content-type","image/x-icon"); // 創建連接 httpURLConnection.connect(); if (httpURLConnection.getResponseCode() == 200) { InputStream in = httpURLConnection.getInputStream(); list = ICODecoder.readExt(in); // 從響應結果集中獲取ico圖片流 return list; } }catch (Exception e) { e.printStackTrace(); }finally { if(httpURLConnection != null){ httpURLConnection.disconnect(); } } return list; } /** * 配置https證書 */ public static void checkQuietly() { try { HttpsURLConnection .setDefaultHostnameVerifier(new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }); SSLContext context = SSLContext.getInstance("TLS"); context.init(null, new X509TrustManager[] { new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } } }, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(context .getSocketFactory()); } catch (Exception e) { e.printStackTrace(); } }
3.2 java-image-scaling-0.8.6.jar 主要縮放,修改圖片大小
由於ICO圖標的像素大小(寬高)都比較小,再獲取到圖片後, 需要調整大小。如果採用普通方式去調整大小的話,圖片會模糊,而且會出現類似馬賽克的影像噪點。這樣的效果並不理想。
下面的方法就是對ICO圖片進行放大到80×80像素,在轉換成PNG,並轉換成base64,以便保存。
/** * 處理ICOImage圖片 */ public static String hadleICOImage(ICOImage icoImage) throws IOException { ResampleOp resampleOp = new ResampleOp(80,80); resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.Oversharpened); BufferedImage bi = resampleOp.filter(icoImage.getImage(), null); BufferedImage result = null; /* 新生成結果圖片 */ result = new BufferedImage(80, 80, BufferedImage.TYPE_INT_RGB); Graphics2D g = result.createGraphics(); g.setColor(Color.WHITE); g.drawImage(bi.getScaledInstance(80,80, Image.SCALE_SMOOTH), 0, 0, null); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ImageIO.write(result, PNG, bos); BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(bos.toByteArray()).replaceAll("n", "").replaceAll("r", "").trim(); }
3.2 實現ICO轉PNG
從調用getICOImageByUrl()
獲取List<ICOImage>
這樣一個list集合,獲取最後一張,並實現轉換。
List<ICOImage> icoImages = getICOImageByUrl(url); // 取最後一張最清晰的圖片出來 ICOImage icoImage = icoImages.get(icoImages.size() - 1); // 處理圖片(轉換大小,圖片格式)並保存 hadleICOImage(icoImage);