牛刀小試:用Java實現商品卡片效果,文末附源碼

先看下效果圖


牛刀小試:用Java實現商品卡片效果,文末附源碼

牛刀小試:用Java實現商品卡片效果,文末附源碼

實現思路

  • PS 扣一個底層的模板圖片
  • 讀取底層模板圖片
  • 繪製產品主圖, 圖片加圓角處理, 圖片抗鋸齒處理
  • 繪製產品標題, 計算內容寬度並換行, 文字座標計算, 字體抗鋸齒處理
  • 繪製產品價格
  • 生成二維碼圖片, 二維碼白邊處理

PS 扣一個底層的模板圖片

這個環節我們主要用PS摳圖並記錄下每個元素的座標和大小

牛刀小試:用Java實現商品卡片效果,文末附源碼

<code>/**
* 產品圖片區域
*/
private Rectangle imageArea = new Rectangle(64, 64, 620, 620);
/**
* 標題區域
*/
private Rectangle titleArea = new Rectangle(86, 712, 300, 64);
/**
* 價格區域
*/
private Rectangle priceArea = new Rectangle(552, 720, 118, 43);
/**
* 二維碼區域
*/
private Rectangle qrcodeArea = new Rectangle(87, 830, 100, 100);/<code>

讀取底層模板圖片

<code>// 讀取模版圖片
final BufferedImage cardImg = ImageIO.read(ClassLoader.getSystemResource(templatePath));
final Graphics2D g = cardImg.createGraphics();/<code>

繪製產品主圖,加圓角,抗鋸齒

<code>// 繪製封面
BufferedImage productImg = ImageIO.read(product.getProductImageUrl());
// 切圓角
productImg = setRadius(productImg, 60);
// 繪製
g.drawImage(productImg, imageArea.x, imageArea.y, imageArea.width, imageArea.height, null);/<code>
<code>public static BufferedImage setRadius(BufferedImage srcImage, int radius) {
int w = srcImage.getWidth();
int h = srcImage.getHeight();
BufferedImage output = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = output.createGraphics();
g2.setComposite(AlphaComposite.SrcOut);
// 抗鋸齒
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(new Color(0, 0, 0));
g2.setBackground(Color.black);
g2.setPaint(new Color(0, 0, 0));

g2.fill(new RoundRectangle2D.Float(0, 0, w, h, radius, radius));
g2.setComposite(AlphaComposite.SrcAtop);
g2.drawImage(srcImage, 0, 0, null);
g2.dispose();
return output;
}/<code>

繪製產品標題,換行,座標計算,抗鋸齒

在使用drawString 繪製文本內容的時候如果, 你需要填寫座標 x, y 如果你直接把ps上面的座標用在代碼裡面的話你會發現位置根本就不對, 那是為什麼呢?


牛刀小試:用Java實現商品卡片效果,文末附源碼

字體的高由個元素組成: ascent , descent

drawString中用的y座標是指baseline的y座標,即字體所在矩形的左上角y座標+ascent

<code>// 開啟文本抗鋸齒
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);/<code>
<code>private void drawTitle(ProductCard product, Graphics2D g) {
g.setColor(Color.decode("#666666"));
g.setFont(new Font("宋體", Font.BOLD, 28));
int ascent = g.getFontMetrics(g.getFont()).getAscent();
final Rectangle2D titleBounds = g.getFontMetrics().getStringBounds(product.getTitle(), g);
// 一行最多 10 個字符
final String title = product.getTitle();
final int rowMaxWidth = titleArea.width;
if (titleBounds.getWidth() > rowMaxWidth) {
final char[] chars = product.getTitle().toCharArray();
for (int i = 0, w = 0, start = 0; i < chars.length; i++) {
w += g.getFontMetrics().charWidth(chars[i]);
if (w >= rowMaxWidth) {
if (start == 0) {
// 寫第一行
int y = titleArea.y + ascent;
g.drawString(title.substring(0, i), titleArea.x, y);
start = i;
w = 0;
} else if (start > 0) {
// 寫第二行
String part2 = title.substring(start, i);
// 判斷是否需要追加點點點
if (titleBounds.getWidth() > rowMaxWidth * 2) part2 += "...";
// 繪製
int padding = 5;
int y = titleArea.y + ascent + titleArea.height / 2 + padding;
g.drawString(part2, titleArea.x, y);
break;
}
}
}
} else {
g.drawString(title, titleArea.x, titleArea.y + ascent);

}
}/<code>

繪製產品價格

標題會了價格就很簡單了, 這裡有個遺留問題就是: 如果價格超過4位數會出現超出圖片的問題, 大家可以修改模板或者調整字號來解決

<code>g.setFont(new Font("Arial", Font.BOLD, 48));
final FontMetrics fontMetrics = g.getFontMetrics(g.getFont());
g.setColor(Color.decode("#ff4f13"));
g.drawString(product.getPrice(), priceArea.x, priceArea.y + fontMetrics.getAscent());/<code>

生成二維碼圖片, 刪除白邊

生成二維碼我們需要依賴一個第三方依賴

<code>
<dependency>
<groupid>com.google.zxing/<groupid>
<artifactid>core/<artifactid>
<version>3.3.0/<version>
/<dependency>
<dependency>
<groupid>com.google.zxing/<groupid>
<artifactid>javase/<artifactid>
<version>3.3.0/<version>
/<dependency>/<code>

生成二維碼

<code>// 生成二維碼圖片
QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.encode(product.getProductUrl(), BarcodeFormat.QR_CODE, qrcodeArea.width, qrcodeArea.height);/<code>

刪除白邊

<code>public static BitMatrix deleteWhite(BitMatrix matrix) {
int[] rec = matrix.getEnclosingRectangle();
int resWidth = rec[2] + 1;

int resHeight = rec[3] + 1;
BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
resMatrix.clear();
for (int i = 0; i < resWidth; i++) {
for (int j = 0; j < resHeight; j++) {
if (matrix.get(i + rec[0], j + rec[1]))
resMatrix.set(i, j);
}
}
return resMatrix;
}/<code>

源碼地址:https://gitee.com/qiaohhgz/product-tools.git


分享到:


相關文章: