前言:
晚上刷朋友圈,看到這樣一條朋友圈挺有意思的,如下:
於是,我點開文章后,大概看了下文章的意思,其實就是把一個圖片分成九宮圖,即拼圖的碎片,既然Python都能實現,作為回應,java也是可以做到的。
接着,一時技癢,整理了下思路。就馬上打開IDEA開始編碼,就有了這篇文章。
某號的實現:
將一張完整的圖片分割成9張小圖片,制作成朋友圈九宮格的圖片,從而在朋友圈曬出不一樣的美景。
我的追加實現:
將分割成的九個小圖片,在生成一個拼圖頭像圖片。
最終實現效果:
主要思路:
1、 一個待繪制的BufferedImage,長寬都是原圖的1/3
2、使用graphics,通過偏移量選擇繪制原圖的區域
3、繪制結束就可以輸出到文件
4、通過兩層循環,繪制9個位置的全部圖片
5、將生成九個拼圖碎片進行圖片合成
實現代碼:
1、生成拼圖碎片
具體示例代碼如下:
import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; /** * @author rongrong * @version 1.0 * @description 將圖片分成九個拼圖碎片 * @date 2020/7/28 20:20 */ public class SetImage { public static void main(String[] args) { File imgfile; Image originimg; BufferedImage image; Graphics g; FileOutputStream out; JPEGImageEncoder encoder; try { // 獲取原始圖片 imgfile = new File("D:\\picture\\original.jpg"); originimg = ImageIO.read(imgfile); // 獲取原始圖片的寬和高 int width = originimg.getWidth(null); int height = originimg.getHeight(null); // 如果輸入為長方形,重新計算長寬 int outputwidth = width > height ? height : width; int outputheight = outputwidth; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { // 九宮格,每張圖片大小都為原來的1/3 // 長方形,新建圖片大小為計算后的正方型的1/3 image = new BufferedImage(outputwidth / 3, outputheight / 3, BufferedImage.TYPE_INT_RGB); // 創建圖片 g = image.createGraphics(); // 繪制圖片 // 長方形,計算偏移量的數據采用計算后的正方形 g.drawImage(originimg, outputwidth * -i / 3, outputheight * -j / 3, width, height, null); // 圖片繪制完成,關閉g g.dispose(); // 輸出流和輸出文件 out = new FileOutputStream("D:\\log\\" + (i+1)+ "-" + j + ".jpg"); // 下面代碼將輸出圖片轉換為JPEG、JPG文件 encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(image); out.close(); System.out.println("拼圖碎片已分拆成功"); } } } catch (Exception e) { e.printStackTrace(); } } }
2、利用生成拼圖碎片合成頭像圖片
具體示例代碼如下:
import javax.imageio.ImageIO; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; /** * @description 將九個拼圖生成頭像 * @author rongrong * @version 1.0 * @date 2020/7/28 21:18 */ public class MakeGropHeadPic { /**圖片寬度*/ private final Integer PIC_WIDTH = 422; /**圖片高度*/ private final Integer PIC_HEIGHT = 422; /**空白寬度*/ private final Integer PIC_SPACE = 14; /**小圖片寬度*/ private Double LUMP_WIDTH = null; /**小圖片起始點橫坐標*/ private Double LUMP_POINT_X = null; /**小圖片起始點縱坐標*/ private Double LUMP_POINT_Y = null; // 圍邊使用的灰色 private final int [] COLOR_GREY_BGR = new int[] {230, 230, 230}; //校對數組使用下標 private int flg = 0; public static void main(String[] args) { MakeGropHeadPic picUtil = new MakeGropHeadPic(); //添加拼圖圖片 List<String> pics = new ArrayList<>(); pics.add("D:\\picture\\1-0.jpg"); pics.add("D:\\picture\\2-0.jpg"); pics.add("D:\\picture\\3-0.jpg"); pics.add("D:\\picture\\1-1.jpg"); pics.add("D:\\picture\\2-1.jpg"); pics.add("D:\\picture\\3-1.jpg"); pics.add("D:\\picture\\1-2.jpg"); pics.add("D:\\picture\\2-2.jpg"); pics.add("D:\\picture\\3-2.jpg"); picUtil.getCombinationOfhead(pics,"D:\\picture\\","拼圖頭像"); } /** * @param pics 圖片列表 * @param path 存儲路徑 * @param fileName 存儲圖片名稱 * @return 成功 OR 失敗 */ public boolean getCombinationOfhead(List<String> pics, String path, String fileName){ List<BufferedImage> bufferedImages = new ArrayList<BufferedImage>(); // BufferedImage.TYPE_INT_RGB可以自己定義可查看API BufferedImage outImage = new BufferedImage(PIC_WIDTH, PIC_HEIGHT, BufferedImage.TYPE_INT_RGB); Graphics2D gra = outImage.createGraphics(); //設置背景為藍灰色 gra.setColor(toColor(COLOR_GREY_BGR)); //填滿圖片 gra.fillRect(0, 0, PIC_WIDTH, PIC_HEIGHT); // 開始拼湊 根據圖片的數量判斷該生成哪種樣式組合頭像 Integer size = pics.size();//圖片數量 Integer sqrt = (int)Math.ceil(Math.sqrt(size));//寬度 一行幾張圖片 //計算出 單張圖片寬度 LUMP_WIDTH = (PIC_WIDTH - ((sqrt + 1.0) * PIC_SPACE))/sqrt; System.out.println(LUMP_WIDTH); // 壓縮圖片所有的圖片生成尺寸同意的 為 125*125 for (int i = 0; i < pics.size(); i++) { BufferedImage resize2 = resize2(pics.get(i), LUMP_WIDTH.intValue(), LUMP_WIDTH.intValue(), true); bufferedImages.add(resize2); } //缺幾個滿伍 int lack = 0; //計算起始點坐標 if(size < sqrt*(sqrt-1)){//少一行 不滿伍 //缺幾個滿伍 lack = sqrt*(sqrt-1) - size; //向右邊偏移量 LUMP_POINT_X = PIC_SPACE.doubleValue() + lack * (LUMP_WIDTH + PIC_SPACE) / 2; //向下偏移量 LUMP_POINT_Y = PIC_SPACE.doubleValue() + LUMP_WIDTH/2.; }else if (size == sqrt*(sqrt-1)){//滿伍少一行 //向右邊偏移量 LUMP_POINT_X = PIC_SPACE.doubleValue(); //向下偏移量 LUMP_POINT_Y = PIC_SPACE.doubleValue() + LUMP_WIDTH/2.; }else if(size < sqrt*sqrt){//不滿伍 //缺幾個滿伍 lack = sqrt*sqrt - size; //向右邊偏移量 LUMP_POINT_X = PIC_SPACE.doubleValue()+ lack * (LUMP_WIDTH + PIC_SPACE) / 2; LUMP_POINT_Y = PIC_SPACE.doubleValue(); }else if (size == sqrt*sqrt){//滿伍 LUMP_POINT_X = PIC_SPACE.doubleValue(); LUMP_POINT_Y = PIC_SPACE.doubleValue(); } int line = lack==0?-1:0; //第幾行圖片 int row = 0; //第幾列圖片 for (int i = 0; i < bufferedImages.size(); i++){ if ((i + lack) % sqrt == 0){ line ++; row = 0; } if(line == 0){ gra.drawImage(bufferedImages.get(i), LUMP_POINT_X.intValue() + (row++ * (PIC_SPACE+LUMP_WIDTH.intValue())) , LUMP_POINT_Y.intValue(), null); }else{ gra.drawImage(bufferedImages.get(i), PIC_SPACE + (row++ * (PIC_SPACE+LUMP_WIDTH.intValue())) , LUMP_POINT_Y.intValue() + (line * (PIC_SPACE+LUMP_WIDTH.intValue())), null); } } File file = new File(path+fileName+".png"); //文件如果存在先刪除,再創建 try { if(!file.getParentFile().exists()) { file.getParentFile().mkdirs(); if(file.exists()) { file.delete(); if(!file.createNewFile()) { System.out.println("創建失敗!"); } } } }catch(IOException e) { e.printStackTrace(); } //將圖片寫到文件 try { return ImageIO.write(outImage, "png", file); } catch (IOException e) { return false; } } /** * 圖片縮放 * @param picPath 本地或網絡圖片路徑 * @param height 縮放后高度 * @param width 縮放后寬度 * @param fill 是否填充灰色 * @return BufferedImage */ public BufferedImage resize2(String picPath, Integer height, Integer width, boolean fill){ try { BufferedImage imageBuff =null; if(picPath.indexOf("https://")==0 || picPath.indexOf("http://")==0){ //簡單判斷是網絡圖片還是本地圖片 imageBuff = ImageIO.read(new URL(picPath)); }else{ imageBuff = ImageIO.read(new File(picPath)); } Image itemp = imageBuff.getScaledInstance(width, height, Image.SCALE_SMOOTH); double ratio = 0; // 縮放比例 // 計算比例 if ((imageBuff.getHeight() > height) || (imageBuff.getWidth() > width)) { if (imageBuff.getHeight() > imageBuff.getWidth()) { ratio = height.doubleValue()/ imageBuff.getHeight(); } else { ratio = width.doubleValue() / imageBuff.getWidth(); } AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(ratio, ratio), null); itemp = op.filter(imageBuff, null); } if (fill) { BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = image.createGraphics(); g.setColor(toColor(COLOR_GREY_BGR)); g.fillRect(0, 0, width, height); if (width == itemp.getWidth(null)) g.drawImage(itemp, 0, (height - itemp.getHeight(null)) / 2, itemp.getWidth(null), itemp.getHeight(null), Color.white, null); else g.drawImage(itemp, (width - itemp.getWidth(null)) / 2, 0, itemp.getWidth(null), itemp.getHeight(null), Color.white, null); g.dispose(); itemp = image; } return (BufferedImage) itemp; } catch (IOException e) { e.printStackTrace(); } return null; } /** * @toColor 顏色索引轉為顏色 * @param colorRoot 顏色索引 * @return 顏色 */ private Color toColor(int[] colorRoot) { if(colorRoot.length>=3) { return new Color(colorRoot[0], colorRoot[1], colorRoot[2]); }else { return null; } } }
整個過程分為兩個部分:
1、轉換圖片、切割圖片和保存圖片
2、切割圖片合成新圖片
體驗:
最后,我們找一張圖片來做測試,比如我把源文件放到D盤的picture文件夾下,如下圖:
1、首先,運行先生成拼圖圖片,即九宮格的碎片。結果如下圖所示:
從截圖我們可以看到,我們的圖片切割精准都是正方形,所以這段代碼拿去盡管去用即可。
2、將九張拼圖合成一個圖片頭像,在來運行第二個類,結果如下圖所示:
最后
以上便是一個生成拼圖碎片,再生成拼圖頭像的過程。感興趣的朋友,還不趕緊去試試?
大家如果覺得喜歡,點個“在看”並分享給更多的朋友吧!