前言

本文介绍了java为pdf, word, excel, ppt等文档添加水印的方法, 详见官方文档


目录

  • 前言
  • 正文
    • 效果图
    • maven依赖
    • java代码
  • 总结

正文

效果图

pdf

word

注意: wps显示异常, 详见代码注释

ppt


maven依赖

e-iceblue.office仓库

可以直接将jar推送到私服无需引入此仓库

<!-- office水印仓库 -->
<repository><id>com.e-iceblue</id><url>https://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>

maven依赖

<!-- pdf水印 -->
<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.12</version>
</dependency>
<!-- pdf中文水印支持 -->
<dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version>
</dependency>
<!-- office水印依赖包 -->
<dependency><groupId>e-iceblue</groupId><artifactId>spire.office.free</artifactId><version>5.3.1</version>
</dependency>

java代码

main函数里有测试用例


import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.HeaderFooter;
import com.spire.doc.Section;
import com.spire.doc.documents.Paragraph;
import com.spire.doc.documents.ShapeLineStyle;
import com.spire.doc.fields.ShapeObject;
import com.spire.pdf.PdfDocument;
import com.spire.pdf.graphics.*;
import com.spire.pdf.widget.PdfPageCollection;
import com.spire.presentation.*;
import com.spire.presentation.collections.SlideCollection;
import com.spire.presentation.drawing.FillFormatType;
import com.spire.xls.ViewMode;
import com.spire.xls.Workbook;
import com.spire.xls.Worksheet;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import sun.font.FontDesignMetrics;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;/*** 水印工具类** @author LSL* @date 2022-07-28 22:54:52*/
@Slf4j
public class WatermarkUtil {/*** 水印相关配置*/private static final int FONT_SIZE = 12;private static final Font FONT = new Font("宋体", Font.PLAIN, FONT_SIZE);private static final Color FONT_COLOR = new Color(200, 200, 200);private static final float TEXT_ROTATION = 30;/*** 文件类型*/interface FileType {String PDF = "pdf";String DOC = "doc";String DOCX = "docx";String XLS = "xls";String XLSX = "xlsx";String PPT = "ppt";String PPTX = "pptx";String JPG = "jpg";String JPEG = "jpeg";String PNG = "png";String BMP = "bmp";}/*** word格式映射*/private static final Map<String, FileFormat> FILE_FORMAT_WORD_MAP = new HashMap<>();/*** ppt格式映射*/private static final Map<String, com.spire.presentation.FileFormat> FILE_FORMAT_PPT_MAP = new HashMap<>();static {FILE_FORMAT_WORD_MAP.put(FileType.DOC, FileFormat.Doc);FILE_FORMAT_WORD_MAP.put(FileType.DOCX, FileFormat.Docx_2013);FILE_FORMAT_PPT_MAP.put(FileType.PPT, com.spire.presentation.FileFormat.PPT);FILE_FORMAT_PPT_MAP.put(FileType.PPTX, com.spire.presentation.FileFormat.PPTX_2013);}/*** 添加水印** @param inputStream  文件输入流* @param outputStream 输出流* @param fileType     文件类型* @param watermark    水印*/public static boolean watermark(InputStream inputStream, OutputStream outputStream, String fileType, String watermark) {try {switch (fileType) {// officecase FileType.PDF:WatermarkUtil.pdf(inputStream, outputStream, fileType, watermark);break;case FileType.DOC:case FileType.DOCX:WatermarkUtil.word(inputStream, outputStream, fileType, watermark);break;case FileType.XLS:case FileType.XLSX:WatermarkUtil.excel(inputStream, outputStream, fileType, watermark);break;case FileType.PPT:case FileType.PPTX:WatermarkUtil.ppt(inputStream, outputStream, fileType, watermark);break;// 图片case FileType.JPG:case FileType.JPEG:case FileType.PNG:case FileType.BMP:WatermarkUtil.picture(inputStream, outputStream, fileType, watermark);break;// 其他default:WatermarkUtil.other(inputStream, outputStream, fileType, watermark);break;}} catch (Exception e) {log.error(fileType + "水印添加失败", e);return false;} finally {// 释放资源try {if (outputStream != null) {outputStream.close();}} catch (Exception e) {e.printStackTrace();}try {if (inputStream != null) {inputStream.close();}} catch (Exception e) {e.printStackTrace();}}return true;}/*** pdf添加水印** @param inputStream  文件输入流* @param outputStream 输出流* @param fileType     文件类型* @param watermark    水印*/public static void pdf(InputStream inputStream, OutputStream outputStream, String fileType, String watermark) {pdfByItextpdf(inputStream, outputStream, fileType, watermark);
//        pdfBySpire(inputStream, outputStream, fileType, watermark);}/*** pdf添加水印 itextpdf** @param inputStream  文件输入流* @param outputStream 输出流* @param fileType     文件类型* @param watermark    水印*/@SneakyThrowsprivate static void pdfByItextpdf(InputStream inputStream, OutputStream outputStream, String fileType, String watermark) {PdfReader reader = null;PdfStamper stamper = null;try {// 水印配置final float fontSize = FONT_SIZE;final BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);final BaseColor fontColor = new BaseColor(200, 200, 200);final float rotation = TEXT_ROTATION;// 输入long startLoad = System.currentTimeMillis();reader = new PdfReader(inputStream);log.debug("耗时load: {}", System.currentTimeMillis() - startLoad);stamper = new PdfStamper(reader, outputStream);// 准备int total = reader.getNumberOfPages() + 1;double rotationRotation = Math.toRadians(rotation);final float textWidth = (float) (font.getWidthPoint(watermark, fontSize) * Math.cos(rotationRotation));final float textHeight = (float) (textWidth * Math.tan(rotationRotation));PdfContentByte content;// 遍历页面for (int i = 1; i < total; i++) {content = stamper.getOverContent(i);content.beginText();content.setColorFill(fontColor);content.setFontAndSize(font, fontSize);com.itextpdf.text.Rectangle rectangle = reader.getPageSize(i);final float width = rectangle.getWidth();final float height = rectangle.getHeight();final float widthMargin = 20;final float heightMargin = 40;final float widthGap = (width - textWidth * 3 - widthMargin * 2) / 2;final float heightGap = (height - textHeight * 4 - heightMargin * 2) / 3;for (int j = 0; j < 4; j++) {for (int k = 0; k < 3; k++) {content.showTextAligned(Element.ALIGN_LEFT, watermark, widthMargin + (widthGap + textWidth) * k, heightMargin + (heightGap + textHeight) * j, rotation);}}content.endText();}} catch (Exception e) {throw e;} finally {// 释放资源try {if (stamper != null) {stamper.close();}} catch (Exception e) {e.printStackTrace();}try {if (reader != null) {reader.close();}} catch (Exception e) {e.printStackTrace();}}}/*** pdf添加水印 spire** @param inputStream  文件输入流* @param outputStream 输出流* @param fileType     文件类型* @param watermark    水印*/@Deprecatedprivate static void pdfBySpire(InputStream inputStream, OutputStream outputStream, String fileType, String watermark) {// 水印配置final Font font = FONT;final float rotation = TEXT_ROTATION;long startNewFont = System.currentTimeMillis();PdfTrueTypeFont trueTypeFont = new PdfTrueTypeFont(font);log.debug("耗时newFont: {}", System.currentTimeMillis() - startNewFont);long startNew = System.currentTimeMillis();PdfDocument pdf = new PdfDocument();log.debug("耗时new: {}", System.currentTimeMillis() - startNew);try {// 输入long startLoad = System.currentTimeMillis();pdf.loadFromStream(inputStream);log.debug("耗时load: {}", System.currentTimeMillis() - startLoad);// 遍历页面PdfPageCollection pages = pdf.getPages();for (int i = 0, len = pages.getCount(); i < len; i++) {PdfCanvas canvas = pages.get(i).getCanvas();Dimension2D dimension2D = new Dimension();dimension2D.setSize(canvas.getClientSize().getWidth() / 2, canvas.getClientSize().getHeight() / 3);PdfTilingBrush brush = new PdfTilingBrush(dimension2D);PdfCanvas graphics = brush.getGraphics();graphics.setTransparency(0.3F);graphics.save();graphics.translateTransform((float) brush.getSize().getWidth() / 2, (float) brush.getSize().getHeight() / 2);graphics.rotateTransform(-rotation);graphics.drawString(watermark, trueTypeFont, PdfBrushes.getViolet(), 0, 0, new PdfStringFormat(PdfTextAlignment.Center));graphics.restore();graphics.setTransparency(1);Rectangle2D loRect = new Rectangle2D.Float();loRect.setFrame(new Point2D.Float(0, 0), canvas.getClientSize());canvas.drawRectangle(brush, loRect);}// 输出long startSave = System.currentTimeMillis();pdf.saveToStream(outputStream);log.debug("耗时save: {}", System.currentTimeMillis() - startSave);} catch (Exception e) {throw e;} finally {if (null != pdf) {pdf.dispose();}}}/*** word添加水印** @param inputStream  文件输入流* @param outputStream 输出流* @param fileType     文件类型* @param watermark    水印*/public static void word(InputStream inputStream, OutputStream outputStream, String fileType, String watermark) {// 注意: wps doc显示异常, docx电脑端异常但手机端显示正常// 水印配置final Color fontColor = FONT_COLOR;final float rotation = TEXT_ROTATION;long startNew = System.currentTimeMillis();Document doc = new Document();log.debug("耗时new: {}", System.currentTimeMillis() - startNew);try {// 输入long startLoad = System.currentTimeMillis();FileFormat fileFormat = FILE_FORMAT_WORD_MAP.get(fileType);doc.loadFromStream(inputStream, fileFormat);log.debug("耗时load: {}", System.currentTimeMillis() - startLoad);// 该类型水印wps正常显示
//            TextWatermark txtWatermark = new TextWatermark();
//            txtWatermark.setText(watermark);
//            txtWatermark.setFontSize(18);
//            txtWatermark.setColor(fontColor);
//            txtWatermark.setLayout(WatermarkLayout.Diagonal);
//            doc.getSections().get(0).getDocument().setWatermark(txtWatermark);// 添加并设置艺术字文本内容和样式ShapeObject shape = new ShapeObject(doc, com.spire.doc.documents.ShapeType.Text_Plain_Text);final int widthMargin = 20;final int heightMargin = 50;final int weightGap = 160;final int heightGap = 150;shape.setWidth(100);shape.setHeight(20);shape.setRotation(-rotation);shape.getWordArt().setText(watermark);shape.setFillColor(fontColor);shape.setLineStyle(ShapeLineStyle.Single);shape.setStrokeColor(fontColor);shape.setStrokeWeight(1);Section section;HeaderFooter header;// 遍历页面for (int n = 0; n < doc.getSections().getCount(); n++) {section = doc.getSections().get(n);header = section.getHeadersFooters().getHeader();Paragraph paragraph1;for (int i = 0; i < 4; i++) {paragraph1 = header.addParagraph();for (int j = 0; j < 3; j++) {// 设置水印shape = (ShapeObject) shape.deepClone();shape.setVerticalPosition(heightMargin + heightGap * i);shape.setHorizontalPosition(widthMargin + weightGap * j);paragraph1.getChildObjects().add(shape);}}}// 输出doc.saveToStream(outputStream, fileFormat);} catch (Exception e) {throw e;} finally {if (null != doc) {doc.dispose();}}}/*** excel添加水印** @param inputStream  文件输入流* @param outputStream 输出流* @param fileType     文件类型* @param watermark    水印*/public static void excel(InputStream inputStream, OutputStream outputStream, String fileType, String watermark) {// 水印配置final Font font = FONT;final Color fontColor = FONT_COLOR;final float rotation = TEXT_ROTATION;long startNewLoad = System.currentTimeMillis();Workbook workbook = new Workbook();try {// 输入workbook.loadFromStream(inputStream);log.debug("耗时newLoad: {}", System.currentTimeMillis() - startNewLoad);// 遍历页面for (int i = 0; i < workbook.getWorksheets().getCount(); i++) {Worksheet sheet = workbook.getWorksheets().get(i);com.spire.xls.PageSetup pageSetup = sheet.getPageSetup();// 绘制水印并设置BufferedImage img = drawImage(font, fontColor, watermark, rotation, (int) pageSetup.getPageHeight(), (int) pageSetup.getPageWidth());pageSetup.setCenterHeaderImage(img);pageSetup.setCenterHeader("&G");sheet.setViewMode(ViewMode.Layout);}// 输出workbook.saveToStream(outputStream);} catch (Exception e) {throw e;} finally {if (null != workbook) {workbook.dispose();}}}/*** 绘图** @param watermark 水印* @param font      字体* @param fontColor 文字颜色* @param rotation  旋转角度* @param height    高度* @param width     宽度*/private static BufferedImage drawImage(Font font, Color fontColor, String watermark, float rotation, int height, int width) {// 画板BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);// 画笔Graphics2D loGraphic = img.createGraphics();try {// 画笔设置FontMetrics loFontMetrics = loGraphic.getFontMetrics(font);int textWidth = loFontMetrics.stringWidth(watermark);int textHeight = loFontMetrics.getHeight();loGraphic.fillRect(0, 0, width, height);loGraphic.translate((width - textWidth) / 2, (height - textHeight) / 2);loGraphic.rotate(Math.toRadians(-rotation));loGraphic.translate(-(width - textWidth) / 2, -(height - textHeight) / 2);loGraphic.setFont(font);loGraphic.setColor(fontColor);// 绘制final int weightMargin = -80;final int weightGap = Math.abs(width - weightMargin * 2 - textWidth * 3) / 2;final int heightMargin = 100;final int heightGap = (height - heightMargin * 2) / 3;for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {loGraphic.drawString(watermark, weightMargin + (weightGap + textWidth) * j, heightMargin + (heightGap + textHeight) * i);}}} catch (Exception e) {throw e;} finally {if (null != loGraphic) {loGraphic.dispose();}}return img;}/*** ppt添加水印** @param inputStream  文件输入流* @param outputStream 输出流* @param fileType     文件类型* @param watermark    水印*/@SneakyThrowspublic static void ppt(InputStream inputStream, OutputStream outputStream, String fileType, String watermark) {// 水印配置final float fontSize = FONT_SIZE;final Color fontColor = FONT_COLOR;final float rotation = TEXT_ROTATION;long startNewLoad = System.currentTimeMillis();Presentation ppt = new Presentation();try {// 输入com.spire.presentation.FileFormat fileFormat = FILE_FORMAT_PPT_MAP.get(fileType);ppt.loadFromStream(inputStream, fileFormat);log.debug("耗时newLoad: {}", System.currentTimeMillis() - startNewLoad);// 坐标大小Dimension2D pageSize = ppt.getSlideSize().getSize();final int textWidth = 160;final int textHeight = 80;final int widthMargin = 0;final int heightMargin = 10;final int weightGap = (int) pageSize.getWidth() / 6;final int heightGap = (int) pageSize.getHeight() / 8;// 遍历页面SlideCollection slides = ppt.getSlides();for (int k = 0, len = slides.size(); k < len; k++) {float x = widthMargin;float y = heightMargin;ISlide slide = slides.get(k);// 绘制for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {Rectangle2D.Double rect = new Rectangle2D.Double(x, y, textWidth, textHeight);IAutoShape shape = slide.getShapes().appendShape(ShapeType.RECTANGLE, rect);shape.getFill().setFillType(FillFormatType.NONE);shape.getShapeStyle().getLineColor().setColor(Color.white);shape.setRotation(-rotation);shape.getLocking().setSelectionProtection(true);shape.getLine().setFillType(FillFormatType.NONE);shape.getTextFrame().setText(watermark);shape.setShapeArrange(ShapeAlignmentEnum.ShapeArrange.SendToBack);PortionEx textRange = shape.getTextFrame().getTextRange();textRange.getFill().setFillType(FillFormatType.SOLID);textRange.getFill().getSolidColor().setColor(fontColor);textRange.setFontHeight(fontSize);x += (textWidth + weightGap);}x = widthMargin;y += (textHeight + heightGap);}}// 输出long startSave = System.currentTimeMillis();ppt.saveToFile(outputStream, fileFormat);log.debug("耗时save: {}", System.currentTimeMillis() - startSave);} catch (Exception e) {throw e;} finally {if (null != ppt) {ppt.dispose();}}}/*** 图片添加水印** @param inputStream  文件输入流* @param outputStream 输出流* @param fileType     文件类型* @param watermark    水印*/@SneakyThrowspublic static void picture(InputStream inputStream, OutputStream outputStream, String fileType, String watermark) {// 水印配置final Font font = FONT;final Color fontColor = FONT_COLOR;final float alpha = 0.5f;final float rotation = TEXT_ROTATION;BufferedImage bufferedImage = null;Graphics2D g = null;try {// 输入BufferedImage srcImage = ImageIO.read(inputStream);// 画板int width = srcImage.getWidth();int height = srcImage.getHeight();bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 画笔g = bufferedImage.createGraphics();g.drawImage(srcImage, 0, 0, width, height, null);g.setFont(font);g.setColor(fontColor);g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); // 透明度// 坐标大小FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);int textWidth = metrics.stringWidth(watermark);int textHeight = metrics.getHeight();final int weightMargin = -40;final int weightGap = 50;final int heightMargin = 80;final int heightGap = 100;int colums = (int) Math.round(width * 1.0 / (weightGap + textWidth));int rows = (int) Math.round(height * 1.0 / heightGap);// 旋转坐标轴g.translate((width - textWidth) / 2, (height - textHeight) / 2);g.rotate(Math.toRadians(-rotation));g.translate(-(width - textWidth) / 2, -(height - textHeight) / 2);// 绘制for (int i = 0; i < rows; i++) {for (int j = 0; j < colums; j++) {g.drawString(watermark, weightMargin + (weightGap + textWidth) * j, heightMargin + (heightGap + textHeight) * i);}}// 输出ImageIO.write(bufferedImage, fileType, outputStream);} catch (Exception e) {throw e;} finally {if (null != g) {g.dispose();}}}/*** 其他** @param inputStream  文件输入流* @param outputStream 输出流* @param fileType     文件类型* @param watermark    水印*/@SneakyThrowspublic static void other(InputStream inputStream, OutputStream outputStream, String fileType, String watermark) {log.info("{}水印无法添加", fileType);IOUtils.copy(inputStream, outputStream);}@SneakyThrowspublic static void main(String[] args) {// 参数InputStream inputStream = null;OutputStream outputStream = null;String fileType = null;String watermark = null;// *********************** 测试 S **************************** // TODOString path = "E:/test/watermark/";String fileName = "shuiyin";fileType = "ppt";watermark = "测试水印-" + fileType;inputStream = new FileInputStream(path + fileName + "." + fileType);outputStream = new FileOutputStream(path + fileName + "Output." + fileType);// *********************** 测试 E **************************** //// 添加水印log.info("水印添加: {}.{}", fileName, fileType);long startAll = System.currentTimeMillis();watermark(inputStream, outputStream, fileType, watermark);log.debug("耗时all: {}", System.currentTimeMillis() - startAll);}}

总结

暂时木有

pdf和word等文档添加水印相关推荐

  1. 手机版PDF编辑器支持PDF转Word、文档内容编辑合并与提取

    PDF文档作为使用十分普遍的办公文档,其内容展示精美.设备兼容性好的特性十分受到用户们的喜爱.不过也有令人头疼的部分,修改PDF内容不易,需要专用的PDF编辑器,当然你也可以选择将PDF转成Word后 ...

  2. C# 给word文档添加水印

    C# 给word文档添加水印 和PDF一样,在word中,水印也分为图片水印和文本水印,给文档添加图片水印可以使文档变得更为美观,更具有吸引力.文本水印则可以保护文档,提醒别人该文档是受版权保护的,不 ...

  3. word+增加水印+java_为Word2019文档添加水印的两种方法

    水印的类型包括文字水印和图片水印两种.在Word文档中添加文字水印时,可以使用程序中预设的水印效果,而图片水印则需要自定义添加. 一.使用程序预设的文字水印 Word 2019中预设了机密.紧急.免责 ...

  4. C# Word文档添加水印

    在工作中遇到个需求,需要给Word文档添加水印搞了一天才搞出来,所以在此记录一下: 重点用到了E-iceblue官网下载到的:Spire.dll using Spire.Doc; using Spir ...

  5. 如何用java代码给Word文档添加水印?

    为防止非法使用.定义所有权.显示文档状态等多种目的,在 Word 文档中添加水印.在本文中,您将学习如何使用 Java 为 Word 文档添加水印.文章将分别演示如何将文字和图片水印插入到Word文档 ...

  6. Word处理控件Aspose.Words功能演示:使用 Java 为 Word 文档添加水印

    为防止非法使用.定义所有权.显示文档状态等多种目的,在 Word 文档中添加水印.在本文中,您将学习如何使用 Java 为 Word 文档添加水印.文章将分别演示如何将文字和图片水印插入到Word文档 ...

  7. Java操作Word文档添加水印(文字/图片)

    水印是一种常用于各种文档的声明.防伪手段,一般可设置文字水印或者加载图片作为水印.以下内容将分享通过Java编程给Word文档添加水印效果的方法. 使用工具:Free Spire.Doc for Ja ...

  8. 如何在Word 2013中向文档添加水印

    A watermark is a faded, background image that displays behind the text in a document. It can be used ...

  9. 给pdf、word、excel文件添加水印

    今天公司让给pdf.word.excel文件添加水印, 在网上导了一堆,最后总结了一下方法. /**  * @author CArom_XUE    2021-03-18  *  * TODO 生成文 ...

最新文章

  1. python opencv 图像旋转
  2. kvm cobbler无人值守批量安装操作系统
  3. shell编程之简单四则运算及数组定义
  4. NumPy之:ndarray中的函数
  5. linux每天一小步---sed命令详解
  6. vue 中 created 和 mounted 钩子生命周期 问题
  7. 枚举、位操作 CLR学习第十二课
  8. IDC分析报告:亚洲安全软件市场兴旺
  9. 不能定义声明dllimport_不允许 dllimport 函数 的定义 高手帮帮忙
  10. GitHub Desktop理解与入门
  11. 讲座笔记:图匹配 Graph Matching 问题 | 机器学习组合优化
  12. tsp的理论和实践(10)tsp系列暂停一下
  13. 遗传算法GA原理详解及实例应用 附Python代码
  14. Excel连接数据库
  15. 【渝粤题库】陕西师范大学210033 劳动法与社会保障法作业
  16. NLP文本相似度(TF-IDF)
  17. RAC环境备份归档日志和RMAN恢复启动数据库
  18. jbpm3\jbpm4_在jBPM中支持高级用户交互模式
  19. 程序中中文乱码问题的总结
  20. VSCODE(三)用户界面

热门文章

  1. java 僵尸进程_神奇的Java僵尸(defunct)进程问题排查过程
  2. MATLAB 2018a安装教程(迅雷)
  3. 某cpws - ciphertext加密与数据解密
  4. 研发人员为什么留不住:问题与现象、原因的解析
  5. python+matplotlib绘制南丁格尔玫瑰图
  6. 计算机会议论文EI检索,ei检索会议论文算期刊_ei论文检索_ei会议论文算核心吗...
  7. 2019年厦门国际银行“数创金融杯”数据建模大赛总结
  8. 深入研究绘图——图像和图像视图
  9. H5营销海报如何制作,在线制作平台分享
  10. Mac下cmake使用