blog

これからはじめる Gulp シリーズこれからはじめるGulp(16):gulp-image-resizeプラグインを使ってサムネイルやレスポンシブイメージを作る

    • Ryuichi Nonaka
    この記事は書かれてから1年以上経過しており、内容が古い場合があります。

    はじめに

    この記事はGulp.js(全俺) Advent Calendar 2014です。

    前回のこれからはじめるGulp(15):gulp-responsiveプラグインを使ったレスポンシブイメージ作成の自動化でNode.js向け画像処理ライブラリを使ったレスポンシブイメージ作成の自動化を行いました。今回はより手軽に使えるgulp-image-resizeプラグインを使いサムネイル画像を作ってみたいと思います。

    gulp-image-resizeについて

    gulp-image-resizeは画像のリサイズや切り抜きができるプラグインです。gulp-image-resizeを使うにはImageMagickGraphicsMagickが必要です。

    ImageMagick or GraphicsMagickのインストール

    どちらもHomebrewを使ってインストールします。どちらか一方でかまいませんが、ImageMagickを使うにはオプション指定が必要になります。今回はオプションの指定方法も説明するのであえてImageMagickを使います。

    ImageMagickのインストール方法

    今回はこちらをインストールします。

    $ brew install imagemagick
    

    Graphicsmagickのインストール方法

    $ brew install graphicsmagick
    

    gulp-image-resizeのインストール

    続いて、gulp-image-resizeプラグイン本体をインストールします。

    $ sudo npm install --save-dev gulp-image-resize
    Password:
    gulp-image-resize@0.5.0 node_modules/gulp-image-resize
    ├── async@0.2.10
    ├── through2@0.4.2 (xtend@2.1.2, readable-stream@1.0.33)
    ├── lodash@2.4.1
    ├── gulp-gm@0.0.7 (gm@1.17.0)
    └── gulp-util@2.2.20 (lodash._reinterpolate@2.4.1, minimist@0.2.0, vinyl@0.2.3, chalk@0.5.1, through2@0.5.1, multipipe@0.1.2, dateformat@1.0.11, lodash.template@2.4.1)
    

    サムネイルを作成するタスク

    141枚のスクリーンキャプチャを用意し、サムネイル画像を作ってみます。まずは横200px:縦200pxの画像の中心を基準にしたサムネイルを作成し、gulp-imageminプラグインと連携して軽量化するタスクを作ります。このタスクにはgulp-changedプラグインとと処理されたファイル名をログに流すgulp-filelogプラグインを使います。gulp-filelogを使うことでタスクの進捗を把握します。

    var gulp        = require('gulp');
    var changed     = require('gulp-changed'); 
    var filelog     = require('gulp-filelog');
    var imageResize = require('gulp-image-resize');
    var imagemin    = require('gulp-imagemin');
    
    var paths = {
      srcDir : 'src',
      prvDir : 'prv',
      dstDir : 'prd',
      uploadsDir: '/uploads'
    }
    
    gulp.task( 'image-optim:thumb', function(){
      var baseDir  = paths.srcDir + paths.uploadsDir + '/origin';
      var srcGlob  = paths.srcDir + paths.uploadsDir + '/origin/**/*.+(jpg|jpeg|png|gif)';
      var dstGlob  = paths.dstDir + paths.uploadsDir + '/thumb';
    
      var resizeOptions = {
        width       : 200,
        height      : 200,
        gravity     : 'Center',
        crop        : true,
        upscale     : false,
        imageMagick : true
      };
    
      var imageminOptions = {
        optimizationLevel: 7
      };
    
      return gulp.src( srcGlob, { base: baseDir } )
        .pipe(changed( dstGlob ))
        .pipe(imageResize( resizeOptions ))
        .pipe(imagemin( imageminOptions ))
        .pipe(gulp.dest( dstGlob ))
        .pipe(filelog());
    });
    

    リサイズオプションの指定はこのようになります。imageMagick : trueがImageMagickを使うための指定です。

      var resizeOptions = {
        width       : 200,
        height      : 200,
        gravity     : 'Center',
        crop        : true,
        upscale     : false,
        imageMagick : true
      };
    

    image-optim:thumbタスクの実行

    タスクを実行してみます(長すぎるので途中を省いています)。

    $ gulp image-optim:thumb
    [00:00:04] Using gulpfile ~/Projects/gulp.whiskers.nukos.kitchen/gulpfile.js
    [00:00:04] Starting 'image-optim:thumb'...
    [00:00:05] [1] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb/2014/08/gifbrewery/animation_gif.gif]
    [00:00:06] [2] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb/2014/08/gifbrewery/capture_tool.png]
    [00:00:08] [3] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb/2014/08/gr/gr_photo_001.jpg]
    [00:00:08] [4] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb/2014/08/gr/gr_photo_002.jpg]
    [00:00:09] [5] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb/2014/08/gifbrewery/crop.png]
    [00:00:10] [6] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb/2014/08/gifbrewery/open_gifbrewery.png]
    [00:00:10] [7] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb/2014/08/gifbrewery/gif_animation.png]
    [00:00:10] [8] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb/2014/06/start/thumbnail_960.png]
    [00:00:11] [9] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb/2014/09/monotony/kimonolabs.png]
    …
    [00:01:45] gulp-imagemin: Minified 141 images (saved 647.91 kB - 22%)
    [00:01:45] [141] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb/2014/11/high-performance-browser-networking-meetup/thumbnail.png]
    [00:01:45] Found [141] files.
    [00:01:45] Finished 'image-optim:thumb' after 1.68 min
    

    141個のサムネイル作成に1分45秒かかり、22%軽量化できました。[/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb/2014/09/monotony/kimonolabs.png]がgulp-filelogが出力したログです。もう一度タスクを実行するとgulp-chagedが効き処理が省略されます。

    $ gulp image-optim:thumb
    [02:52:40] Using gulpfile ~/Projects/gulp.whiskers.nukos.kitchen/gulpfile.js
    [02:52:40] Starting 'image-optim:thumb'...
    [02:52:41] gulp-imagemin: Minified 0 images (saved 0 B - 0%)
    [02:52:41] Found [0] files.
    [02:52:41] Finished 'image-optim:thumb' after 318 ms
    

    高解像度ディスプレイ用のサムネイルとミドルサイズの画像を作る

    追加で2種類の画像とオリジナル画像を軽量化するタスクを作ります。この3種類タスクは管理しやすくするため別々のタスクとします。

    400*400のサムネイルを作るタスク

    //create thumb 2x size
    gulp.task( 'image-optim:thumb-2x', function(){
      var baseDir  = paths.srcDir + paths.uploadsDir + '/origin';
      var srcGlob  = paths.srcDir + paths.uploadsDir + '/origin/**/*.+(jpg|jpeg|png|gif)';
      var dstGlob  = paths.dstDir + paths.uploadsDir + '/thumb-2x';
    
      var resizeOptions = {
        width       : 400,
        height      : 400,
        gravity     : 'Center',
        crop        : true,
        upscale     : false,
        imageMagick : true
      };
    
      var imageminOptions = {
        optimizationLevel: 7
      };
    
      return gulp.src( srcGlob, { base: baseDir } )
        .pipe(changed( dstGlob ))
        .pipe(imageResize( resizeOptions ))
        .pipe(imagemin( imageminOptions ))
        .pipe(gulp.dest( dstGlob ))
        .pipe(filelog());
    });
    

    ミドルサイズの画像を作るタスク

    //create middle size
    gulp.task( 'image-optim:middle', function(){
      var baseDir  = paths.srcDir + paths.uploadsDir + '/origin';
      var srcGlob  = paths.srcDir + paths.uploadsDir + '/origin/**/*.+(jpg|jpeg|png|gif)';
      var dstGlob  = paths.dstDir + paths.uploadsDir + '/middle';
    
      var resizeOptions = {
        width       : 960,
        upscale     : false,
        imageMagick : true
      };
    
      var imageminOptions = {
        optimizationLevel: 7
      };
    
      return gulp.src( srcGlob, { base: baseDir } )
        .pipe(changed( dstGlob ))
        .pipe(imageResize( resizeOptions ))
        .pipe(imagemin( imageminOptions ))
        .pipe(gulp.dest( dstGlob ))
        .pipe(filelog());
    });
    

    オリジナル画像を軽量化するタスク

    //optimize origin
    gulp.task( 'image-optim:origin', function(){
      var baseDir  = paths.srcDir + paths.uploadsDir + '/origin';
      var srcGlob  = paths.srcDir + paths.uploadsDir + '/origin/**/*.+(jpg|jpeg|png|gif|svg)';
      var dstGlob  = paths.dstDir + paths.uploadsDir + '/origin';
    
      var imageminOptions = {
        optimizationLevel: 7
      };
    
      return gulp.src( srcGlob, { base: baseDir } )
        .pipe(changed( dstGlob ))
        .pipe(imagemin( imageminOptions ))
        .pipe(gulp.dest( dstGlob ))
        .pipe(filelog());
    });
    

    それぞれのタスクを非同期処理させるようimage-optimというタスクを作ります。

    gulp.task( 'image-optim', ['image-optim:thumb', 'image-optim:thumb-2x', 'image-optim:middle', 'image-optim:origin']);
    

    image-optimタスクを実行する

    image-optimタスクですべての画像処理を実行します。4つのタスクが非同期で処理されます。

    $ gulp image-optim
    [02:57:08] Using gulpfile ~/Projects/gulp.whiskers.nukos.kitchen/gulpfile.js
    [02:57:08] Starting 'image-optim:thumb'...
    [02:57:08] Starting 'image-optim:thumb-2x'...
    [02:57:08] Starting 'image-optim:middle'...
    [02:57:08] Starting 'image-optim:origin'...
    [02:57:09] gulp-imagemin: Minified 0 images (saved 0 B - 0%)
    [02:57:09] Found [0] files.
    [02:57:09] Finished 'image-optim:thumb' after 1.06 s
    [02:57:09] [1] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/origin/2014/08/gifbrewery/animation_gif.gif]
    [02:57:10] [1] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/middle/2014/08/gifbrewery/animation_gif.gif]
    [02:57:10] [1] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb-2x/2014/08/gifbrewery/animation_gif.gif]
    [02:57:15] [2] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb-2x/2014/06/start/thumbnail_960.png]
    [02:57:49] [2] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/origin/2014/06/start/thumbnail_960.png]
    [02:57:50] [2] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/middle/2014/06/start/thumbnail_960.png]
    [02:57:54] [3] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/thumb-2x/2014/08/gifbrewery/capture_tool.png]
    ...
    [03:25:40] gulp-imagemin: Minified 141 images (saved 2.29 MB - 12.2%)
    [03:25:40] [141] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/middle/2014/11/high-performance-browser-networking-meetup/thumbnail.png]
    [03:25:40] Found [141] files.
    [03:25:40] Finished 'image-optim:middle' after 29 min
    [03:25:40] [136] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/origin/2014/11/ios_byword_and_ver22/iphone_preview.png]
    [03:25:42] [137] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/origin/2014/11/ios_byword_and_ver22/upload_success.png]
    [03:26:19] [138] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/origin/2014/10/hello-yosemite/vmware_error.png]
    [03:26:50] [139] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/origin/2014/10/hello-yosemite/thumbnail.png]
    [03:27:03] [140] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/origin/2014/11/high-performance-browser-networking-meetup/thumbnail.png]
    [03:27:28] gulp-imagemin: Minified 141 images (saved 11.44 MB - 34.9%)
    [03:27:28] [141] [/Users/ryuichi/Projects/gulp.whiskers.nukos.kitchen/prd/uploads/origin/2014/11/ios_byword_and_ver22/ipad_preview.png]
    [03:27:28] Found [141] files.
    [03:27:28] Finished 'image-optim:origin' after 30 min
    [03:27:28] Starting 'image-optim'...
    [03:27:28] Finished 'image-optim' after 27 μs
    

    すべてのタスクが完了するまで30分程度かかりました。オリジナルの画像が2000px以上の画像だったりするのでやはり時間がかかりました。初回はファイル量が多いため時間がかかってしまうのも仕方ありませんが、2回目以降は変更しれたファイルのみが対象となるためそれほど気にならなくなります。もう一度実行してみるとgulp-changedプラグインのおかげで一切の処理が実行されていません。

    $ gulp image-optim
    [03:35:07] Using gulpfile ~/Projects/gulp.whiskers.nukos.kitchen/gulpfile.js
    [03:35:07] Starting 'image-optim:thumb'...
    [03:35:07] Starting 'image-optim:thumb-2x'...
    [03:35:07] Starting 'image-optim:middle'...
    [03:35:07] Starting 'image-optim:origin'...
    [03:35:07] gulp-imagemin: Minified 0 images (saved 0 B - 0%)
    [03:35:07] Found [0] files.
    [03:35:07] Finished 'image-optim:origin' after 375 ms
    [03:35:07] gulp-imagemin: Minified 0 images (saved 0 B - 0%)
    [03:35:07] Found [0] files.
    [03:35:07] Finished 'image-optim:thumb-2x' after 383 ms
    [03:35:07] gulp-imagemin: Minified 0 images (saved 0 B - 0%)
    [03:35:07] Found [0] files.
    [03:35:07] Finished 'image-optim:thumb' after 396 ms
    [03:35:07] gulp-imagemin: Minified 0 images (saved 0 B - 0%)
    [03:35:07] Found [0] files.
    [03:35:07] Finished 'image-optim:middle' after 381 ms
    [03:35:07] Starting 'image-optim'...
    [03:35:07] Finished 'image-optim' after 8 μs
    

    これで、ドローツールに頼らずともサムネイル画像や画像のリサイズを行えるようになりました。明日からSketch 3との連携について紹介していきたいと思います。

    シリーズ

    1. これからはじめるGulp(0):アドベントカレンダースケジュール
    2. これからはじめるGulp(1):bundler, rbenv, nodebrewでGulp環境を作ってみる
    3. これからはじめるGulp(2):gulp-sassを使ってSCSSをコンパイルするタスクを作ってみる
    4. これからはじめるGulp(3):gulp.watchでファイルの変更を監視しタスクを実行する
    5. これからはじめるGulp(4):gulp-connectモジュールを使ったローカルサーバの起動
    6. これからはじめるGulp(5):gulp-connectモジュールを使ったLiveReload
    7. これからはじめるGulp(6):gulp-plumberとgulp-notifyを使ったデスクトップ通知
    8. これからはじめるGulp(7):require-dirモジュールを使ったタスク単位のファイル分割
    9. これからはじめるGulp(8):delモジュールとvinyl-pathsモジュールを使ったファイルの削除
    10. これからはじめるGulp(9):Ruby版Sassが使えるgulp-ruby-sassへの乗り換え
    11. これからはじめるGulp(10):deprecatedになっていたgulp-connectからgulp-webserverへ乗り換える
    12. これからはじめるGulp(11):ブラウザ間でスクロールやクリック操作を同期できるBrowserSync
    13. これからはじめるGulp(12):gulp-imageminプラグインを使ったJPEG,PNG,GIF,SVGの最適化
    14. これからはじめるGulp(13):gulp-changedプラグインで変更されたファイルだけを処理させる
    15. これからはじめるGulp(14):gulp-cachedプラグインで変更されたSCSSファイルだけを処理させる
    16. これからはじめるGulp(15):gulp-responsiveプラグインを使ったレスポンシブイメージ作成の自動化
    17. これからはじめるGulp(16):gulp-image-resizeプラグインを使ってサムネイルやレスポンシブイメージを作る
    18. これからはじめるGulp(17):SketchTool(Sketch 3 command line tool)を使ったアートボード・スライスの書き出しとgulp-execプラグインを使ったSketchtoolの呼び出し
    19. これからはじめるGulp(18):SketchToolで何ができるのかコマンドと主要なオプションを使ってみる
    20. これからはじめるGulp(19):gulp-sketchとgulp-execを使ったSketch 3デザインデータの画像書き出し
    21. これからはじめるGulp(20):Node.jsのChild Processモジュールを使ってgulpからjekyllのbuildコマンドを実行する
    22. これからはじめるGulp(21):gulp-awspublishプラグインを使ったAmazon S3への静的Webサイトパブリッシュ
    23. これからはじめるGulp(22):gulp-iconfontとgulp-sketchを使ったアイコンフォント作成の自動化
    24. これからはじめるGulp(23):gulp-consolidateでgulp-iconfontで作ったアイコンフォントのシンボル一覧HTMLを作る
    25. これからはじめるGulp(24):gulp.spritesmithプラグインでSpriteイメージを作る
    26. これからはじめるGulp(25):Hologramとgulp-hologramでスタイルガイドを作る
    27. これからはじめるGulp(26):Sketch3のサブディレクトリ書き出しに対応したgulp-sketchを試す

    コメント・フィードバック