Ritaglia automaticamente lo spazio bianco dell’immagine usando jQuery

Ho 100.000 immagini che non sono sotto il mio controllo. Alcune di queste immagini sono eccellenti in quanto l’immagine si estende ai limiti mentre alcune hanno una quantità eccessiva di spazio bianco.

Quando c’è uno spazio bianco eccessivo, la pagina sembra terribile e le immagini sullo schermo sembrano tutte di dimensioni diverse.

Puoi vedere cosa intendo qui:

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

Quello che sto cercando è un metodo jQuery per ritagliare le immagini e rimuovere automaticamente gli spazi.

1) La quantità di spazi bianchi è diversa in ogni immagine 2) I rapporti delle immagini sono diversi 3) Voglio usare javascript piuttosto che pre-elaborare le immagini.

Spero che tu possa aiutare!

Modifica: ecco un’immagine di esempio – http://sofit.miximages.com/image/128554505.jpg . Nota che le immagini provengono da vari siti affiliati e provengono sicuramente da un dominio diverso.

Per analizzare gli spazi vuoti in un’immagine, l’unico modo che conosco è di caricare quell’immagine in una canvas :

 var img = new Image(), $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'; 

Successivamente, utilizzare il metodo getImageData () . Questo metodo restituisce un object ImageData che è ansible utilizzare per ispezionare ogni dato di pixel (colore).

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

Francamente non sono riuscito a testare questo codice per una buona ragione: mi sono imbattuto nel famigerato " Imansible ottenere i dati dell'immagine dalla canvas perché la canvas è stata macchiata da dati di origine incrociata ". Eccezione di sicurezza.

Questo non è un bug, è una caratteristica prevista. Dalle specifiche :

I metodi toDataURL (), toDataURLHD (), toBlob (), getImageData () e getImageDataHD () controllano il flag e generano un'eccezione SecurityError piuttosto che perdite di dati di origine incrociata.

Questo accade quando drawImage() carica file da domini esterni, il che fa sì che il flag clean-originale del canvas sia impostato su false, impedendo ulteriori manipolazioni di dati.

Ho paura che ti imbatti nello stesso problema, ma comunque, ecco il codice.

Anche se questo funziona dal lato del cliente, posso immaginare quanto sarà miserabile il rendimento. Quindi, come ha detto Jan, se è ansible scaricare le immagini e pre-elaborarle sul lato server, sarebbe meglio.


Edit: ero curioso di vedere se il mio codice potesse davvero ritagliare un'immagine, e in effetti lo fa. inserisci la descrizione dell'immagine qui

Puoi verificarlo qui

Funziona solo per le immagini del tuo dominio, come affermato in precedenza. Puoi scegliere la tua immagine con sfondo bianco e modificare l'ultima riga:

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

Ovviamente, dovrai eseguire il codice dal tuo dominio, non da jsFiddle.


Modifica2: se si desidera ritagliare e ridimensionare per mantenere le stesse proporzioni, quindi modificare questo

 var $croppedCanvas = $("").attr({ width: cropWidth, height: cropHeight }); // finally crop the guy $croppedCanvas[0].getContext("2d").drawImage(canvas, cropLeft, cropTop, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight); 

a

 var $croppedCanvas = $("").attr({ width: imgWidth, height: imgHeight }); // finally crop the guy $croppedCanvas[0].getContext("2d").drawImage(canvas, cropLeft, cropTop, cropWidth, cropHeight, 0, 0, imgWidth, imgHeight); 

Edit3: Un modo veloce per ritagliare le immagini sul browser, è quello di parallelizzare il carico di lavoro attraverso l'utilizzo di Web Workers , come spiega questo eccellente articolo .

Sulla base dell’ottima risposta fornita da Jose Rui Santos , ho cambiato il suo codice per lavorare con un solo object image senza la libreria jQuery da caricare.

Il ritorno di questa funzione è l’URL dei dati immagine ritagliati da utilizzare direttamente nell’elemento immagine.

 /* 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(); }