用Java实现仿x宝产品卡片制作教程,附源码

浅殇忆流年 2020-03-20 14:23:13 ⋅ 656 阅读

先看下效果图




实现思路


  • PS 扣一个底层的模板图片

  • 读取底层模板图片

  • 绘制产品主图, 图片加圆角处理, 图片抗锯齿处理

  • 绘制产品标题, 计算内容宽度并换行, 文字坐标计算, 字体抗锯齿处理

  • 绘制产品价格

  • 生成二维码图片, 二维码白边处理


PS 扣一个底层的模板图片


这个环节我们主要用PS抠图并记录下每个元素的坐标和大小


/** * 产品图片区域 */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);

读取底层模板图片

// 读取模版图片final BufferedImage cardImg = ImageIO.read(ClassLoader.getSystemResource(templatePath));final Graphics2D g = cardImg.createGraphics();

绘制产品主图,加圆角,抗锯齿


// 绘制封面BufferedImage productImg = ImageIO.read(product.getProductImageUrl());// 切圆角productImg = setRadius(productImg, 60);// 绘制g.drawImage(productImg, imageArea.x, imageArea.y, imageArea.width, imageArea.height, null);
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;}


绘制产品标题,换行,坐标计算,抗锯齿

在使用drawString 绘制文本内容的时候如果, 你需要填写坐标 x, y  如果你直接把ps上面的坐标用在代码里面的话你会发现位置根本就不对, 那是为什么呢?



字体的高由个元素组成:ascent , descent


drawString中用的y坐标是指baseline的y坐标,即字体所在矩形的左上角y坐标+ascent


// 开启文本抗锯齿g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
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); }}

绘制产品价格

标题会了价格就很简单了, 这里有个遗留问题就是:如果价格超过4位数会出现超出图片的问题, 大家可以修改模板或者调整字号来解决

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());

生成二维码图片, 删除白边

生成二维码我们需要依赖一个第三方依赖

<!-- qrcode --><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>

生成二维码

// 生成二维码图片QRCodeWriter qrCodeWriter = new QRCodeWriter();BitMatrix bitMatrix = qrCodeWriter.encode(product.getProductUrl(), BarcodeFormat.QR_CODE, qrcodeArea.width, qrcodeArea.height);

删除白边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;}

源码分享

Gitee: https://gitee.com/qiaohhgz/product-tools.git



全部评论: 0

    我有话说:

    纯HTML实现优惠券、商品列表和活动悬浮等布局(文末有

    最近温习一下HTML5+CSS3的一些特性,准备找个高仿的目标,最后选择了某粉丝福利页面

    SpringBoot+zk+dubbo架构实践(四):sb+zk+dubbo框架搭建(内GitHub地址)

    本篇案例模拟了一个provider服务提供方和PC、Web两个服务消费方内GitHub......

    VUE 开源库收藏版(一):史上最全面的学习资源 ,GitHub地址

    VUE 开源库收藏版(一):史上最全面的学习资源 ,GitHub地址

    「轻阅读」图解 Java 线生命周期

    Java 线生命周期中都包含哪些状态?生命周期中各个状态都是什么含义?

    手把手Spring Cloud + Redis 是实现点赞功能,包包会

    ; 这玩意是怎么实现的呢?我来手把手实现,其...

    仿墨迹天气小程序(袋鼠天气)

    实时天气预报微信小程序

    GitHub竟然有基于SpringCloud的“网约车”项目,

    有人问小编有没有开的“网约车”项目,并且最好是采用微服务架构设计,这样可以投入技术团队进行二次开发。 小编在GitHub上还真找到了这个项目,接下来一起看一看吧! 项目介绍 该项目是一款标准且

    精品推荐:Java核心数据结构(List,Map,Set)使用技巧与优化

    JDK提供了一组主要的数据结构实现,如List、Map、Set等常数据结构。这些数据都继承自 java.util.Collection 接口,并位于 java.util 包内。

    JavaWeb实战篇:视图化了解多线Wait、NotifyAll使用案例

    内容简介本节针对于我们常听说而不常使用的 wait 和 notify 方法做个生产者和消费者案例效果图多线......

    JAVA实现附近范围内公交定位问题

    接上篇【前端实战篇:通过JS抓取城市所有站点与线路】获取附近定位信息

    Google发布Java 核心工具库——Guava 28.0

    Guava是一种基于开Java库,其中包含谷歌正在由他们很多项目使用的很多核心库。这个库是为了方便编码,并减少编码错误。这个库提供用于集合,缓存,支持原语,并发性,常见注解,字符串处理,I/O和

    推荐一款前端数据管理工具 algeb

    方案不是很灵活,无法解决共享数据,数据没回来时怎...

    Java Web实战篇:增强for循环实现原理及for循环实战性能优化

    Iterator是工作在一个独立的线中,并且拥有一个 mutex 锁。 Iterator被创建之后会建立一个指向原来对象的单链索引表......

    可承载10亿级别的高性能微服务 API 网关APIOAK 0.4.0 发布(

    重构了动态负载均衡、路由解析器等内核模块并提供了强大易的控制台管理

    纯JS实现复制功能的三种方式,有踩坑

    业余时间写了一个在WX里面分享X优惠券的小工具,里面有到复制T口令的功能,当时以为实现起来很....

    Java Web实战篇:发布和运维必备的12条Linux命令

    作为一名Java起步的从业人员,学会一些常用的Linux命令是必须的。

    Java Web实战篇-轻松提高千万级数据库查询效率

    通过优化数据库设计、java后台和数据库优化达到提高千万级数据查询的效率。

    微服务架构:搭建网站扫登录的功能设计

    微信扫登录大家都是应用比较多的登录方式了,现在大的购物网站像京东、淘等都支持使用APP扫登录网站了。今天就APP扫登录网站的实例来举例说明微服务架构的搭建过程。