Aslongasyoucanstillgrababreath,youfight.只要一息尚存,就不得不战。
第一步,获取网络图片的路径。金山词霸每日一句的图片路径地址形式如下所示。可以根据当前日期获取最新的图片路径。
HttpEntityentity=response.getEntity();InputStreampicStream=entity.getContent();第五步,从图片输入流中读取信息,并输出到本地文件中。
Filepic=Files.createTempFile(Paths.get("D:\\test"),"pic_",".jpg");FileOutputStreamfos=newFileOutputStream(pic);intread=0;//1024Byte(字节)=1KB1024KB=1MBbyte[]bytes=newbyte[1024*100];while((read=inputStream.read(bytes))!=-1){fos.write(bytes,0,read);}fos.flush();fos.close();在指定的临时目录下可以查看采集到的图片,如下所示。
海报背景的大小为678*1013像素,个人品牌二维码的大小为128*128像素。两张图片都是事先准备好的,放在src目录下。整个项目的目录结构图如下所示。
接下来,我们把这两张图片分别读取到临时文件当中,供后续动作使用。
第一步,创建ClassLoader对象,从classpath的根路径下查找资源。
ClassLoaderclassLoader=ReadBgAndQrcode.class.getClassLoader();第二步,通过classLoader.getResourceAsStream()读取海报背景和个人品牌二维码,复制到临时文件中。
FilebgFile=Files.createTempFile(DIRECTORY,"bg_",".jpg").toFile();InputStreaminputStream=classLoader.getResourceAsStream("default_bgimg.jpg");FileUtils.copyInputStreamToFile(inputStream,bgFile);logger.debug("背景:"+bgFile.getAbsolutePath());FileqrcodeFile=Files.createTempFile(DIRECTORY,"qrcode_",".jpg").toFile();InputStreamqrcodeInputStream=classLoader.getResourceAsStream("default_qrcodeimg.jpg");FileUtils.copyInputStreamToFile(qrcodeInputStream,qrcodeFile);logger.debug("二维码:"+qrcodeFile.getAbsolutePath());在指定的临时目录下可以查看海报背景和个人品牌二维码,如下所示。
Graphics2D类扩展了Graphics类,提供了对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制,是用于呈现二维形状、文本和图像的基础类。
BufferedImage使用可访问的图像数据缓冲区描述图像,由颜色模型和图像数据栅格组成,所有BufferedImage对象的左上角坐标为(0,0)。
可以利用BufferedImage类的createGraphics()方法获取Graphics2D对象。
第一步,将海报背景和海报封面读入到BufferedImage对象中。注意,deleteOnExit()方法请求在虚拟机终止时删除此抽象路径名所表示的文件或目录。
//背景FilebgFile=FileUtil.read("bg_",".jpg","default_bgimg.jpg");bgFile.deleteOnExit();BufferedImagebgImage=ImageIO.read(bgFile);//封面图FilepicFile=CapturePic.capture();picFile.deleteOnExit();BufferedImagepicImage=ImageIO.read(picFile);第二步,计算封面图的起始坐标,以及高度和宽度。
//封面图的起始坐标intpic_x=MARGIN,pic_y=MARGIN;//封面图的宽度intpic_width=bgImage.getWidth()-MARGIN*2;//封面图的高度intpic_height=picImage.getHeight()*pic_width/picImage.getWidth();第三步,在海报背景上绘制封面图。
Graphics2Dgraphics2d=bgImage.createGraphics();//在背景上绘制封面图graphics2d.drawImage(picImage,pic_x,pic_y,pic_width,pic_height,null);//释放图形上下文,以及它正在使用的任何系统资源。graphics2d.dispose();第四步,将绘制好的图像输出到文件中。
FileposterFile=Files.createTempFile(FileUtil.DIRECTORY,"poster_",".jpg").toFile();ImageIO.write(bgImage,"jpg",posterFile);在指定的临时目录下可以查看海报,如下所示。
Font类表示字体,用于以可见的方式呈现文本。字体提供了将字符序列映射到象形文字序列以及在图形和组件对象上呈现象形文字序列所需的信息。
第一步,通过GraphicsEnvironment类的getAvailableFontFamilyNames()查看计算机上允许使用的字体。
String[]fontNames=GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();for(StringfontName:fontNames){System.out.println(fontName);}大致的中文字体有这么一些(还有更多,未列出):
宋体幼圆微软雅黑微软雅黑Light新宋体方正姚体方正舒体楷体隶书黑体
第二步,设置字体和颜色。
//Font的构造参数依次是字体名字,字体式样,字体大小Fontfont=newFont("微软雅黑",Font.PLAIN,28);g.setFont(font);//RGBg.setColor(newColor(71,71,71));第三步,根据当前字体下每个中文字符的宽度,以及海报可容纳的最大文本宽度,对文本进行换行。
计算每个字体的宽度时,需要用到sun.font.FontDesignMetrics,它扩展了java.awt.FontMetrics。FentMetrics类定义了一个字体度量对象,该对象封装了有关在特定屏幕上呈现特定字体的信息。FontDesignMetrics提供了更多指标的Font信息。
FontDesignMetrics有几个重要的值需要说明一下:
FontDesignMetrics的charWidth()方法可以计算字符的宽度。
publicstaticStringmakeLineFeed(Stringzh,FontDesignMetricsmetrics,intmax_width){StringBuildersb=newStringBuilder();intline_width=0;for(inti=0;i
Fontfont=newFont("微软雅黑",Font.PLAIN,28);FontDesignMetricsmetrics=FontDesignMetrics.getMetrics(font);Stringzh="沉默王二,《Web全栈开发进阶之路》作者;一个不止写代码的程序员,还写有趣有益的文字,给不喜欢严肃的你。";String[]rows=makeLineFeed(zh,metrics,600).split("\n");for(inti=0;i 沉默王二,《Web全栈开发进阶之路》作者;一个不止写代码的程序员,还写有趣有益的文字,给不喜欢严肃的你。 第四步,将自动换行后的文本在海报背景上打印。 这里需要用到FontDesignMetrics的getHeight()方法获取每行文本的高度。对照下面的示意图,理解height的具体高度。 //自动换行后的文本StringzhWrap=FontUtil.makeLineFeed(graphics2dPoster.getZh(),metrics,graphics2dPoster.getSuitableWidth());//拆分行String[]zhWraps=zhWrap.split("\n");//将每一行在海报背景上打印for(inti=0;i 可以看得出,文字带有很强的锯齿感,怎么消除呢? graphics2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);如果英语不好的话,看起来这段代码会很吃力。ANTIALIASING单词的意思就是“消除混叠现象,消除走样,图形保真”。 英文和中文最大的不同在于,换行的单位不再是单个字符,而是整个单词。 第一步,根据当前字体下每个英文单词的宽度,以及海报可容纳的最大文本宽度,对文本进行换行。 publicstaticStringmakeEnLineFeed(Stringen,FontDesignMetricsmetrics,intmax_width){//每个单词后追加空格charspace='';intspaceWidth=metrics.charWidth(space);//按照空格对英文文本进行拆分String[]words=en.split(String.valueOf(space));//利用StringBuilder对字符串进行修改StringBuildersb=newStringBuilder();//每行文本的宽度intlen=0;for(inti=0;i Fontfont=newFont("微软雅黑",Font.PLAIN,28);FontDesignMetricsmetrics=FontDesignMetrics.getMetrics(font);Stringen="Fearcanholdyouprisoner.Hopecansetyoufree.Ittakesastrongmantosavehimself,andagreatmantosaveanother.";String[]rows=makeEnLineFeed(en,metrics,600).split("\n");for(inti=0;i Fearcanholdyouprisoner.Hopecansetyoufree.Ittakesastrongmantosavehimself,andagreatmantosaveanother. 第三步,将自动换行后的文本在海报背景上打印。 //设置封面图和下方中文之间的距离graphics2dPoster.addCurrentY(20);Graphics2Dgraphics2d=graphics2dPoster.getGraphics2d();graphics2d.setColor(newColor(157,157,157));FontDesignMetricsmetrics=FontDesignMetrics.getMetrics(graphics2d.getFont());StringenWrap=FontUtil.makeEnLineFeed(graphics2dPoster.getEn(),metrics,graphics2dPoster.getSuitableWidth());String[]enWraps=enWrap.split("\n");for(inti=0;i 有了前面绘制海报封面的经验,绘制二维码就变得轻而易举了。 //二维码FileqrcodeFile=FileUtil.read("qrcode_",".jpg","default_qrcodeimg.jpg");qrcodeFile.deleteOnExit();BufferedImageqrcodeImage=ImageIO.read(qrcodeFile);//二维码起始坐标intqrcode_x=bgImage.getWidth()-qrcodeImage.getWidth()-MARGIN;intqrcode_y=bgImage.getHeight()-qrcodeImage.getHeight()-MARGIN;graphics2dPoster.getGraphics2d().drawImage(qrcodeImage,qrcode_x,qrcode_y,qrcodeImage.getWidth(),qrcodeImage.getHeight(),null);此时的海报效果如下图所示。 是不是感觉海报的左下角比较空白,整体的对称性不够自然,那就在左下角追加一些二维码的描述文本吧。 graphics2d.setColor(newColor(71,71,71));Fontfont=newFont(USE_FONT_NAME,Font.PLAIN,22);graphics2d.setFont(font);FontDesignMetricsmetrics=FontDesignMetrics.getMetrics(graphics2d.getFont());graphics2d.drawString("沉默王二",MARGIN,bgImage.getHeight()-MARGIN-metrics.getHeight()*2);graphics2d.drawString("一个幽默的程序员",MARGIN,bgImage.getHeight()-MARGIN-metrics.getDescent());此时的海报效果如下图所示。 Swing是一个用于JavaGUI编程(图形界面设计)的工具包(类库);换句话说,Java之所以可以用来开发带界面的PC软件,就是因为Swing的存在。 Swing使用纯粹的Java代码来模拟各种控件,没有使用本地操作系统的内在方法,所以Swing是跨平台的。也正是因为Swing的这种特性,人们通常把Swing控件称为轻量级控件。 Eclipse默认是不支持可视化的Swing编程的,但Eclipse的插件市场上有这样一个好插件——WindowBuilder,使用它可以大幅度地降低开发难度,迅速地提升开发效率。 可直接拖拽到Eclipse进行安装,如下图。 注意,Eclipse的版本要求为: 2018-09(4.9),Photon(4.8),Oxygen(4.7),Neon(4.6),2018-12(4.10),2019-03(4.11) 拖拽到Eclipse后的效果如下: 安装完成后,会提醒你重启Eclipse。 安装成功后,就可以使用可视化工具设计界面了,如下图所示: 在将应用程序进行打包时,使用者都希望开发者只提供一个单独的文件,而不是包含大量源码的文件夹。jar包存在的目的正源于此。 将项目打成jar包也很简单,在Eclipse中,可依次右键项目→Export→RunnableJARfile。你将会看到以下界面。 选择main方法所在类,指定导出目标,选择Copyrequiredlibraries选项,点击「Finish」即可。在指定的目录下可找到生成的jar包文件。 如果电脑上安装了Java的运行环境,双击该jar包文件就可以运行。运行后的界面,如下图所示。可以填写中文、英文、海报封面路径,然后点击按钮生成海报。 PS:为了便于大家的学习,我已经将源码放在了GitHub上,地址如下。