--Write sample code to regularly post tweets with images on AWS Lambda + Java 8 --Draw the current date and time in Japanese on the prepared background image --Use the Twitter4J library for posting to Twitter --Use Amazon CloudWatch Events for regular execution
--Japanese fonts are not available on AWS Lambda + Java --Reference: Check if there is a font that can use Japanese \ (Hiragana / Katakana / Kanji ) in AWS Lambda \ + Java -Qiita --Incorporate and use Noto Sans CJK JP Regular fonts from Google Noto Fonts --Font file NotoSansCJKjp-Regular.otf is about 16.4MB in size --Reference: Noto CJK – Google Noto Fonts
--pom.xml: Build configuration file for Maven --ImageTweet.java: Java class that performs the main processing --NotoSansCJKjp-Regular.otf: Font file containing Japanese characters --fukidashi.png: Background image file of the image to be posted on Twitter
├── pom.xml
└── src
└── main
├── java
│ └── com
│ └── example
│ └── ImageTweet.java
└── resources
├── font
│ └── NotoSansCJKjp-Regular.otf
└── image
└── fukidashi.png
ImageTweet.java
package com.example;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import twitter4j.Status;
import twitter4j.StatusUpdate;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.conf.ConfigurationBuilder;
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
public class ImageTweet implements RequestHandler<Map<String, Object>, Map<String, Object>> {
/**
*This is the entry point when running as a standalone Java application.
*
* @param args First element[0]An array with a string to tweet to
*/
public static void main(String[] args) {
Map<String, Object> output = new ImageTweet().invoke(new HashMap<String, Object>());
System.out.println(output);
}
/**
*Entry point when executing AWS Lambda function(Handler method)is.
*
* @param input input data
* @param context AWS Lambda Context object
* @return output data
*/
@Override
public Map<String, Object> handleRequest(Map<String, Object> input, Context context) {
return invoke(input);
}
/**
*Tweet
*
* @param input Text to tweet
*/
public Map<String, Object> invoke(Map<String, Object> input) {
Map output = new HashMap<String, Object>();
try {
//Assemble the text to tweet
String text = LocalDateTime.now(ZoneId.of("JST", ZoneId.SHORT_IDS))
.format(DateTimeFormatter.ofPattern("Year M month d day H hour m minutes s seconds"));
//Image file path
String imagePath = "image/fukidashi.png ";
//Image file name
String imageFileName = new File(imagePath).getName();
//Image format name
String imageFormatName = "png";
//Load image file
BufferedImage image = getImageFromResource(imagePath);
//Read font file
String fontPath = "font/NotoSansCJKjp-Regular.otf";
Font font = getFont(fontPath);
//Process the image(Draw text)
Graphics2D g = image.createGraphics();
g.setColor(Color.BLUE);
g.setFont(font.deriveFont(30.0f));
g.drawString(text, image.getWidth() / 4, image.getHeight() / 2);
g.dispose();
//Get image data
InputStream imageBody = createInputStream(image, imageFormatName);
//Get environment variables
Map<String, String> env = System.getenv();
//Tweet
TwitterFactory tf = getTwitterFactory(env);
Status status = tweet(tf, text, imageFileName, imageBody);
//Build output data
output.put("result", status);
} catch (Exception e) {
output.put("error", e);
}
return output;
}
/**
*Load the font file.
*
* @param path font file path
* @return font object
* @throws FontFormatException When the required font data is not available
* @throws IOException if any error occurs
*/
private Font getFont(String path) throws FontFormatException, IOException {
ClassLoader cl = getClass().getClassLoader();
try (InputStream input = cl.getResourceAsStream(path)) {
//The default size of Java Font objects is 12
return Font.createFont(Font.TRUETYPE_FONT, input).deriveFont(12.0f);
}
}
/**
*Load the image file.
*
* @param path Image file path
* @return image object
* @throws IOException if any error occurs
*/
private BufferedImage getImageFromResource(String path) throws IOException {
ClassLoader cl = getClass().getClassLoader();
URL url = cl.getResource(path);
return ImageIO.read(url);
}
/**
*Gets the byte string of image data.
*
* @param image image object
* @param formatName Image format name
* @return Image data byte sequence
* @throws IOException if any error occurs
*/
private InputStream createInputStream(BufferedImage image, String formatName) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
ImageIO.write(image, formatName, output);
return new ByteArrayInputStream(output.toByteArray());
}
/**
*Gets a TwitterFactory object.
*
* @param env environment variable
* @return TwitterFactory object
*/
private TwitterFactory getTwitterFactory(Map<String, String> env) {
ConfigurationBuilder cb = new ConfigurationBuilder();
//Get Twitter credentials from environment variables
cb.setDebugEnabled(true)
.setOAuthConsumerKey(env.get("TWITTER_CONSUMER_KEY"))
.setOAuthConsumerSecret(env.get("TWITTER_CONSUMER_SECRET"))
.setOAuthAccessToken(env.get("TWITTER_ACCESS_TOKEN"))
.setOAuthAccessTokenSecret(env.get("TWITTER_ACCESS_TOKEN_SECRET"));
return new TwitterFactory(cb.build());
}
/**
*Post a tweet with an image.
*
* @param text The text to tweet
* @param imageFileName File name of the image to be included in the tweet
* @param imageBody Image data to include in tweets
* @return Status object as a result of tweeting
* @throws TwitterException If any error occurs
*/
private Status tweet(TwitterFactory tf, String text, String imageFileName, InputStream imageBody) throws TwitterException {
Twitter twitter = tf.getInstance();
StatusUpdate status = new StatusUpdate(text);
status.setMedia(imageFileName, imageBody);
return twitter.updateStatus(status);
}
}
pom.xml
Configuration file for building with Maven.
--Match Java version 1.8 supported by AWS Lambda --Introduce the library aws-lambda-java-core for AWS Lambda --Introduce maven-shade-plugin to generate JAR file including library
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>image-tweet</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>image-tweet</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-lambda-java-core -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.twitter4j/twitter4j-core -->
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>4.0.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- https://maven.apache.org/plugins/maven-shade-plugin/ -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
In this program, a balloon image is prepared as the background of the image to be tweeted.
Build with Maven and generate a JAR file.
$ mvn package
A JAR file called image-tweet-1.0.jar is generated in the target directory.
Create a Lambda function from the Lambda Management Console (https://console.aws.amazon.com/lambda/).
Enter the "basic information". Function name: any name Runtime: Java 8 Run Role: Create a new role with basic Lambda permissions
Enter the "function code". Code entry type: Upload .zip or jar file Runtime: Java 8 Handler: com.example.ImageTweet :: handleRequest
Click "Upload" to upload the generated JAR file image-tweet-1.0.jar.
Set environment variables. In this program, the credential information for calling the Twitter API is obtained from environment variables.
Click Test at the top right of the page to create a new test event. Event template: Hello World Event name: any name Change the JSON that is the input data to any one (or leave the default).
You can run the test by clicking "Test" at the top right of the page. The result is displayed.
This completes the function for posting tweets with images on Twitter.
Click Add Trigger on the left side of the Lambda function Designer.
Select CloudWatch Events.
Set the content of the trigger to execute every minute. Rule: Create a new rule Rule name: any name Rule description: Arbitrary description Rule type: Scheduled expression Scheduled expression: cron (* * * *? *)
This completes the settings that are executed periodically.
You will be able to post tweets with images to Twitter on a regular basis.
-Building Lambda functions with Java -AWS Lambda -What is Amazon CloudWatch Events -Amazon CloudWatch Events -Schedule expression using Rate or Cron -AWS Lambda -Rule Schedule Expression -Amazon CloudWatch Events -Google Developers Japan: Japanese, Chinese and Korean have been added to the beautiful open source Noto font family.
Recommended Posts