Sharpサーバーサイド画像処理

【Node.js】 画像処理モジュールsharpの使い方を網羅してみました

更新日:2024/02/12

最近Node.jsで画像を処理する案件に遭遇しました。

その際にSharpというモジュールを使用しましたが、日本語の資料があまりないのでここでまとめておきます。

このページの目次

 

sharpのインストール

npmでsharpをインストールします。


npm install sharp

requireでロードします。


const sharp = require("sharp");

 

画像の読み込み

sharpの使い方を簡単に解説します。

既存画像のロード

sharp関数に画像へのパスを指定することで、既存画像を読み込みます。


const sharInstance = sharp( 画像パス );

返り値はsharpのインスタンスです。
sharpインスタンスメソッドの多くは、sharpインスタンスを返します。
下表のsharpインスタンスメソッドは引数でコールバックが省略されるとpromiseを返します。

Promiseを返すメソッド
metadata([callback])
stats([callback])
toFile(fileOut, [callback])
toBuffer([options], [callback])

Promiseを返すメソッドは、次のようにthen()やcatch()を使用できます。

thenで結果を受け取る


sharp( 画像パス )
   .stats(  )
   .then( e=>{} )
   .catch( e=>{} );

または、次のようにawaitで処理の終了を待つことができます。

awaitで終了を待つ


(async ()=>{

   ・・・なんらかの処理

    const metadata = await sharp( 画像パス )
                .stats(  );

   ・・・後に続く処理

})();

新規画像で初期化

新規で画像を作成する場合は、次のような引数を渡します。


sharp( {
    create: {
        width: 250,
        height: 80,
        channels: 4,
        background: { r: 255, g: 100, b: 100, alpha: 0.5 }
    }
} )
.toFile( 出力パス );

出力結果は次のようになります。

sharp create

■createのオブジェクトのプロパティ

createのオブジェクトは4つのプロパティを指定できます。

プロパティ名意味
width作成する無地画像の幅
height作成する無地画像の高さ
channelsチャネルの数。3または4。赤、青、緑、アルファ値で4
background無地画像の色

backgroundは、r,g,b,alphaをプロパティに持つオブジェクトです。
それぞれ赤、青、緑、アルファ値に対応しています。

赤、青、緑は0から255で、数字が大きいほど濃くなります。

アルファ値は0から1.0までの小数で、ピクセルの透明度を表します。
0が透明です。

この他に、カラー名またはカラーコードでの指定もできます。

■カラー名で指定
background : "red"

■カラーコードで指定
background : "#ff00"

ピクセルデータを読み込む

他から取得したり、自分で作成したピクセルデータを読み込むことができます。

自分でピクセルデータを作成する場合は、Uint8Array()を使用します。


    const LOGOHEIGHT = 80;
    const LOGOHWIDTH = 250;
    const LOGOCHANNEL = 4;
    const LINEBYTS = LOGOHWIDTH * LOGOCHANNEL;
    const LOGOBUFSIZE = LOGOHEIGHT * LINEBYTS;

        // バッファを確保
    const logoBuf = new Uint8Array( LOGOBUFSIZE ).fill(255);

    const rgba = {r:255,g:100,b:100,alpha:.5 * 255};

        // 一行目だけピクセルセット
    for( let i = 0 ; i < LOGOHWIDTH ; i += 10 ){
        const pos = i * LOGOCHANNEL;
        logoBuf[pos] = rgba.r;
        logoBuf[pos+1] = rgba.g;
        logoBuf[pos+2] = rgba.b;
        logoBuf[pos+3] = rgba.alpha;
    }

        // 一行目を1ピクセルずらしてコピー
    let start = LINEBYTS + LOGOCHANNEL;
    while( start < LOGOBUFSIZE ){
        logoBuf.copyWithin( start , 0 , LINEBYTS);
        start += LINEBYTS + LOGOCHANNEL;
    }
        // 下側半分の白地部分を透明化
    start = LOGOHWIDTH * LOGOHEIGHT/2 * LOGOCHANNEL;
    while( start < LOGOBUFSIZE ) {
        if( logoBuf[start+1] === 255)  logoBuf[start+3] = 0;
        start += 4;
    }

一つのピクセルは、赤、緑、青、アルファ値の4バイト使用します。
そのため画像一枚分は縦×横×4バイトになるので、その分だけ new Uint8Array( )で領域を確保し、白地にするために255で初期化しています。

そして、10ピクセル毎に斜め線を描くように、ピクセル値をセットしています。

なお、createのオブジェクトのアルファ値は0から1.0でしたが、ピクセル値の場合は0から255です。

次にsharpの第一引数にピクセルデータを、第二引数にオプション値を渡します。

オプション値は、rawオブジェクトをプロパティに持つオブジェクトです。


sharp( logoBuf , 
    {
        raw:{
            width:LOGOHWIDTH,
            height:LOGOHEIGHT,
            channels:LOGOCHANNEL,
        }
    } )
    .toFile( 出力パス );

rawオブジェクトはwidth、height、channelsをプロパティとして持ち、これらの値で、入力されたピクセルデータの縦横アルファ値を指定します。

出力結果は次のようになります。

sharp option raw

※透明度がわかりやすいように、背景に色をつけています。

ストリームからの読み込み

ストリームから画像を読み込むこともできます。


const fs = require("fs");
const readableStream = fs.createReadStream( 画像パス );

const sharpData = sharp( );

readableStream.pipe(sharpData);

sharpData.flip().toFile( 出力先画像パス );

複製を作成する

cloneメソッドを使用することで、sharpオブジェクトの複製を作成できます。

cloneメソッドを実行前に適用した処理(パラメーター)は、複製先に引き継がれます。


const sharpOrg =   sharp( 画像パス )
            .rotate( 45 ,
                {
                    background:{ r:200,g:250,b:250,alpha:1}
                }
            );
sharpOrg.clone().flip().toFile( 出力先画像パス ); // 1
sharpOrg.clone().flop().toFile( 出力先画像パス ); // 2

sharp clone
1で出力された画像
 
sharp clone
2で出力された画像

 

フォーマット変換・保存

画像をファイル保存(出力)する

toFileメソッドにファイルのパスを指定すると、画像を保存できます。


await sharp( 画像パス )
          .toFile( 出力先画像パス , ( err , info ) =>{
                            if( err ) { エラー処理 }
           });

出力形式は、画像パスの拡張子が考慮されます。

第二引数には、結果を受け取る関数を指定できます。

上の例では、読み込み直後に出力していますが、入力したファイルと出力ファイルは同じデータにはなりません。

例:
入力 image.png 115KB
出力 output.png 102KB ←サイズが減少した

一度画像を読み込んだ後、出力時に既定の品質で再フォーマットされているからです。

画像をバッファーに出力する

toBufferメソッドを使用すると、画像をバッファーに出力できます。
これにより、他のオブジェクトに画像データを渡すことができます。


const fs = require("fs").promises;

const imgBuffer = await sharp( 画像パス )
          .resize( 300 , 300 , { fit : "cover" } )
          .png( { progressive : true } )
          .toBuffer();

await fs.writeFile("output.png", imgBuffer);

上の例は、fsモジュール経由で画像データをファイル出力しています。

ストリームに出力する

ストリームに画像を出力することもできます。


    const fs = require("fs");

    const readableStream = fs.createReadStream( 画像パス );

    const sharpData = sharp( )
            .flip();
        
    const writeStream = fs.createWriteStream( 出力先画像パス );

    readableStream.on( "error" , err=>{
            writeStream.end();
        } );

    readableStream
            .pipe( sharpData )
            .pipe( writeStream );

フォーマット変換

toFormatメソッドを使用することで、出力形式を強制します。


await sharp( 画像パス )
          .toFormat( フォーマット名 )
          .toFile( 出力先画像パス);

フォーマット名には次の値が使用できます。
"heic","heif","avif","jpeg","jpg","png","raw","tiff","webp","gif"

PNGに変換

pngメソッドを実行すると出力形式がPNGに変更されます。
品質等を指定できます。


await sharp( 画像パス )
          .png( { progressive : true } )
          .toFile( 出力先画像パス );

pngの引数は、次のプロパティを持つオブジェクトです。
省略可能です。

プロパティ意味規定値
progressiveプログレッシブ(インターレース)スキャンを使用するfalse
compressionLevelzlib圧縮レベル 0から99
adaptiveFiltering適応行フィルタリングを使用するかどうかfalse
paletteアルファ透明度をサポートするパレットベースの画像にクオンタイズする。false
quality与えられた品質を達成するために必要な最小の色数。100
coloursパレットエントリの最大数。256
colorscoloursのの代替スペル256
ditherフロイド-スタインバーグ誤差拡散のレベル。
forcetoFile()などの出力時PNG出力を強制。それ以外の場合は、入力形式を使用。true

JPEGに変換

jpegメソッドを実行すると出力形式がJPEGに変換されます。
品質等を指定できます。


await sharp( 画像パス )
          .jpeg( 引数 )
          .toFile( 出力先画像パス );

jpegの引数は、次のプロパティを持つオブジェクトです。
省略可能です。

プロパティ意味規定値
quality品質。1から10080
progressiveプログレッシブ(インターレース)スキャンを使用するfalse
chromaSubsamplingクロマサブサンプリングを防ぐには"4:4:4"に設定する。"4:2:0"
optimiseCodingハフマン符号化テーブルを最適化するtrue
optimizeCodingoptimiseCodingの代替スペルtrue
trellisQuantisation格子量子化を適用するfalse
overshootDeringingオーバーシュートデリンギングを適用false
optimiseScansプログレッシブスキャンを最適化し、プログレッシブを強制するfalse
optimizeScansoptimiseScansの代替スペルfalse
quantisationTable使用する量子化テーブル、整数0から80
quantizationTablequantisationTableの代替スペル0
forcetoFile()などの出力時JPEGを強制。それ以外の場合は、入力形式を使用。true

WEBPに変換

webpメソッドを実行すると出力形式をWEBPに変更できます。
品質等を指定できます。


await sharp( 画像パス )
          .webp( 引数 )
          .toFile( 出力先画像パス );

webpの引数は、次のプロパティを持つオブジェクトです。
省略可能です。

プロパティ意味規定値
quality品質。1から10080
alphaQualityアルファレイヤーの品質。0から100100
lossless可逆圧縮(ロスレス)モードを使用するfalse
nearLosslessニアロスレスモードを使用するfalse
smartSubsample高品質クロマサブサンプリングを使用するfalse
reductionEffortファイルサイズ削減のCPU稼働レベル。0から64
pageHeightアニメーション出力のページの高さfalse
loopアニメーションの繰り返し回数。0は無限回数0
delayアニメーションフレーム間の遅延のリスト(ミリ秒の配列)
forcetoFile()などの出力時WEBPを強制。それ以外の場合は、入力形式を使用。true

ピクセルデータに変換

rawメソッドを実行すると出力形式を生のピクセルデータに変更します。
1ピクセルは、ピクセルデータ内に符号なし8ビットデータをチャネル数分連続で所持します。

引数はありません。


await sharp( 画像パス )
          .raw( )
          .toFile( 出力先画像パス );

その他の変換

jpeg()などの他に、gif()、tiff()、avif()、heif()、raw()が用意されています。
使用頻度が少ないと思われるので、ここでは紹介しません。

色空間(カラースペース)の変更

toColourspaceまたはtoColorspaceメソッドを使用すると、出力時の色空間を指定できます。

第一引数に、色空間名を指定します。
例:"srgb"、"rgb"、 "cmyk"、 "lab"、"b-w"、"cmc"、"rgb16"、"grey16"、"hsv"等


await sharp( 画像パス )
          .toColourspace( "cmyk" )
          .toFile( 出力先画像パス );

 

画像サイズ(縦横)を変更する

画像の縦横サイズを変更するには、resizeメソッドを使用します。


await sharp( 画像パス )
          .resize( 300 , 300 , { fit : "cover" } )
          .toFile( 出力先画像パス );

resizeの第一・第二引数は幅、高さの順で指定します。

第三引数は省略可能で、次のプロパティを持つオブジェクトです。

プロパティ意味規定値
width第一引数と同じ。こちらが優先
height第二引数と同じ。こちらが優先
fitwidthとheightに合わせて画像を変更する方法。"cover", "contain", "fill", "inside", "outside"のどれか

fitの適用例参照

"cover"
positionfitが"cover"または "contain"のときの位置。

"center","centre","north","east","south","west","northeast","southeast","southwest","northwest","top","right","bottom","left","right top","right bottom","left bottom","left top","entropy","attention"のどれか
positionの適用例参照

"centre"
backgroundfitが"contain"のときの背景色{r: 0, g: 0, b: 0, alpha: 1}
kernel画像縮小に使用するカーネル

"nearest","cubic","mitchel","lanczos2","lanczos3"のどれか

"lanczos3"
withoutEnlargement現在の幅または高さが指定値よりも小さい場合は拡大しない。これはGraphicsMagickの ">"ジオメトリオプションと同等。false
fastShrinkOnLoadJPEGおよびWebPのロード時縮小機能をさらに活用する。これにより、一部の画像でわずかなモアレパターンが発生する可能性がある。true

fitの適用例

次のサイズ100×100画像を、width70、height30でresizeを実行したときの適用結果です。

けーちゃん

fitの値適用結果出力サイズ
coversharp resize fit cover70×30
containsharp resize fit contain70×30
fillsharp resize fit fill70×30
insidesharp resize fit inside30×30
outsidesharp resize fit outside70×70

positionの適用例

positionの値fit:"contain"fit:"cover"
70×3030×7070×3030×70
centersharp resize fit contain position centersharp resize fit contain position centersharp resize fit cover position centersharp resize fit cover position center
centresharp resize fit contain position centresharp resize fit contain position centresharp resize fit cover position centresharp resize fit cover position centre
northsharp resize fit contain position northsharp resize fit contain position northsharp resize fit cover position northsharp resize fit cover position north
eastsharp resize fit contain position eastsharp resize fit contain position eastsharp resize fit cover position eastsharp resize fit cover position east
southsharp resize fit contain position southsharp resize fit contain position southsharp resize fit cover position southsharp resize fit cover position south
westsharp resize fit contain position westsharp resize fit contain position westsharp resize fit cover position westsharp resize fit cover position west
northeastsharp resize fit contain position northeastsharp resize fit contain position northeastsharp resize fit cover position northeastsharp resize fit cover position northeast
southeastsharp resize fit contain position southeastsharp resize fit contain position southeastsharp resize fit cover position southeastsharp resize fit cover position southeast
southwestsharp resize fit contain position southwestsharp resize fit contain position southwestsharp resize fit cover position southwestsharp resize fit cover position southwest
northwestsharp resize fit contain position northwestsharp resize fit contain position northwestsharp resize fit cover position northwestsharp resize fit cover position northwest
topsharp resize fit contain position topsharp resize fit contain position topsharp resize fit cover position topsharp resize fit cover position top
rightsharp resize fit contain position rightsharp resize fit contain position rightsharp resize fit cover position rightsharp resize fit cover position right
bottomsharp resize fit contain position bottomsharp resize fit contain position bottomsharp resize fit cover position bottomsharp resize fit cover position bottom
leftsharp resize fit contain position leftsharp resize fit contain position leftsharp resize fit cover position leftsharp resize fit cover position left
right-topsharp resize fit contain position right-topsharp resize fit contain position right-topsharp resize fit cover position right-topsharp resize fit cover position right-top
right-bottomsharp resize fit contain position right-bottomsharp resize fit contain position right-bottomsharp resize fit cover position right-bottomsharp resize fit cover position right-bottom
left-bottomsharp resize fit contain position left-bottomsharp resize fit contain position left-bottomsharp resize fit cover position left-bottomsharp resize fit cover position left-bottom
left-topsharp resize fit contain position left-topsharp resize fit contain position left-topsharp resize fit cover position left-topsharp resize fit cover position left-top
entropysharp resize fit contain position entropysharp resize fit contain position entropysharp resize fit cover position entropysharp resize fit cover position entropy
attentionsharp resize fit contain position attentionsharp resize fit contain position attentionsharp resize fit cover position attentionsharp resize fit cover position attention

 

画像の合成

画像の合成は、sharp関数の戻り値に対してcompositeメソッドを実行します。
compositeメソッドの引数は、複数のオブジェクトの配列で指定します。

他の画像との合成

inputプロパティに画像ファイルへのパスを指定すると、画像を読み込んで合成できます


await sharp( 画像バス )
           .composite([ {
                        input: 画像バス ,
                        blend: "over",
                        top:100,
                        left:100,
            } ] )
          .toFile( 出力先画像パス );

topとleftの代わりに、gravityが使用できます。
例:{ gravity : "east" }

値は、"center","centre","north","east","south","west","northeast","southeast","southwest","northwest"で、それぞれの方位(東西南北)に寄せることができます。

blendは、下地となる画像との合成方法を指定します。
次の値が使用できます。
"clear","source","over"(規定値),"in","out","atop","dest","dest-over","dest-in","dest-out","dest-atop","xor","add","saturate","multiply","screen","overlay","darken","lighten","colour-dodge","color-dodge","colour-burn","color-burn","hard-light","soft-light","difference","exclusion"
意味はこちらを参考にしてみてください。

下の例を見るとわかりますが、かけ合わせる画像の範囲ではなく、下地となる画像の全領域が対象となります。
場合によっては真っ黒になるので、注意が必要です。

blendの指定例

blendの例として、2つの画像を合成してみます。

【下地画像】
合成下地

【合成画像】
けーちゃん

blend値合成結果blend値合成結果
clearsharp composite blend clearmultiplysharp composite blend multiply
sourcesharp composite blend sourcescreensharp composite blend screen
over

規定値

sharp composite blend overoverlaysharp composite blend overlay
insharp composite blend indarkensharp composite blend darken
outsharp composite blend outlightensharp composite blend lighten
atopsharp composite blend atopcolour-dodgesharp composite blend colour-dodge
destsharp composite blend destcolor-dodgesharp composite blend color-dodge
dest-oversharp composite blend dest-overcolour-burnsharp composite blend colour-burn
dest-insharp composite blend dest-incolor-burnsharp composite blend color-burn
dest-outsharp composite blend dest-outhard-lightsharp composite blend hard-light
dest-atopsharp composite blend dest-atopsoft-lightsharp composite blend soft-light
xorsharp composite blend xordifferencesharp composite blend difference
addsharp composite blend addexclusionsharp composite blend exclusion
saturatesharp composite blend saturate

複数画像の合成

次のようにオブジェクトを複数指定することで、複数画像を合成できます。


await sharp( 画像バス )
           .composite([ 
                  {
                    input: 画像パス ,
                    gravity:"northwest",
                }, {
                    input: 画像パス ,
                    gravity:"northeast",
                    blend:"overlay"
                },{
                    input: 画像パス ,
                    gravity:"southwest",
                    blend:"colour-dodge"
                },{
                    input: 画像パス ,
                    gravity:"southeast",
                    blend:"exclusion"
                },
           ] )
          .toFile( 出力先画像パス );

sharp composite input 複数

上の例は同じ画像ファイルを読み込んでいますが、異なるファイルでも問題ありません。

画像をタイル状に合成する

compositeに渡すオブジェクトにtitleプロパティを指定すると、合成画像をタイル表示できます。

まずはタイルなしバージョン。


await  sharp( 画像パス )
            .composite([ {
                input: 合成画像パス,
                top:20,
                left:100,
            } ])
            .toFile( 出力先パス );

上のコードで、昔のけーちゃんみたいに河原でたそがれている男性の後ろ姿に、このサイトのロゴを貼り付けた結果がこちら。

sharp composite tile false

次に、タイル表示してみます。


await  sharp( 画像パス )
            .composite([ {
                input: 合成画像パス,
                top:20,
                left:100,
                tile:true,
            } ])
            .toFile( 出力先パス );

sharp composite tile true

タイル表示できましたが、間隔が狭すぎてごちゃっとしたイメージですね。
しかし、画像と画像の間隔指定ができないので、調整するにはタイル表示する画像を編集する必要があります。

あと注意する点が、topとleftの扱いです。

タイル表示なしの場合、下地画像の座標位置に、ロゴ画像を貼り付けています。

しかしタイル表示ありの場合、今回は資料を探すことができなかったのですが実行結果を見てみると、topとleftはタイル表示する画像上の座標位置をとして扱い、この位置と下地画像の左上を合わせているようです。

新規画像(無地)の合成

compositeに渡すオブジェクトのinputプロパティに、createプロパティを持っているオブジェクトを指定すると、無地画像を合成できます。


await  sharp( 画像パス )
            .composite([
               {
                   input: {
                        create:{
                            width:250 , height:80 , channels:4,
                            background:{r:255,g:100,b:100,alpha:.5}
                    }
                },
                top:20 , left:100,
              },
            ])
            .toFile( 出力先パス );

createのオブジェクトについては、こちらを見てください。

例として、無地画像と画像をタイル状に合成するの画像を使用して、ロゴ画像の下にボックスを描画してみます。


await  sharp( 画像パス )
            .composite([ {
                input: {
                    create:{
                        width:250,
                        height:80,
                        channels:4,
                        background:{r:255,g:100,b:100,alpha:.5}
                    }
                },
                top:20,
                left:100,
            },{
                input: 合成画像パス,
                top:20,
                left:100,
                tile:true,
            } ])
            .toFile( 出力先パス );

sharp composite input create

いい感じにタイトルっぽくなりました。

ピクセルデータを作成して合成

ピクセルデータの合成もできます。

合成するピクセルデータは、input及び、rawプロパティで指定します。


await  sharp( 画像パス )
            .composite([ {
                input: logoBuf,
                raw:{
                    width:LOGOHWIDTH,
                    height:LOGOHEIGHT,
                    channels:4,
                },
                top:20,
                left:100,
            },{
                input: 合成画像パス,
                top:20,
                left:100,
                tile:true,
            } ])
            .toFile( 出力先パス );

ここで読み込んでいるピクセルデータは、ピクセルデータを読み込むで作成しているものです。

結果は次のようになります。

sharp composite raw

わかりにくいですが、ロゴの下半分だけ透過しています。

SVGデータの合成

SVGデータはBuffer.fromメソッドを経由して、compositeメソッドに渡します。


await sharp( 画像バス )
           .composite([ {
                        input: Buffer.from( SVGデータ ),
                        blend: "over",
                        top:100,
                        left:100,
            } ] )
          .png( { progressive : true } )
          .toFile( 出力先画像パス );

text-to-svgモジュールを使用して文字列を描画することもできます。


    const TextToSVG = require("text-to-svg");

    const outputText = "お腹すいたなぁ・・・";
    const svgOptions = {x: 0, y: 0, fontSize: 40, anchor: "left  top", attributes: {fill: "white", stroke: "black"}};

    const svgBuffer = TextToSVG.loadSync().getSVG(outputText, svgOptions);

    sharp( 画像バス )
            .composite([ {
                input: Buffer.from( svgBuffer ),
                top:200,
                left:80,
            },{
                input: 合成画像パス,
                top:20,
                left:100,
            }  ])
            .toFile( 出力先パス );

結果は次のようになります。

sharp svg

文字の合成については別の記事で紹介しているので、そちらを見てください。
【Node.js】 既存画像に文字を描画し圧縮して出力する

 

画像情報の取得

画像メタデータの取得

metadataメソッドを使用すると、画像が持っているメタデータを取得できます。


sharp( 画像バス )
            .metadata( (err,metadata) =>{
                if( err ) { エラー処理 }
                console.log( metadata);
            });

Promiseを使用すると、次のようになります。


sharp( 画像バス )
            .metadata( )
            .then( metadata =>{
                     console.log( metadata);
                },err => {
                   エラー処理
                });

■出力結果


{
  format: 'jpeg',
  width: 500,
  height: 333,
  space: 'srgb',
  channels: 3,
  depth: 'uchar',
  density: 72,
  chromaSubsampling: '4:2:0',
  isProgressive: true,
  hasProfile: false,
  hasAlpha: false
}

ピクセル情報の取得

statsメソッドを使用すると、画像のピクセル情報を取得できます。


sharp( 画像バス )
            .stats( (err,metadata) =>{
                if( err ) { エラー処理 }
                console.log( metadata);
            });

Promiseを使用すると、次のようになります。


sharp( 画像バス )
            .stats( )
            .then( metadata =>{
                     console.log( metadata);
                },err => {
                   エラー処理
                });

■出力結果


{
  channels: [
    {
      min: 1,
      max: 255,
      sum: 28100568,
      squaresSum: 5649201036,
      mean: 168.7721801801802,
      stdev: 73.79105130026998,
      minX: 302,
      minY: 304,
      maxX: 92,
      maxY: 0
    },
    {
      min: 0,
      max: 255,
      sum: 28473774,
      squaresSum: 5856332986,
      mean: 171.01365765765766,
      stdev: 76.99049020788779,
      minX: 290,
      minY: 272,
      maxX: 18,
      maxY: 0
    },
    {
      min: 0,
      max: 255,
      sum: 26903409,
      squaresSum: 5486401443,
      mean: 161.58203603603604,
      stdev: 82.72029222291602,
      minX: 200,
      minY: 182,
      maxX: 28,
      maxY: 0
    }
  ],
  isOpaque: true,
  entropy: 7.19947114540264,
  sharpness: 2.462638259245144,
  dominant: { r: 248, g: 248, b: 248 }
}

 

画像処理

ここでは次の画像を例として、sharpで実行できる画像処理を紹介します。

sharp画像処理用画像
画像サイズ:300×199

なお、これらのメソッドは各パラメータをセットするだけです。
処理は後で行われます。
そのため、rotateを複数呼び出すなどしても、回転処理が適用されるのは基本的に一度だけです。

回転処理

rotateメソッドを使用すると、画像を回転できます。
第一引数に角度、オプションで第二引数に背景色を指定できます。


sharp( 画像パス )
            .rotate( 317 , 
                   { 
                      background:{ r:200,g:150,b:150,alpha:1}
                  }
             )
            .toFile( 出力パス )

sharp rotate

画像サイズそのままで回転するので、出力サイズは355×350と大きくなりました。

垂直方向に反転

flipメソッドで、垂直方向に反転するかどうか指定できます。

第一引数に反転するかどうかの真偽値を指定します。
省略時はtrueです。


sharp( 画像パス )
            .rotate( 317 , { background:{ r:200,g:150,b:150,alpha:1}})
            .flip()
            .toFile( 出力パス )

sharp rotate

sharp flip

水平方向に反転

flipメソッドで、垂直方向に反転するかどうか指定できます。

第一引数に反転するかどうかの真偽値を指定します。
省略時はtrueです。


sharp( 画像パス )
            .rotate( 317 , { background:{ r:200,g:150,b:150,alpha:1}})
            .flop()
            .toFile( 出力パス )

sharp rotate

sharp flip

アフィン変換をおこなう

affineメソッドを使用することで、画像のピクセル位置をアフィン変換で移動します。

第一引数は要素数4の配列または2×2の2次元配列です。

この配列により、次のように変換されます。(配列は2次元配列とする)

変換後X = 配列[0][0] * (x + idx) + 配列[0][1] * (y + idy) + odx
変換後Y = 配列[1][0] * (x + idx) + 配列[1][1] * (y + idy) + ody

idx、idy、odx、odyはオプションで指定でき、デフォルトで0です。


sharp( 画像パス )
            .affine([[1, 0.5], [0.2, 0.4]], {
                background: "#f0a0a0",
            })
            .toFile( 出力先画像パス );

sharp affine

■affineのオプション

プロパティ名意味初期値
background背景色"#000000"
idx入力水平オフセット0
idy入力垂直オフセット0
odx出力水平オフセット0
ody出力垂直オフセット0
interpolator補間オプションの変更sharp.interpolators.bicubic

■sharp.interpolatorsのプロパティ

オプションinterpolatorには、次の値を使用できます。

sharp.interpolators.nearest
http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation

sharp.interpolators.bilinear
http://en.wikipedia.org/wiki/Bilinear_interpolation

sharp.interpolators.bicubic(デフォルト)
http://en.wikipedia.org/wiki/Bicubic_interpolation

sharp.interpolators.locallyBoundedBicubic
https://github.com/jcupitt/libvips/blob/master/libvips/resample/lbb.cpp#L100

sharp.interpolators.nohalo
http://eprints.soton.ac.uk/268086/

sharp.interpolators.vertexSplitQuadraticBasisSpline
https://github.com/jcupitt/libvips/blob/master/libvips/resample/vsqbs.cpp#L48

画像をシャープにする

sharpenメソッドを使用すると、画像をシャープにできます。

このメソッドは引数を3つ受け取ります。
引数なしで実行すると、穏やかなシャープネスを高速で実行する。

順番引数名意味規定値
1sigmaガウスマスクのシグマ。

0.01から10000。またはマイルドなシャープを実行するか(真偽値)。
LAB色空間でLチャネルのより遅くより正確なシャープネスを実行

2flat「平らな」領域に適用するシャープネスのレベル。

0から10000。

1.0
jagged「ギザギザ」の領域に適用するシャープネスのレベル。

0から10000。

2.0

sharp( 画像パス )
            .sharpen(100, 100, 0)
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp sharpen

画像のノイズを除去

medianメソッドを使用すると、メディアンフィルタで画像のノイズを除去します。

このメソッドはマスクサイズを引数として受け取ります。
引数は省略でき、規定値は3です。


sharp( 画像パス )
            .median(10)
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp median

画像をぼかす

blurメソッドを使用すると、画像をぼかすことができます。

このメソッドはガウスマスクのシグマを表す0.3から1000の値を引数として受け取ります。
引数は省略すると、高速で穏やかなぼかしを実行します。


sharp( 画像パス )
            .blur(10)
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp blur

透明なチャネルとマージする

flattenメソッドは、アルファ透明チャンネルがある場合にbackgroundとマージします。

このメソッドはbackgroundプロパティ値を持つオブジェクトを引数として受け取ります。
引数は省略すると、{r:0,g:0,b:0}が規定値となります。


sharp( 画像パス.png )
            .toFile( {background:"blue"} )
            .toFile( 出力先画像パス.png );

sharp画像処理用画像 透明化済み

sharp blur

※不透明化後、pngで出力したものを入力画像として使用しています。

ガンマ補正をおこなう

gammaメソッドを使用すると、ガンマ補正をおこなうことができます。

このメソッドは引数を2つ受け取ります。
第二引数が省略された場合、第一引数は入力および出力ガンマ値の両方の設定値となります。
第二引数が指定された場合、第一引数が入力、第二引数が出力ガンマ値となります。

引数が指定されなかった場合は、規定値が2.2となります。


sharp( 画像パス )
            .gamma( 1 , 3 )
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp gamma

ネガを生成

negateメソッドを使用すると、ネガを生成かどうか指定できます。

第一引数にネガを生成するかどうかの真偽値を指定します。
省略時はtrueです。


sharp( 画像パス )
            .negate(  )
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp negate

画像の輝度を正規化

normaliseメソッドおよびnormalizeメソッドは、ダイナミックレンジ全体をカバーするように輝度を伸ばすことで、出力画像のコントラストを強化します。

第一引数にネガを正規化するかどうかの真偽値を指定します。
省略時はtrueです。


sharp( 画像パス )
            .normalise(  )
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp normalise

コンボリューション(たたみ込み)処理をおこなう

convolveメソッドは、指定された情報をもとにたたみ込み処理をおこないます。

このメソッドは、プロパティを5つもつオブジェクトを引数として受け取ります。

順番プロパティ名意味規定値
1kernelカーネル値を含む要素数width * heightの配列
2widthkernelの幅(ピクセル単位) 3から1001
3heightkernelの高さ(ピクセル単位) 3から1001
4scale

(省略可)

kernelのスケール(ピクセル単位)kernelの要素の合計
5offset

(省略可)

kernelのオフセット(ピクセル単位)0

※kernel.length === width * height を満たす必要があります。


sharp( 画像パス )
            .convolve({
                width:3,
                height:3,
                kernel:[ 1 , -2 , -1 , 1 , -1 , 0 , 2 , -1 , 1],
            })
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp convolve

しきい値処理をおこなう

thresholdメソッドは、しきい値以上のピクセル値に255をセット、または現在の値を保持し、それ以外は0をセットします。

このメソッドは、2つの引数を受け取ります。

第一引数は、しきい値です。0,から255で指定します。

第二引数は省略可能で、greyscaleまたはgrayscaleプロパティを持つオブジェクトを指定します。
greyscaleまたはgrayscaleがtrueのときピクセル値に255がセットされます。
falseのときは、色が保持されます。
規定値は、trueです。


sharp( 画像パス )
            .threshold(200)
            .toFile( 出力先画像パス );

sharp( 画像パス )
            .threshold( 200 , { greyscale:false } )
            .toFile( 出力先画像パス );

sharp threshold true
greyscale : true(指定なし)
 
sharp threshold false
greyscale : false

画像間のビット演算をおこなう

booleanメソッドは、指定された画像とビット演算をおこないます。

このメソッドは3つの引数を持ちます。

順番引数名意味規定値
1operand演算対象の画像。パスや画像バッファー、ピクセルデータなどで指定
2operator演算方法。"and"、"or"、 "eor"のどれか
3options入力がピクセルデータのときにrawオブジェクトをプロパティに持つオブジェクトを指定

sharp( 画像パス )
            .boolean( 演算用画像 , "and" )
            .toFile( 出力先画像パス );

次の2枚をビット演算します。
2枚目は、白地で1枚目と同サイズです。

sharp画像処理用画像

 
sharp画像処理用画像2

■結果

sharp boolean

レベル調整をおこなう

linearメソッドは、一次方程式a * input + bを画像に適用し、レベル調整をおこないます。

inputは、ピクセルの値。

aは第一引数で、規定値は1.0。
bは第二引数で、規定値は0.0です。
両引数とも、省略可能です。


sharp( 画像パス )
            .linear( 2 , -25 )
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp linear

画像をマトリクスで組み替える

recombメソッドは、3×3の配列で画像を組み替えます。

配列は第一引数で指定します。


sharp( 画像パス )
            .recomb( [
                [ 1.2222 , 0.3333 , 0.12345 ],
                [ 0.1234 , 1.2345 , 0.44444 ],
                [ 1.0101 , 0.2020 , 1.30303 ]
            ])
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp recomb

明るさ、彩度、色相の回転で画像を変換

modulateメソッドは、明るさ、彩度、色相の回転を使用して画像を変換します。

引数は、3つのプロパティを持つオブジェクトを一つ指定します。

順番引数名意味規定値
1brightness明るさに乗算する値1
2saturation彩度に乗算する値1
3hue色相の回転角度0

sharp( 画像パス )
             .modulate({
                brightness:1.3,
                hue:126,
            })
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp modulate

画像に色を付ける

tintメソッドは、輝度を維持しながら、指定した色の彩度を使用して画像に色を付けます。

引数は、色を表す値です。


sharp( 画像パス )
            .tint("blue")
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp tint

グレイスケールに変換

greyscaleまたはgrayscaleメソッドを使用すると、8ビットのグレイスケールに変換するかどうかを指定できます。。

第一引数に変換するかどうかの真偽値を指定します。
省略時はtrueです。


sharp( 画像パス )
            .greyscale(  )
            .toFile( 出力先画像パス );

sharp画像処理用画像

sharp greyscale

 

チャネル操作

処理は後でまとめて行われるため、処理をする順番はあまり意味がありません。
ensureAlphaメソッドでアルファチャネルを追加した後、extractChannelメソッドでアルファチャネルを抜き出そうとしてもエラーが出る可能性があります。

アルファチャネルを削除する

removeAlphaメソッドは、アルファチャネルを削除します。


sharp( 画像パス.png )
            .removeAlpha( )
            .toFile( 出力先画像パス.png );

sharp 画像処理用画像 透明化済み
半透明な
画像
sharp removeAlpha
アルファチャネル削除
したため透明解除

アルファチャネルを追加する

ensureAlphaメソッドは、アルファチャネルを追加して、255をセットします。

次の例は、jpg画像を読み込み不透明化し、pngで出力しています。


sharp( 画像パス.jpg )
            .ensureAlpha()
            .raw()
            .toBuffer( (err, data, info) =>{
                const length = data.length;
                for( let i = 3; i < length ; i+=4 ) data[i] = 0.2 * 255;
                sharp( data , { raw:{ width:info.width , height:info.height , channels:4}})
                    .toFile( 画像パス.png );
            });

sharp画像処理用画像
sharp ensureAlpha

チャネルを抜き出す

extractChannelは指定したチャネルを抜き出し、他のチャネルを同じ値に置き換えます。

チャネルは第一引数に"red"、 "green"、 "blue"、 "alpha"で指定します。


sharp( 画像パス )
            .extractChannel("red")
            .toFile( 画像パス );

sharp画像処理用画像
sharp extractChannel

チャネルを追加する

joinChannelは指定した画像データのチャネルを追加します。
複数チャネルがある場合でも、単純に追加されます。

例えば元となる画像のチャネル数が3で、追加指定した画像のチャネル数が4なら合計で7チャネルになります。

次のコードは、追加する画像の赤チャネルを抜き出し、元となる画像のアルファチャネルに追加しています。


sharp( 追加する画像のパス )
            .extractChannel("red")
            .toColourspace("b-w")
            .raw()
            .toBuffer((err, data, info)=>{
                sharp( 画像パス )
                    .joinChannel( data , { raw:{width:info.width,height:info.height,channels:1 }} )
                    .toFile( 出力先パス.png );
            });

toColourspace("b-w")でチャネル数を1にしているため、toBufferで受け取るチャネルが一つのみになります。

■追加する画像

追加する画像

■結果

sharp画像処理用画像
sharp joinChannel

全チャネルをビット演算する

bandboolは画像内の全チャネルをビット演算子、結果を全チャネルにセットします。
チャネルは第一引数に"and"、 "or"、 "eor"で指定します。


sharp( 画像パス )
            .toFile("and")
            .toFile( 画像パス );

sharp画像処理用画像
sharp bandbool

更新日:2024/02/12

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。