头像生成
实现:
可以参考官方文档:
https://avatars.dicebear.com/docs/http-api
具体api案例:
https://avatars.dicebear.com/api/male/1.svg
https://avatars.dicebear.com/api/avataaars/2.svg
https://avatars.dicebear.com/api/bottts/3.svg
https://avatars.dicebear.com/api/croodles/一.svg
https://avatars.dicebear.com/api/gridy/二.svg
https://avatars.dicebear.com/api/human/三.svg
https://avatars.dicebear.com/api/jdenticon/jeden.svg
当然还可以控制头像的一些属性,比如发型,肤色,鼻子,嘴巴等具体可以参考:https://avatars.dicebear.com/styles/avataaars
具体运用到实战:
首先是需要调这个第三方的api接口,它会返回给你一串字符串,我们拿到字符串,写入文件,注意后缀要以.svg结尾,否则这个图片无法查看。(一般区块链的图片,上链的大多都是svg文件)
然后我们需要将这个图片给前端展示,这里就需要将svg转成jpg(苹果前端和苹果前端也是可以处理的,不过比较麻烦,这里就需要我们处理一下)。
接着将图片转成jpg之后,还需要将它上传到图片存储服务器上,这里我以AWS的S3为例。
最后jpg图片上传成功以后,需要清理之前在服务器上生成的svg和jpg文件。
/** * @Description newsContentPicture为需要生成图片的内容 * @Author zhiwei Liao * @Date 2021/9/14 16:28 **/ @Override public String uploadNewsContentPictureS3(String newsContentPicture) throws Exception{ String osName = System.getProperties().getProperty("os.name"); String svgPath = null; String jpgPath = null; URL url = null; log.info("========操作系统:" + osName); String fileName = String.valueOf(System.currentTimeMillis()); if(osName.contains("Linux")){ svgPath = linuxSvgPath + fileName + ".svg"; jpgPath = linuxJpgPath + fileName + ".jpg"; }else if(osName.contains("Windows")){ svgPath = System.getProperty("user.dir") + "\\svg\\" + fileName + ".svg"; jpgPath = System.getProperty("user.dir") + "\\jpg\\" + fileName + ".jpg"; } //新闻图片内容转svg File svgFile = readIoStringToFile(newsContentPicture, svgPath); if(svgFile != null){ //svg文件转jpg File jpgFile = SVGConverterUtils.svgFileChangeJpg(svgFile, jpgPath); if(jpgFile != null){ //上传jpg图片到s3 AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey); AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withRegion(clientRegion) .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)).build(); PutObjectRequest request = new PutObjectRequest(bucketName, fileName, jpgFile); ObjectMetadata metadata = new ObjectMetadata(); metadata.addUserMetadata("x-amz-meta-title", "someTitle"); request.setMetadata(metadata); request.setKey(fileName); s3Client.putObject(request); url = s3Client.getUrl(bucketName, fileName); if (svgFile.exists()) { svgFile.delete(); } if (jpgFile.exists()) { jpgFile.delete(); } } } return url.toString(); } /** * 把IO字符串输出到文件 * @param ioString * @param filePath */ public static File readIoStringToFile(String ioString, String filePath) { log.info("========readIoStringToFile.filePath:" + filePath); File file = null; FileOutputStream fos = null; try { file = new File(filePath); log.info("========readIoStringToFile.file:" + file); if (file.exists()) { file.delete(); }else { file.getParentFile().mkdir(); file.createNewFile(); } fos = new FileOutputStream(file); fos.write(ioString.getBytes("UTF-8")); fos.flush(); } catch (Exception e) { log.error("readIoStringToFile.Exception异常了:" + e.getMessage()); e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { log.error("readIoStringToFile.IOException异常了:" + e.getMessage()); e.printStackTrace(); } } } return file; }
svg转jpg依赖:
<!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-all --> <dependency> <groupId>org.apache.xmlgraphics</groupId> <artifactId>batik-all</artifactId> <version>1.12</version> <type>pom</type> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/fop --> <dependency> <groupId>org.apache.xmlgraphics</groupId> <artifactId>fop</artifactId> <version>2.4</version> </dependency>
svg转jpg的工具类:
package com.common.entity.utils; import lombok.extern.slf4j.Slf4j; import org.apache.batik.transcoder.*; import org.apache.batik.transcoder.image.JPEGTranscoder; import org.apache.batik.transcoder.image.PNGTranscoder; import org.apache.fop.render.ps.EPSTranscoder; import org.apache.fop.render.ps.PSTranscoder; import org.apache.fop.svg.PDFTranscoder; import java.io.*; /** * @author zhiwei Liao * @version 1.0 * @Description 利用Apache Batik实现 SVG转PDF/PNG/JPG * @Date 2021/9/13 16:26 */ @Slf4j public class SVGConverterUtils { public static void main(String[] args) throws Exception { String svgpath = "E:\\svgfile\\c.svg"; File svgFile = new File(svgpath); String name = svgFile.getName(); name = name.substring(0, name.lastIndexOf(".")); // converter.svg2PDF(new File(svgpath), new File("E:/" + name + "_SVG文件转PDF.pdf")); // converter.svg2PNG(new File(svgpath), new File("E:/" + name + "_SVG文件转PNG.png")); svg2JPEG(new File(svgpath), new File("E:/" + name + "_SVG文件转JPG.jpg")); String svgCode = svg2String(new File(svgpath)); // converter.svg2PDF(svgCode, "D:/" + name + "_SVG代码转PDF.pdf"); // converter.svg2PNG(svgCode, "D:/" + name + "_SVG代码转PNG.png"); // converter.svg2JPEG(svgCode, "D:/" + name + "_SVG代码转JPG.jpg"); // converter.svg2PDF(svgCode, new FileOutputStream(new File("E:/svgfile/" + name + "_SVG代码转输出流.pdf"))); // converter.svg2PNG(svgCode, new FileOutputStream(new File("E:/svgfile/" + name + "_SVG代码转输出流.png"))); // converter.svg2JPEG(svgCode, new FileOutputStream(new File("E:/svgfile/" + name + "_SVG代码转输出流.jpg"))); // converter.svg2EPS(svgCode, new FileOutputStream(new File("E:/svgfile/" + name + "_SVG代码转输出流.eps"))); // converter.svg2PS(svgCode, new FileOutputStream(new File("E:/svgfile/" + name + "_SVG代码转输出流.ps"))); svgtoeps(svgCode, new FileOutputStream(new File("E:/svgfile/" + name + "_SVG代码转输出流.eps"))); } public static File svgFileChangeJpg(File svgFile, String jpgPath){ log.info("========svgFileChangeJpg.jpgPath:" + jpgPath); try { File file = new File(jpgPath); if (file.exists()) { file.delete(); }else { file.getParentFile().mkdir(); file.createNewFile(); } log.info("========svgFileChangeJpg.jpgFile:" + file); log.info("========svgFileChangeJpg.svgFile:" + svgFile); svg2JPEG(svgFile, file); return file; } catch (Exception e) { log.error(e.getMessage()); } return null; } public static void svgtoeps(String svgCode, OutputStream os){ EPSTranscoder epsTranscoder = new EPSTranscoder(); try { svgCode = svgCode.replaceAll(":rect", "rect"); TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(svgCode.getBytes())); TranscoderOutput output = new TranscoderOutput(os); epsTranscoder.transcode(input, output); os.flush(); os.close(); } catch (Exception e) { } } /** * SVG转PNG * * @param svgCode SVG代码 * @param outpath 输出路径 * @throws TranscoderException * @throws IOException */ public void svg2PNG(String svgCode, String outpath) throws TranscoderException, IOException { Transcoder transcoder = new PNGTranscoder(); svgConverte(svgCode, outpath, transcoder); } /** * SVG转PNG * * @param svgCode SVG代码 * @param out 输出流 * @throws TranscoderException * @throws IOException */ public void svg2PNG(String svgCode, OutputStream out) throws TranscoderException, IOException { Transcoder transcoder = new PNGTranscoder(); svgConverte(svgCode, out, transcoder); } /** * SVG转PNG * * @param svgFile SVG文件 * @param outFile 输出文件 * @throws TranscoderException * @throws IOException */ public void svg2PNG(File svgFile, File outFile) throws TranscoderException, IOException { Transcoder transcoder = new PNGTranscoder(); svgConverte(svgFile, outFile, transcoder); } /** * SVG转JPG * * @param svgCode SVG代码 * @param outpath 输出路径 * @throws TranscoderException * @throws IOException */ public void svg2JPEG(String svgCode, String outpath) throws TranscoderException, IOException { Transcoder transcoder = new JPEGTranscoder(); //为防止ERROR: The JPEG quality has not been specified. Use the default one: no compression 错误,需如下配置 transcoder.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, 0.99f); svgConverte(svgCode, outpath, transcoder); } /** * SVG转JPG * * @param svgCode SVG代码 * @param out 输出流 * @throws TranscoderException * @throws IOException */ public void svg2JPEG(String svgCode, OutputStream out) throws TranscoderException, IOException { Transcoder transcoder = new JPEGTranscoder(); //为防止ERROR: The JPEG quality has not been specified. Use the default one: no compression 错误,需如下配置 transcoder.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, 0.99f); svgConverte(svgCode, out, transcoder); } /** * SVG转JPG * * @param svgFile SVG文件 * @param outFile 输出文件 * @throws TranscoderException * @throws IOException */ public static void svg2JPEG(File svgFile, File outFile) throws TranscoderException, IOException { Transcoder transcoder = new JPEGTranscoder(); //为防止ERROR: The JPEG quality has not been specified. Use the default one: no compression 错误,需如下配置 transcoder.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, 0.99f); svgConverte(svgFile, outFile, transcoder); } /** * SVG转PDF * * @param svgCode SVG代码 * @param outpath 输出路径 * @throws TranscoderException * @throws IOException */ public void svg2PDF(String svgCode, String outpath) throws TranscoderException, IOException { Transcoder transcoder = new PDFTranscoder(); svgConverte(svgCode, outpath, transcoder); } /** * SVG转PS * * @param svgCode * @param outpath * @throws TranscoderException * @throws IOException */ public void svg2PS(String svgCode, String outpath) throws TranscoderException, IOException { Transcoder transcoder = new PSTranscoder(); svgConverte(svgCode, outpath, transcoder); } /** * SVG转PS * * @param svgCode SVG代码 * @param out 输出流 * @throws TranscoderException * @throws IOException */ public void svg2PS(String svgCode, OutputStream out) throws TranscoderException, IOException { Transcoder transcoder = new PSTranscoder(); svgConverte(svgCode, out, transcoder); } /** * SVG转EPS * * @param svgCode SVG代码 * @param out 输出流 * @throws TranscoderException * @throws IOException */ public void svg2EPS(String svgCode, OutputStream out) throws TranscoderException, IOException { Transcoder transcoder = new EPSTranscoder(); svgConverte(svgCode, out, transcoder); } /** * SVG转EPS * * @param svgCode * @param outpath * @throws TranscoderException * @throws IOException */ public void svg2EPS(String svgCode, String outpath) throws TranscoderException, IOException { Transcoder transcoder = new EPSTranscoder(); svgConverte(svgCode, outpath, transcoder); } /** * SVG转PDF * * @param svgCode SVG代码 * @param out 输出流 * @throws TranscoderException * @throws IOException */ public void svg2PDF(String svgCode, OutputStream out) throws TranscoderException, IOException { Transcoder transcoder = new PDFTranscoder(); svgConverte(svgCode, out, transcoder); } /** * SVG转PDF * * @param svgFile SVG文件 * @param outFile 输出文件 * @throws TranscoderException * @throws IOException */ public void svg2PDF(File svgFile, File outFile) throws TranscoderException, IOException { Transcoder transcoder = new PDFTranscoder(); svgConverte(svgFile, outFile, transcoder); } private void svgConverte(String svgCode, String outpath, Transcoder transcoder) throws IOException, TranscoderException { svgConverte(svgCode, getOutputStream(outpath), transcoder); } private static void svgConverte(File svg, File outFile, Transcoder transcoder) throws IOException, TranscoderException { svgConverte(svg2String(getInputStream(svg)), getOutputStream(outFile), transcoder); } private static void svgConverte(String svgCode, OutputStream out, Transcoder transcoder) throws IOException, TranscoderException { svgCode = svgCode.replaceAll(":rect", "rect"); TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(svgCode.getBytes())); TranscoderOutput output = new TranscoderOutput(out); svgConverte(input, output, transcoder); } private static void svgConverte(TranscoderInput input, TranscoderOutput output, Transcoder transcoder) throws IOException, TranscoderException { transcoder.transcode(input, output); } public static InputStream getInputStream(File file) throws IOException { return new FileInputStream(file); } public InputStream getInputStream(String filepath) throws IOException { File file = new File(filepath); if (file.exists()) return getInputStream(file); else return null; } public static OutputStream getOutputStream(File outFile) throws IOException { return new FileOutputStream(outFile); } public OutputStream getOutputStream(String outpath) throws IOException { File file = new File(outpath); if (!file.exists()) file.createNewFile(); return getOutputStream(file); } /** * 默认使用编码UTF-8 SVG文件输入流转String * * @param svgFile * @return SVG代码 * @throws IOException */ public static String svg2String(File svgFile) throws IOException { InputStream in = getInputStream(svgFile); return svg2String(in, "UTF-8"); } /** * SVG文件输入流转String * * @param svgFile * @return SVG代码 * @throws IOException */ public String svg2String(File svgFile, String charset) throws IOException { InputStream in = getInputStream(svgFile); return svg2String(in, charset); } /** * 默认使用编码UTF-8SVG输入流转String * * @param in * @return SVG代码 */ public static String svg2String(InputStream in) { return svg2String(in, "UTF-8"); } /** * 指定字符集SVG输入流转String * * @param in 输入流 * @param charset 字符编码 * @return SVG代码 */ public static String svg2String(InputStream in, String charset) { StringBuffer svgBuffer = new StringBuffer(); BufferedReader bfr = null; try { InputStreamReader inputStreamReader = new InputStreamReader(in, charset); bfr = new BufferedReader(inputStreamReader); String line = ""; while ((line = bfr.readLine()) != null) { svgBuffer.append(line); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bfr != null) bfr.close(); } catch (IOException e) { e.printStackTrace(); } } return svgBuffer.toString(); } }
这里有些配置的我就不公开了
看到这想必大家对这个功能有所了解了,接下来进阶需求,由设计师提供一个图像模板,比如:汽车,房屋等。对这类对象的属性进行切换,比如,汽车是否为敞篷,颜色,房屋的层高,风格等。
可以控制图像的属性,生成图片。如果给你做,你会如何实现?(这类功能有很多实现场景,比如:很多游戏中的模型切换(游戏中使用的技术是Cocos2d游戏开发引擎)等)
这里分享一个纯前端实现人形头像元素切换的功能:https://github.com/Ice-Hazymoon/random-avatar-generator
解剖功能实现原理(以人形头像为例):
将人像的元素拆分出来:发型,肤色,头像大小,鼻子,嘴巴等,给定一个人形模型模板,让每个元素套用在模型模板上面,实现控制人像切换。
同理(汽车和房屋也一样)
Java后端通过创建对象,列举对象属性,将数据填充到模板里面,然后通过模板生成对应的图片即可。
这个模板可以使用Freemarker技术实现,由前端给的一个html的文件,将文件内容复制到以.ftl为后缀的文件中,将参数替换成变量即可。
前端可以通过叠加样式或者图片实现人像切换,后端则负责给定对象属性以及参数。