As long as you can still grab a breath, you fight. We must fight while we breathe.

There was a time when I was obsessed with the daily one-sentence sharing poster of Kingsoft Powerword. Because not only the picture on the poster is beautiful, but also the text is particularly beautiful, so that I feel that life has poetry. Just like the sentence at the beginning of the article, both Chinese and English are wonderful.

Recently, there are a lot of people obsessed with fluent speaking small program to share posters (circle of friends everywhere). But whether kingsoft powerword or Fluent said, the posters shared are not their own TWO-DIMENSIONAL code, which for the personal brand founder, it is really an effort to please.

Of course, as a programmer, this is not a problem for me. This article we use Java to generate a copy of kingsoft powerword poster.

01. General idea

  • Collecting network pictures

  • Load the poster background and personal brand QR code

  • Graphics2D was used to draw network images into poster covers

  • Graphics2D was used to print the Chinese and English text on the poster

  • Use Graphics2D to draw personal QR codes on posters

  • Use Swing to build graphical interfaces

  • Publish the project as a JAR package

  • Run the JAR package and fill in the necessary information to generate the poster

02. Collect network pictures

The first step is to get the path of the network picture. Kingsoft Powerword daily sentence picture path address form is shown below. You can get the latest picture path based on the current date.

// Kingsoft Powerword image path
String formatDate = DateFormatUtils.format(new Date(), "yyyyMMdd");
String picURL = "http://cdn.iciba.com/news/word/big_" + formatDate + "b.jpg";
Copy the code

Second, once you have the image path, you can create an HTTP GET request based on that path.

// Initiate an HTTP GET request based on the path
HttpGet httpget = new HttpGet(picURL);
// Use the addHeader method to add the request header
httpget.addHeader("Content-Type"."text/html; charset=UTF-8");

// Configure timeout Settings for requests
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(500).setConnectTimeout(500)
		.setSocketTimeout(500).build();
httpget.setConfig(requestConfig);
Copy the code

In the third step, create the CloseableHttpClient object to execute the HTTP GET request and obtain the response information. CloseableHttpClient is an abstract class that is the basic implementation of HttpClient and also implements the java.io.Closeable interface.

CloseableHttpClient httpclient = HttpClientBuilder.create().build();
CloseableHttpResponse response = httpclient.execute(httpget);
Copy the code

Step 4, get the image input stream from CloseableHttpResponse.

HttpEntity entity = response.getEntity();
InputStream picStream = entity.getContent();
Copy the code

Step 5: Read the information from the image input stream and output it to a local file.

File pic = Files.createTempFile(Paths.get("D:\\test"), "pic_".".jpg");
FileOutputStream fos = new FileOutputStream(pic);
int read = 0;

// 1024 bytes =1KB 1024KB=1MB
byte[] bytes = new byte[1024 * 100];
while((read = inputStream.read(bytes)) ! = -1) {
	fos.write(bytes, 0, read);
}

fos.flush();
fos.close();
Copy the code

The collected images can be viewed in the specified temporary directory, as shown below.

03. Load the poster background and qr code of personal brand

The size of the poster background is 678 x 1013 pixels and the size of the personal brand QR code is 128 x 128 pixels. Both images are prepared and placed in the SRC directory. The directory structure of the entire project is shown below.

Next, we read the two images separately into a temporary file for subsequent actions.

The first step is to create a ClassLoader object that looks up the resource from the root of the classpath.

ClassLoader classLoader = ReadBgAndQrcode.class.getClassLoader();
Copy the code

The second step, through this getResourceAsStream () read the poster background and personal brand qr code, copy to a temporary file.

File bgFile = Files.createTempFile(DIRECTORY, "bg_".".jpg").toFile();
InputStream inputStream = classLoader.getResourceAsStream("default_bgimg.jpg");
FileUtils.copyInputStreamToFile(inputStream, bgFile);
logger.debug("Background:" + bgFile.getAbsolutePath());


File qrcodeFile = Files.createTempFile(DIRECTORY, "qrcode_".".jpg").toFile();
InputStream qrcodeInputStream = classLoader.getResourceAsStream("default_qrcodeimg.jpg");
FileUtils.copyInputStreamToFile(qrcodeInputStream, qrcodeFile);
logger.debug(Qr code: + qrcodeFile.getAbsolutePath());
Copy the code

You can view the poster background and personal brand QR code in the designated temporary directory, as shown below.

05. Use Graphics2D to draw network pictures into poster covers

The Graphics2D class extends the Graphics class to provide more sophisticated control over geometry, coordinate transformations, color management, and text layout, and is the base class for rendering two-dimensional shapes, text, and images.

BufferedImage describes the image using an accessible image data buffer, consisting of a color model and an image data grid, with the upper-left coordinate of (0,0) for all BufferedImage objects.

You can get the Graphics2D object using the createGraphics() method of the BufferedImage class.

The first step is to read the poster background and poster cover into the BufferedImage object. Note that the deleteOnExit() method requests that the file or directory represented by this abstract pathname be deleted upon virtual machine termination.

/ / the background
File bgFile = FileUtil.read("bg_".".jpg"."default_bgimg.jpg");
bgFile.deleteOnExit();
BufferedImage bgImage = ImageIO.read(bgFile);

/ / cover
File picFile = CapturePic.capture();
picFile.deleteOnExit();
BufferedImage picImage = ImageIO.read(picFile);
Copy the code

The second step is to calculate the starting coordinates of the cover, as well as the height and width.

// The starting coordinates of the cover image
int pic_x = MARGIN, pic_y = MARGIN;
// The width of the cover image
int pic_width = bgImage.getWidth() - MARGIN * 2;
// The height of the cover image
int pic_height = picImage.getHeight() * pic_width / picImage.getWidth();
Copy the code

Step 3: Draw the cover on the background of the poster.

Graphics2D graphics2d = bgImage.createGraphics();
// Draw the cover on the background
graphics2d.drawImage(picImage, pic_x, pic_y, pic_width, pic_height, null);
// Release the graphics context and any system resources it is using.
graphics2d.dispose();
Copy the code

Fourth, output the drawn image to a file.

File posterFile = Files.createTempFile(FileUtil.DIRECTORY, "poster_".".jpg").toFile();
ImageIO.write(bgImage, "jpg", posterFile);
Copy the code

You can view the poster in the specified temporary directory, as shown below.

06. Use Graphics2D to print Chinese on posters

The Font class represents a Font and is used to render text in a visible way. Fonts provide the information needed to map character sequences to pictographic sequences and render pictographic sequences on graphics and component objects.

The first step, through the GraphicsEnvironment class getAvailableFontFamilyNames () view allows you to use fonts on your computer.

String[] fontNames = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();

for (String fontName : fontNames) {
	System.out.println(fontName);
}
Copy the code

Here are some general Chinese fonts (there are more, not listed) :

宋体 young circle Microsoft yahei Microsoft yahei Light new 宋体 founder yao shuli regular script black script

Step 2, set the font and color.

// The Font construction parameters are the Font name, Font style, Font size
Font font = new Font(Microsoft Yahei, Font.PLAIN, 28);
g.setFont(font);
// RGB
g.setColor(new Color(71.71.71));
Copy the code

The third step is to wrap the text according to the width of each Chinese character under the current font and the maximum text width that the poster can accommodate.

When calculating the width of each font, need to use the sun. The font. FontDesignMetrics, it extends the Java awt. FontMetrics. The FentMetrics class defines a font metric object that encapsulates information about rendering a particular font on a particular screen. FontDesignMetrics provides Font information for more metrics.

FontDesignMetrics has a few important values to note:

  • Reference point isbaseline
  • Ascent is the distance from baseline to the top of the character
  • Descent is the distance below baseline to the lowest point of a character
  • The leading document says vaguely that it is the distance between descent on the previous line and ascent on the next
  • Top refers to the value of the highest character to the baseline, the maximum of ascent
  • Bottom refers to the value from the bottom character to baseline, the maximum value of descent

The charWidth() method of FontDesignMetrics calculates the character width.

public static String makeLineFeed(String zh, FontDesignMetrics metrics, int max_width) {
	StringBuilder sb = new StringBuilder();
	int line_width = 0;
	for (int i = 0; i < zh.length(); i++) {
		char c = zh.charAt(i);
		sb.append(c);

		// Skip if active line breaks
		if (sb.toString().endsWith("\n")) {
			line_width = 0;
			continue;
		}

		// The charWidth() method of FontDesignMetrics calculates the character width
		int char_width = metrics.charWidth(c);
		line_width += char_width;

		// If the width of the current character plus the existing width of the previous string exceeds the maximum width of the poster, newline
		if (line_width >= max_width - char_width) {
			line_width = 0;
			sb.append("\n"); }}return sb.toString();
}
Copy the code

Suppose the text is “King Of Silence ii, author of The Road to Advanced Web Full-stack Development”; A programmer who doesn’t just write code, but also write interesting and helpful words for you who don’t like to be serious.” Let’s experiment with the makeLineFeed() method.

Font font = new Font(Microsoft Yahei, Font.PLAIN, 28);
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);

String zh = Silent Wang Er, author of "The Road to Advanced Web Full Stack Development"; A programmer who not only writes code, but also writes interesting and helpful text for you who don't like to be serious.";

String[] rows = makeLineFeed(zh, metrics, 600).split("\n");
for (int i = 0; i < rows.length; i++) {
	System.out.println(rows[i]);
}
Copy the code

The result is shown below.

Silent Wang Er, author of “The Road to Advanced Development of Web Full Stack”; A programmer who not only writes code, but also writes interesting and helpful text for you who don’t like to be serious.

Fourth, print the wrapped text on the background of the poster.

Here we use FontDesignMetrics’ getHeight() method to get the height of each line of text. Refer to the diagram below to understand the specific height of height.

// Wrap text
String zhWrap = FontUtil.makeLineFeed(graphics2dPoster.getZh(), metrics, graphics2dPoster.getSuitableWidth());

/ / branch
String[] zhWraps = zhWrap.split("\n");

// Print each line on the background of the poster
for (int i = 0; i < zhWraps.length; i++) {
	graphics2dPoster.addCurrentY(metrics.getHeight());
	graphics2d.drawString(zhWraps[i], MARGIN, graphics2dPoster.getCurrentY());
}
Copy the code

The effect of the poster is shown below.

Can see, the character contains very strong sawtooth feeling, how to eliminate?

graphics2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
Copy the code

If you don’t have good English, this code might look like a drag. The word ANTIALIASING means “get rid of aliasing, get rid of aliasing, graph fidelity”.

07. Use Graphics2D to print English on posters

The biggest difference between English and Chinese is that the units of newlines are not single characters, but whole words.

The first step is to wrap the text according to the width of each English word under the current font and the maximum text width that the poster can accommodate.

public static String makeEnLineFeed(String en, FontDesignMetrics metrics, int max_width) {
	// Append Spaces to each word
	char space = ' ';
	int spaceWidth = metrics.charWidth(space);

	// Split the English text by Spaces
	String[] words = en.split(String.valueOf(space));
	// Use StringBuilder to modify strings
	StringBuilder sb = new StringBuilder();
	// Width of each line of text
	int len = 0;

	for (int i = 0; i < words.length; i++) {
		String word = words[i];

		int wordWidth = metrics.stringWidth(word);
		// Overlays the width of the current word
		len += wordWidth;

		// If the width exceeds the maximum, make a line break
		if (len > max_width) {
			sb.append("\n");
			sb.append(word);
			sb.append(space);

			// The starting width of the next line
			len = wordWidth + spaceWidth;
		} else {
			sb.append(word);
			sb.append(space);

			// There is an extra spacelen += spaceWidth; }}return sb.toString();
}
Copy the code

If the text is “Fear can hold you prisoner. Hope can set you free. It takes a strong man to save himself, And a great man to save another. “Let’s experiment with the makeEnLineFeed() method.

Font font = new Font(Microsoft Yahei, Font.PLAIN, 28);
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);

String en = "Fear can hold you prisoner. Hope can set you free. It takes a strong man to save himself, and a great man to save another.";
String[] rows = makeEnLineFeed(en, metrics, 600).split("\n");
for (int i = 0; i < rows.length; i++) {
	System.out.println(rows[i]);
}
Copy the code

The result is shown below.

Fear can hold you prisoner. Hope can set you free. It takes a strong man to save himself, and a great man to save another.

Third, print the wrapped text on the background of the poster.

// Set the distance between the cover image and the Chinese characters below
graphics2dPoster.addCurrentY(20);

Graphics2D graphics2d = graphics2dPoster.getGraphics2d();
graphics2d.setColor(new Color(157.157.157));

FontDesignMetrics metrics = FontDesignMetrics.getMetrics(graphics2d.getFont());
String enWrap = FontUtil.makeEnLineFeed(graphics2dPoster.getEn(), metrics, graphics2dPoster.getSuitableWidth());
String[] enWraps = enWrap.split("\n");
for (int i = 0; i < enWraps.length; i++) {
	graphics2dPoster.addCurrentY(metrics.getHeight());
	graphics2d.drawString(enWraps[i], MARGIN, graphics2dPoster.getCurrentY());
}
Copy the code

The effect of the poster is shown below.

07. Use Graphics2D to draw personal QR code on the poster

With the experience of drawing a poster cover in front of you, drawing a QR code becomes a breeze.

/ / qr code
File qrcodeFile = FileUtil.read("qrcode_".".jpg"."default_qrcodeimg.jpg");
qrcodeFile.deleteOnExit();

BufferedImage qrcodeImage = ImageIO.read(qrcodeFile);
// The starting coordinates of the qr code
int qrcode_x = bgImage.getWidth() - qrcodeImage.getWidth() - MARGIN;
int qrcode_y = bgImage.getHeight() - qrcodeImage.getHeight() - MARGIN;
graphics2dPoster.getGraphics2d().drawImage(qrcodeImage, qrcode_x, qrcode_y, qrcodeImage.getWidth(),
		qrcodeImage.getHeight(), null);
Copy the code

The effect of the poster is shown below.

Do you feel that the lower left corner of the poster is blank and the overall symmetry is not natural enough? Then add some two-dimensional code description text in the lower left corner.

graphics2d.setColor(new Color(71.71.71));
Font font = new Font(USE_FONT_NAME, Font.PLAIN, 22);
graphics2d.setFont(font);
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(graphics2d.getFont());

graphics2d.drawString("Silent King II.", MARGIN, bgImage.getHeight() - MARGIN - metrics.getHeight() * 2);
graphics2d.drawString("A programmer with a sense of humor.", MARGIN, bgImage.getHeight() - MARGIN - metrics.getDescent());
Copy the code

The effect of the poster is shown below.

08. Use Swing to build graphical interfaces

Swing is a toolkit (class library) for Java GUI programming (graphical interface design); In other words, Java can be used to develop PC software with interfaces because Swing exists.

Swing uses pure Java code to emulate various controls, and there is no built-in way to use a native operating system, so Swing is cross-platform. Because of this nature, Swing controls are often called lightweight controls.

Eclipse does not support visual Swing programming by default, but there is a good plug-in on the Market for Eclipse, WindowBuilder, that can make development much easier and faster.

Download address: marketplace.eclipse.org/content/win…

You can drag it directly to Eclipse for installation, as shown below.

Note that the version requirements for Eclipse are:

2018-09 (4.9), a Photon (4.8) and Oxygen (4.7), Neon (4.6), 2018-12 (4.10), 2019-03 (4.11)

Drag to Eclipse to look like this:

When the installation is complete, you will be reminded to restart Eclipse.

Tips: The installation process takes about 3 minutes and may fail during the installation. Try again for several times. Don’t worry, Eclipse intelligently saves the progress before the failure.

After the installation is successful, you can use the visual tool to design the interface, as shown below:

09. Jar your project

When packaging applications, users expect developers to provide a single file, not a folder containing a lot of source code. That’s why jar packages exist.

It is also easy to jar a project. In Eclipse, right-click the project, Export, and Runnable JAR file. You will see the following screen.

Select the class for the Main method, specify the export target, select the Copy Required Libraries option, and click Finish. The generated JAR package file can be found in the specified directory.

10. Run the JAR package and fill in the necessary information to generate the poster

If the Java runtime environment is installed on your computer, double-click the JAR file to run it. The interface after running, as shown in the figure below. You can fill in the path of Chinese, English and poster cover, and then click the button to generate the poster.

PS: In order to facilitate your study, I have put the source code on GitHub, the address is as follows.

Github.com/qinggee/pos…

Hurry to star!