This article has participated in the activity of “New person creation Ceremony”, and started the road of digging gold creation together.

scenario

The front end has a artifact — Canvas, this canvas tag can process the synthesis of all kinds of pictures, can be accurate to the specific coordinates of the picture, add watermark, to watermark, it is not too simple! Can the Java back end handle that? Please tell him loudly, yes, he must! Image-combiner, so easy!

The environment

  1. jdk1.8
  2. spring boot

Set up

Import poM files

< the dependency > < groupId > com. Freewayso < / groupId > < artifactId > image - combiner < / artifactId > < version > 2.2.0 < / version > </dependency>Copy the code

Define the core interface ImageService

Public interface ImageService {/** * simple ImageService * @param * @return void * @author liyajie * @createTime 2021/12/17 9:54 **/  InputStream generateSimpleImage(String text, String bgImageUrl, String todoImage, String localPath, Boolean saveLocal, Boolean saveOss); * @param * @return void * @author liyajie * @createTime 2021/12/17 9:54 **/ InputStream generateComplexImage(String title, String content, String bgImageUrl, String qrCodeUrl, String productImageUrl, String waterMarkImageUrl, String avatarImageUrl, String localPath, Boolean saveLocal, Boolean saveOss); }Copy the code

Define the core interface implementation class ImageServiceImpl

@Service public class ImageServiceImpl implements ImageService { @Override public InputStream generateSimpleImage(String  text, String bgImageUrl, String todoImage, String localPath, Boolean saveLocal, Boolean saveOss) { InputStream is = null; // Synthesizer (specify the background image and output format, the width and height of the entire image and related calculations depend on the background image, ImageCombiner combiner = new ImageCombiner(bgImageUrl, outputFormat.jpg); AddImageElement (todoImage, 300, 300); addImageElement(todoImage, 300, 300); // addTextElement, the second argument is the font size, the third argument is the left margin, the fourth argument is the top margin combiner.addtextelement (text, 60, 100, 960); // execute image merge combiner.bine (); / / can obtain flow (and upload oss, etc.) is = combiner. GetCombinedImageStream (); If (saveLocal){comine.save (localPath); } // Save to oss if(saveOss){// TODO: 2021/12/17 save to OSS}} Catch (Exception e){e.printStackTrace(); } return is; } @Override public InputStream generateComplexImage(String title, String content, String bgImageUrl, String qrCodeUrl, String productImageUrl, String waterMarkImageUrl, String avatarImageUrl, String localPath, Boolean saveLocal, Boolean saveOss) { InputStream is = null; try{ BufferedImage waterMark = ImageIO.read(new URL(waterMarkImageUrl)); BufferedImage Avatar = imageio. read(new URL(avatarImageUrl)); // avatar // create a synthesizer (specify the background image and output format, the width and height of the entire image and related calculations depend on the background image, ImageCombiner combiner = new ImageCombiner(bgImageUrl, 1500, 0, zoommode. Height, outputFormat.jpg); / / v1.1.4 can specify the background after a new wide high (without specifying the default former wide and high) with pictures / / in view of the background and the whole figure setting combiner. SetBackgroundBlur (30); / / set the background gaussian blur (frosted glass effect) combiner. SetCanvasRoundCorner (100); // Set the rounded corners (output format must be PNG) // Title (default font is Ariphul, black, AddTextElement (title, 0, 150, 1400). SetCenter (true) // Center drawing (ignore x coordinates, .setalpha (.8f) // Transparency (0.0~1.0).setrotate (45) // Rotation (0~360). // color // content (set text wrap, AddTextElement (content, "Microsoft Yahe ", 40, 150) comininer. AddTextElement (content," Microsoft Yahe ", 40, 150, 1480).setStrikeThrough(true) // Delete line. SetAutoBreakLine (837, 2, 60); // Set the coordinates, width and height, and scale mode. If you scale by width, AddImageElement (productImageUrl, 0, 160, 837, 0, zoommode.width). SetCenter (true) Change to automatic calculation). SetRoundCorner (46); AddImageElement (Avatar, 200, 1200). SetRoundCorner (200); // Round corner // watermark (set transparency, 0.0 ~ 1.0) combiner. AddImageElement (waterMark, 630, 1200).setalpha (.8f) // Transparency (0.0~1.0).setrotate (45) // Rotation (0~360).setblur (20); // Add rounded rectangle element (version >=1.2.0), As the bottom line of the qr code combiner. AddRectangleElement (138, 1707, 300, 300). The setColor (Color. WHITE.) setRoundCorner (50) / / this value is greater than or equal to the width is high, is round, For example, 300. setAlpha(.8f); AddImageElement (qrCodeUrl, 138, 1707, 186, 186, ZoomMode.WidthHeight); TextElement textPrice = new TextElement("¥1290", 60, 230, 1300); textPrice.setColor(Color.red); / / red textPrice. SetStrikeThrough (true); // Delete line combiner.addelement (textPrice); // Perform image merge combiner.bine (); / / can obtain flow (and upload oss, etc.) is = combiner. GetCombinedImageStream (); If (saveLocal){comine.save (localPath); } // Save to oss if(saveOss){// TODO: 2021/12/17 save to OSS}} Catch (Exception e){e.printStackTrace(); } return is; }}Copy the code

Test ImageController

@RestController @Slf4j public class ImageController { @Resource HttpServletResponse response; @Autowired ImageService imageService; @param * @return void * @author liyajie * @createTime 2021/12/17 10:43 **/ @GetMapping("/createSimpleImage") public void createSimpleImage(){ OutputStream os = null; Try {String text = ""; String bgImageUrl = "https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg"; String todoImage = "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"; . / / picture flow InputStream is = imageService generateSimpleImage (text, bgImageUrl todoImage, "", false, false); BufferedImage image = ImageIO.read(is); response.setContentType("image/png"); os = response.getOutputStream(); if (image ! = null) { ImageIO.write(image, "png", os); } } catch (IOException e) { e.printStackTrace(); Log.error (' LLDB ', LLDB message ()); } finally { if (os ! = null) { try { os.flush(); os.close(); }catch (Exception e){ e.printStackTrace(); }}}} /** * Complex image aggregation * @param * @return void * @author liyajie * @createTime 2021/12/17 10:43 **/ @getMapping ("/createComplexImage") public void createComplexImage(){// Background String bgImageUrl = "https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg"; / / qr code String qrCodeUrl = "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"; / / commodity figure String productImageUrl = "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"; Figure the String / / waterMark waterMark = "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"; / / avatar String avatar = "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"; // Title text String title = "# favorite home "; Socrates said, "If it had not been for the table, there might not have been the kettle "; OutputStream os = null; Try {/ / picture flow InputStream is = imageService. The generateComplexImage (title, content, bgImageUrl, qrCodeUrl productImageUrl, waterMark, avatar,"",false,false); BufferedImage image = ImageIO.read(is); response.setContentType("image/png"); os = response.getOutputStream(); if (image ! = null) { ImageIO.write(image, "png", os); } }catch (Exception e){ e.printStackTrace(); }finally { if (os ! = null) { try { os.flush(); os.close(); }catch (Exception e){ e.printStackTrace(); } } } } }Copy the code

The test results

conclusion

It can be seen from the test effect:

  1. The realization of picture and picture synthesis
  2. Realized the picture and the text synthesis
  3. Image and text positions can be dynamically modified using parameters (see code for details)

(With opensource address: gitee.com/opensourcec…