タスクキューと App Engine Image API を使用して画像のサイズを変更する方法について説明します。
タスクキューでは、直接的なユーザー操作の外でコードが実行されるので、バックグラウンドでタスクを実行できます。このガイドでは、イメージを Cloud Storage に追加した後、タスクキューを使用してタスクを実行します。次のタスクがタスクキューで実行されます。
- Cloud Storage にアップロードされた画像ファイルを取得します。
- Image API を使用してサムネイル画像にサイズ変更します。
- 結果のサムネイルを Cloud Storage に保存します。
App Engine Java 8 ランタイムでは、AWT や Java2D などの Java ネイティブ画像処理クラスもサポートされています。
始める前に
このガイドでは、Apache Commons IOUtils ライブラリを使用します。IOUtils ライブラリを App Engine プロジェクトに含めるには:
pom.xml
に追加:<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency>
ライブラリのインポート
このガイドのサンプルコードでは、次のインポートが使用されています。
import com.google.appengine.api.images.Image;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.images.Transform;
import org.apache.commons.io.IOUtils;
タスクキューの作成
App Engine には default
タスクキューがありますが、作業タイプに応じて別のタスクキューを作成することもできます。たとえば、画像サイズの変更に使用するタスクキューと、アプリのデータベースの更新に使用するタスクキューを作成できます。
キューを追加するには、queue.xml
ファイルを App Engine プロジェクトの WEB-INF
ディレクトリに作成します。タスクキューには名前と実行レートを指定する必要があります。
<?xml version="1.0" encoding="UTF-8"?>
<queue-entries>
<queue>
<name>resize-image</name>
<rate>60/h</rate>
</queue>
</queue-entries>
この例の resize-image
という名前のキューでは、1 時間に 60 回、つまり 1 分に 1 回の実行レートが定義されています。キュー オプションのリストについては、queue.xml
のリファレンスをご覧ください。
タスクキューには、タスク リクエスタとタスクハンドラという 2 つのコンポーネントがあります。リクエスタはタスクをキューに追加し、それをタスクハンドラに送信します。
キューへのタスクの追加
キューにタスクを追加するには:
QueueFactory.getQueue()
を使用してタスクキュー オブジェクトを作成し、queue.xml
で定義されたキュー名を指定します。Queue imageResizeQueue; // Taskqueue queue @Override public void init() throws ServletException { // Setup Cloud Storage service gcsService = GcsServiceFactory.createGcsService( new RetryParams.Builder() .initialRetryDelayMillis(10) .retryMaxAttempts(10) .totalRetryPeriodMillis(15000) .build()); // Initialize the queue object with the specific queue imageResizeQueue = QueueFactory.getQueue([QUEUE-NAME]); // Cloud SQL connection setup try { final String url = System.getProperty("cloudsql"); // Cloud SQL server URI try { conn = DriverManager.getConnection(url); // Connect to the database Statement createTable; // SQL statement // Batch SQL table creation commands createTable.addBatch(createContentTableSql); createTable.addBatch(createUserTableSql); createTable.addBatch(createImageTableSql); createTable.addBatch(createBlogPostImageTableSql); conn.createTable.executeBatch(); // Execute batch } catch (SQLException e) { throw new ServletException("Unable to connect to Cloud SQL", e); } } finally { // Nothing really to do here. } }
Queue
オブジェクトにタスクを追加します。コードサンプルに示すように、imageResizeQueue.add()
でimageResizeQueue
オブジェクトにタスクを追加します。try { // Add a queued task to create a thumbnail of the uploaded image imageResizeQueue.add( TaskOptions.Builder.withUrl("/tasks/imageresize").param("filename", filename)); }
TaskOptions.Builder.withUrl()
を使用して、タスクハンドラの URI と、ハンドラに送信するパラメータを指定します。この例では、URI は
/tasks/imageresize
で、パラメータは処理対象の画像のファイル名を含むfilename
という変数です。
タスクハンドラの作成
キューにタスクを追加すると、URI /tasks/imageresize
にマップされているタスクハンドラが実行されます。タスクハンドラは、タスクが成功するまで実行を試行する Java サーブレットです。
この例では、タスクハンドラは次の 3 つのタスクを行います。
呼び出し元が指定した画像を Cloud Storage から取得します。
App Engine Image API を使用して画像を変換します。この例では、サムネイル画像に変換します。
変換した画像(サムネイル)を Cloud Storage に保存します。
タスクハンドラを作成するには:
ハンドラを URI
/tasks/imageresize
にマッピングするアノテーションを追加します。@WebServlet(name = "imageResize", description = "Task queue handler", urlPatterns = "/tasks/imageresize") public class imageResize extends HttpServlet { // Task handler functionality }
Cloud Storage 使用ガイドでの説明に従って Cloud Storage への接続を設定し、Cloud Storage から画像を取得します。
public void init() throws ServletException { // initiate GcsService GcsService gcsService = GcsServiceFactory.createGcsService( new RetryParams.Builder() .initialRetryDelayMillis(10) .retryMaxAttempts(10) .totalRetryPeriodMillis(15000) .build()); }
指定されたファイル名を使用して Cloud Storage から画像を取得する受信タスクキュー リクエストを処理します。
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String filename = req.getParameter("filename"); // Get the filename passed from the task requestor GcsFilename gcsFile = new GcsFilename(bucket, filename); // Create a valid Cloud Storage filename GcsInputChannel readChannel = gcsService.openPrefetchingReadChannel(gcsFile, 0, BUFFER_SIZE); // Read the file from Cloud Storage
ImagesService
オブジェクトを使用して画像のサイズを変更します。// Get an instance of the ImagesService we can use to transform images. ImagesService imagesService = ImagesServiceFactory.getImagesService(); // Make an image directly from a byte array, and transform it. Image image = ImagesServiceFactory.makeImage(IOUtils.toByteArray(Channels.newInputStream(readChannel))); Transform resize = ImagesServiceFactory.makeResize(100, 50); // resize image to 100x50 Image resizedImage = imagesService.applyTransform(resize, image); // Write the transformed image back to a Cloud Storage object. gcsService.createOrReplace( new GcsFilename(bucket, "thumbnail_" + filename), new GcsFileOptions.Builder().acl("public-read").build(), ByteBuffer.wrap(resizedImage.getImageData()));
上記のスニペットでは、Image API の
makeResize()
メソッドを使用して画像をサムネイルに変更しています。この処理を行うため、Cloud Storage からInputChannel
に画像を読み込み、IOUtils.toByteArray()
を使用して ByteArray に変換します。変換を適用すると、新しい画像のファイル名に文字列
thumbnail_
が追加されます。また、外部からの読み取りと Cloud Storage への書き込みを可能にする権限が設定されます。
タスクハンドラの URL をセキュリティで保護する
データを変更するなど機密を扱う操作を実行するタスクは、外部ユーザーが直接呼び出すことができないように、保護する必要があります。タスクへのアクセス権を App Engine 管理者に制限することで、ユーザーがタスクの URL にアクセスできないようにして、タスクを保護できます。ただし、この制限は、App Engine アプリからのタスク リクエストには適用されません。
現在の例では、タスクハンドラには /tasks/
フォルダの URL が設定されています。/tasks/
フォルダへのアクセスを App Engine 管理者に制限するには、プロジェクトの web.xml
に次の行を追加します。
<security-constraint>
<web-resource-collection>
<web-resource-name>tasks</web-resource-name>
<url-pattern>/tasks/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
キューからの 1 つのタスクの削除
1 つのキューから 1 つのタスクを削除するには deleteTask()
を使用します。
private void removeTask(Queue queue, String taskName) {
queue.deleteTask(taskName); // remove a task from a queue
}
キューからのすべてのタスクの削除
1 つのキューからすべてのタスクを削除するには purge()
を使用します。パージでは、キュー内のすべてのタスクを削除するのに最大で 1 分かかることがあります。
private void purgeQueue(Queue queue) {
queue.purge(); // remove all tasks from a queue
}
キューからすべてのタスクを削除するのに 1 分かかることがあるため、そのキューに新しいタスクを追加する前に数秒待つ必要があります。
タスクキューの削除
タスクキューを削除するには、プロジェクトの queue.xml
ファイルからエントリを削除し、再デプロイします。
App Engine へのデプロイ
Maven を使用して App Engine にアプリをデプロイします。
プロジェクトのルート ディレクトリに移動し、次のように入力します。
mvn package appengine:deploy -Dapp.deploy.projectId=PROJECT_ID
PROJECT_ID は、Google Cloud プロジェクトの ID に置き換えます。pom.xml
ファイルですでにプロジェクト ID を指定している場合は、実行するコマンドに -Dapp.deploy.projectId
プロパティを含める必要はありません。
Maven によってアプリがデプロイされた後、次のように入力すると、新しいアプリでウェブブラウザのタブが自動的に開きます。
gcloud app browse
次のステップ
このガイドでは、タスクキューを使用して画像サムネイルを作成し、Cloud Storage に保存する方法を示していますが、この方法は Cloud Datastore や Cloud SQL などの他のストレージ サービスでも使用できます。