2012-08-29 7 views
20

私のコントロール下にない100,000の画像があります。これらの画像の中には、画像が境界まで伸びている点で優れているものもあれば、余白が余分にあるものもあります。jQueryを使用して自動的に画像の空白を切り取ります

余分な空白があると、ページがひどく見え、画面上の画像がすべて異なるサイズのように見えます。

あなたは私がここで何を意味するか見ることができます:

http://www.fitness-saver.com/uk/shop/mountain-bikes/

は私がのために狩りをされていることは画像をトリミングして、自動的に空白文字を除去するjQueryの方法です。

1)画像ごとに空白の量が異なる 2)画像の比率が異なる 3)画像を前処理する代わりにjavascriptを使用したい。

私はあなたが助けてくれることを願っています!

編集:画像の例は、http://images.productserve.com/preview/3395/128554505.jpgです。画像はさまざまなアフィリエイトサイトから来ており、間違いなく異なるドメインの画像であることに注意してください。

+1

実際に問題が発生した画像の1つを質問に追加することをお勧めします。あなたのサイトを効果的に宣伝しているので投票が終わることはありません。 –

+1

イメージをキャンバスに描画し、空白の列と行全体を削除し、イメージを同じサイズ(縦横比を保持)に再スケーリングすることができます。 – Prusse

+2

「画像を前処理するのではなく、JavaScriptを使用したい」 - なぜですか?なぜあなたは、サーバー側で一度だけ実行するのではなく、白いスペースを削除する必要がありますか? – h2ooooooo

答えて

41

画像における空白を分析するために、私が知っている唯一の方法は、canvasにそのイメージをロードすることである。

var img = new Image(), 
    $canvas = $("<canvas>"), // create an offscreen canvas 
    canvas = $canvas[0], 
    context = canvas.getContext("2d"); 

img.onload = function() { 
    context.drawImage(this, 0, 0); // put the image in the canvas 
    $("body").append($canvas); 
    removeBlanks(this.width, this.height); 
}; 

// test image 
img.src = 'http://images.productserve.com/preview/1302/218680281.jpg'; 

次に、getImageData()方法を使用します。このメソッドは、各ピクセルデータ(カラー)を検査するために使用できるImageDataオブジェクトを返します。

var removeBlanks = function (imgWidth, imgHeight) { 
    var imageData = context.getImageData(0, 0, canvas.width, canvas.height), 
      data = imageData.data, 
      getRBG = function(x, y) { 
         return { 
         red: data[(imgWidth*y + x) * 4], 
         green: data[(imgWidth*y + x) * 4 + 1], 
         blue: data[(imgWidth*y + x) * 4 + 2] 
         }; 
        }, 
      isWhite = function (rgb) { 
         return rgb.red == 255 && rgb.green == 255 && rgb.blue == 255; 
        }, 
      scanY = function (fromTop) { 
         var offset = fromTop ? 1 : -1; 

         // loop through each row 
         for(var y = fromTop ? 0 : imgHeight - 1; fromTop ? (y < imgHeight) : (y > -1); y += offset) { 

         // loop through each column 
         for(var x = 0; x < imgWidth; x++) { 
          if (!isWhite(getRBG(x, y))) { 
           return y;       
          }  
         } 
        } 
        return null; // all image is white 
       }, 
      scanX = function (fromLeft) { 
         var offset = fromLeft? 1 : -1; 

         // loop through each column 
         for(var x = fromLeft ? 0 : imgWidth - 1; fromLeft ? (x < imgWidth) : (x > -1); x += offset) { 

         // loop through each row 
         for(var y = 0; y < imgHeight; y++) { 
          if (!isWhite(getRBG(x, y))) { 
           return x;       
          }  
         } 
        } 
        return null; // all image is white 
       }; 


     var cropTop = scanY(true), 
      cropBottom = scanY(false), 
      cropLeft = scanX(true), 
      cropRight = scanX(false); 
    // cropTop is the last topmost white row. Above this row all is white 
    // cropBottom is the last bottommost white row. Below this row all is white 
    // cropLeft is the last leftmost white column. 
    // cropRight is the last rightmost white column. 
}; 

は、率直に言って、私は正当な理由のために、このコードをテストすることができませんでした:私は、悪名高い出くわしたセキュリティ例外「キャンバスクロスオリジン・データによって汚染されていますので、キャンバスから画像データを取得することができません。」 。

これはバグではなく、意図した機能です。 specsから:

toDataURL()、toDataURLHD()、toBlob()、getImageData()、及び getImageDataHD()メソッドフラグをチェックし、例外SecurityError 例外をスローするのではなく、クロスオリジンデータを漏洩します。

さらにデータ操作を防止する際drawImage()ロードファイルキャンバスの起源クリーンフラグがfalseに設定されるようになり、外部ドメイン、からこれが起こります。

私はあなたが同じ問題に遭遇するだろうかと思いますが、これはクライアント側で動作する場合であっても、とにかく、here is the code.

、私は性能面になりますどのように悲惨な想像することができます。だから、Janさんが言ったように、あなたが画像をダウンロードしてサーバー側で前処理することができれば、それは良いでしょう。


編集:私は自分のコードが実際に画像をトリミングするかどう見て興味があった、と確かにそれはありません。 enter image description here

あなたは前に述べたようにそれだけで、あなたのドメインからのイメージのために働くhere

それをチェックアウトすることができます。あなたがいないjsFiddleから、自分のドメインからコードを実行する必要があります、明らかに

// define here an image from your domain 
img.src = 'http://localhost/strawberry2.jpg'; 

:あなたは、白い背景を使用して独自の画像を選択して、最後の行を変更することができます。


EDIT2:あなたはトリミングと同じアスペクト比を維持するためにスケールアップしたい場合は、この

var $croppedCanvas = $("<canvas>").attr({ width: cropWidth, height: cropHeight }); 

// finally crop the guy 
$croppedCanvas[0].getContext("2d").drawImage(canvas, 
    cropLeft, cropTop, cropWidth, cropHeight, 
    0, 0, cropWidth, cropHeight); 

var $croppedCanvas = $("<canvas>").attr({ width: imgWidth, height: imgHeight }); 

// finally crop the guy 
$croppedCanvas[0].getContext("2d").drawImage(canvas, 
    cropLeft, cropTop, cropWidth, cropHeight, 
    0, 0, imgWidth, imgHeight); 

EDIT3を変更します。ブラウズで画像をトリミングする1つの方法このexcellent articleが説明するように、Webワーカーを使用して作業負荷を並列化することです。

+0

お返事ありがとうございました。 JavascriptとJSONPのような同等のセキュリティ対策はありませんか? –

+0

アフィリエイトサイトが画像URLをJSONとして返す場合は、JSONレスポンスをjavascript関数でラップしようとする可能性があります。http://en.wikipedia.org/wiki/JSONPまた、新しいHTML5のcrossorigin属性外部ドメインの画像を読むことができますが、サーバ(あなたの系列会社)は 'Access-Control-Allow-Origin'ヘッダを持つことで許可しなければなりません。https://developer.mozilla.org/en-US/docs/CORS_Enabled_Image私はその新しいプロパティをjsFiddleコードに導入しました –

+0

@DavidHilditch私の更新された回答を参照してください –

10

Jose Rui Santosで提供された偉大な答えに基づいて、私はちょうどimageオブジェクトをロードするjQueryライブラリなしで動作するようにコードを変更しました。

この関数の戻り値は、イメージ要素に直接使用されるクロップされたイメージデータのURLです。

/* 
    Source: http://jsfiddle.net/ruisoftware/ddZfV/7/ 
    Updated by: Mohammad M. AlBanna 
    Website: MBanna.info 
    Facebook: FB.com/MBanna.info 
*/ 

var myImage = new Image(); 
myImage.crossOrigin = "Anonymous"; 
myImage.onload = function(){ 
    var imageData = removeImageBlanks(myImage); //Will return cropped image data 
} 
myImage.src = "IMAGE SOURCE"; 



//-----------------------------------------// 
function removeImageBlanks(imageObject) { 
    imgWidth = imageObject.width; 
    imgHeight = imageObject.height; 
    var canvas = document.createElement('canvas'); 
    canvas.setAttribute("width", imgWidth); 
    canvas.setAttribute("height", imgHeight); 
    var context = canvas.getContext('2d'); 
    context.drawImage(imageObject, 0, 0); 

    var imageData = context.getImageData(0, 0, imgWidth, imgHeight), 
     data = imageData.data, 
     getRBG = function(x, y) { 
      var offset = imgWidth * y + x; 
      return { 
       red:  data[offset * 4], 
       green: data[offset * 4 + 1], 
       blue: data[offset * 4 + 2], 
       opacity: data[offset * 4 + 3] 
      }; 
     }, 
     isWhite = function (rgb) { 
      // many images contain noise, as the white is not a pure #fff white 
      return rgb.red > 200 && rgb.green > 200 && rgb.blue > 200; 
     }, 
       scanY = function (fromTop) { 
     var offset = fromTop ? 1 : -1; 

     // loop through each row 
     for(var y = fromTop ? 0 : imgHeight - 1; fromTop ? (y < imgHeight) : (y > -1); y += offset) { 

      // loop through each column 
      for(var x = 0; x < imgWidth; x++) { 
       var rgb = getRBG(x, y); 
       if (!isWhite(rgb)) { 
        if (fromTop) { 
         return y; 
        } else { 
         return Math.min(y + 1, imgHeight - 1); 
        } 
       } 
      } 
     } 
     return null; // all image is white 
    }, 
    scanX = function (fromLeft) { 
     var offset = fromLeft? 1 : -1; 

     // loop through each column 
     for(var x = fromLeft ? 0 : imgWidth - 1; fromLeft ? (x < imgWidth) : (x > -1); x += offset) { 

      // loop through each row 
      for(var y = 0; y < imgHeight; y++) { 
       var rgb = getRBG(x, y); 
       if (!isWhite(rgb)) { 
        if (fromLeft) { 
         return x; 
        } else { 
         return Math.min(x + 1, imgWidth - 1); 
        } 
       }  
      } 
     } 
     return null; // all image is white 
    }; 

    var cropTop = scanY(true), 
     cropBottom = scanY(false), 
     cropLeft = scanX(true), 
     cropRight = scanX(false), 
     cropWidth = cropRight - cropLeft, 
     cropHeight = cropBottom - cropTop; 

    canvas.setAttribute("width", cropWidth); 
    canvas.setAttribute("height", cropHeight); 
    // finally crop the guy 
    canvas.getContext("2d").drawImage(imageObject, 
     cropLeft, cropTop, cropWidth, cropHeight, 
     0, 0, cropWidth, cropHeight); 

    return canvas.toDataURL(); 
} 
+1

なぜあなたは+10を追加しましたか?あなたは私にバグを見つけようと多くの時間を失わせてしまった。 –

+0

@IvanCastellanos編集をありがとう!切り取った画像にテキストがあるため、コードに追加しました。右下に少しスペースが必要でした。そのために残念。 – Mohammad

関連する問題