2012-08-29 39 views
20

Tôi có 100.000 hình ảnh không thuộc quyền kiểm soát của tôi. Một số trong những hình ảnh này là tuyệt vời trong đó hình ảnh trải dài đến ranh giới trong khi một số có quá nhiều không gian màu trắng.Cắt hình ảnh không gian trắng tự động bằng cách sử dụng jQuery

Khi có quá nhiều khoảng trắng, nó làm cho trang trông khủng khiếp và có nghĩa là hình ảnh trên màn hình trông giống như chúng có kích thước khác nhau.

Bạn có thể xem những gì tôi muốn nói ở đây:

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

Những gì tôi đã được săn tìm là một phương pháp jQuery của cắt xén những hình ảnh và loại bỏ các khoảng trắng tự động.

1) Số khoảng trắng khác nhau trong mỗi hình ảnh 2) Tỷ lệ hình ảnh khác nhau 3) Tôi muốn sử dụng javascript thay vì xử lý trước hình ảnh.

Tôi hy vọng bạn có thể trợ giúp!

Chỉnh sửa: Đây là hình ảnh mẫu - http://images.productserve.com/preview/3395/128554505.jpg. Lưu ý những hình ảnh đến từ các trang web liên kết khác nhau và chắc chắn là từ một tên miền khác nhau.

+1

Tôi có thể đề xuất rằng bạn thực sự thêm một trong những hình ảnh mà sự cố xảy ra với câu hỏi của bạn. Nó sẽ ngăn phiếu bầu đóng lại vì bạn đang quảng cáo trang web của mình một cách hiệu quả. –

+1

Bạn có thể vẽ hình ảnh trên canvas và xóa toàn bộ các cột và hàng trống, đồng thời rescale hình ảnh với kích thước 'giống nhau' (giữ tỷ lệ cỡ ảnh). – Prusse

+2

"Tôi muốn sử dụng javascript hơn là xử lý trước hình ảnh" - Tại sao? Tại sao bạn muốn trình duyệt người dùng phải xóa không gian trắng mỗi lần ảnh được tải thay vì chỉ làm một lần ở phía máy chủ, sau đó lưu ảnh mà không có khoảng trắng để sử dụng trong tương lai? – h2ooooooo

Trả lời

41

Để phân tích không gian trống trong một hình ảnh, cách duy nhất tôi biết là để tải hình ảnh đó vào một 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'; 

Tiếp theo, sử dụng phương pháp getImageData(). Phương thức này trả về một đối tượng ImageData mà bạn có thể sử dụng để kiểm tra từng dữ liệu pixel (màu).

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. 
}; 

Thành thật mà nói tôi đã không thể kiểm tra mã này vì một lý do tốt: Tôi đã xem qua các "Không thể để có được dữ liệu hình ảnh từ vải vì vải đã bị làm hỏng bởi dữ liệu chéo gốc." Ngoại lệ an ninh khét tiếng .

Đây không phải là lỗi, nó là một tính năng dự định. Từ specs:

Các toDataURL(), toDataURLHD(), toBlob(), getImageData(), và getImageDataHD() phương pháp kiểm tra cờ và sẽ ném một ngoại lệ SecurityError hơn là rò rỉ dữ liệu chéo gốc .

này xảy ra khi drawImage() tải tệp từ các miền bên ngoài, gây nguồn gốc sạch cờ của vải được thiết lập là false, ngăn không cho thao tác dữ liệu hơn nữa.

Tôi sợ bạn sẽ chạy vào cùng một vấn đề, nhưng dù sao, here is the code.

Thậm chí nếu điều này làm việc về phía khách hàng, tôi có thể tưởng tượng như thế nào đau khổ sẽ là hiệu suất-khôn ngoan. Vì vậy, như Jan đã nói, nếu bạn có thể tải xuống hình ảnh và xử lý trước chúng ở phía máy chủ, điều đó sẽ tốt hơn.


Edit: Tôi đã tò mò muốn xem nếu mã của tôi thực sự sẽ cắt một hình ảnh, và thực sự nó làm. enter image description here

Bạn có thể kiểm tra xem nó ra here

Nó chỉ hoạt động cho hình ảnh từ tên miền của bạn, như đã nói trước đó. Bạn có thể chọn hình ảnh của riêng bạn với nền màu trắng và thay đổi dòng cuối cùng:

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

Rõ ràng, bạn sẽ cần phải chạy mã từ miền của bạn, chứ không phải từ jsFiddle.


Edit2: Nếu bạn muốn cắt và mở rộng quy mô để giữ tỉ lệ tương tự, sau đó thay đổi này

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: Một cách nhanh chóng để cắt hình ảnh trên trình duyệt r, là để song song khối lượng công việc thông qua việc sử dụng Nhân viên Web, vì điều này excellent article giải thích.

+0

Cảm ơn phản hồi chi tiết của bạn. Không có công việc bảo mật tương đương xung quanh như bạn có được với Javascript và JSONP? –

+0

Nếu các trang liên kết trả về URL của hình ảnh dưới dạng JSON, bạn có thể thử trả lời JSON trong một hàm javascript xem http://en.wikipedia.org/wiki/JSONP Ngoài ra, tôi lưu ý thuộc tính crossorigin' HTML5 mới cho phép đọc hình ảnh từ các tên miền nước ngoài, NHƯNG máy chủ (các chi nhánh của bạn) phải cho phép bằng cách có tiêu đề 'Access-Control-Allow-Origin', xem https://developer.mozilla.org/en-US/docs/CORS_Enabled_Image Tôi đã giới thiệu rằng tài sản mới trong mã jsFiddle –

+0

@DavidHilditch Xem câu trả lời cập nhật của tôi –

10

Dựa trên câu trả lời tuyệt vời được cung cấp bởi Jose Rui Santos, tôi đã thay đổi mã của mình để hoạt động chỉ với đối tượng image mà không cần thư viện jQuery được tải.

Sự trở lại của hàm này là URL dữ liệu hình ảnh được cắt sẽ được sử dụng trực tiếp trong phần tử hình ảnh.

/* 
    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

Tại sao bạn thêm +10; làm cho không có ý nghĩa và bạn làm cho tôi mất rất nhiều thời gian cố gắng để tìm lỗi –

+0

@IvanCastellanos Cảm ơn bạn đã chỉnh sửa! Tôi đã thêm nó vào mã vì hình ảnh bị cắt đã có văn bản và tôi cần một khoảng trống nhỏ ở dưới cùng và bên phải. Xin lỗi vì chuyện đó. – Mohammad

Các vấn đề liên quan