2012-08-29 14 views
20

Mam 100 000 obrazów, które nie są pod moją kontrolą. Niektóre z tych obrazów są doskonałe pod tym względem, że obraz rozciąga się do granic, podczas gdy niektóre mają nadmierne ilości białej przestrzeni.Przycinanie białej powierzchni automatycznie przy użyciu jQuery

Gdy jest zbyt dużo białego miejsca, sprawia to, że strona wygląda okropnie i oznacza, że ​​obrazy na ekranie wyglądają jak różne rozmiary.

Można zobaczyć, co mam na myśli tutaj:

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

Co mi zostało polowanie na to metoda jQuery od przycinania zdjęć i usunięcie spacji automatycznie.

1) Ilość białych znaków jest różna dla każdego zdjęcia 2) Stosunki obrazów są różne 3) Chcę używać javascript zamiast wstępnego przetwarzania obrazów.

Mam nadzieję, że możesz pomóc!

Edytuj: Oto przykładowy obraz - http://images.productserve.com/preview/3395/128554505.jpg. Zwróć uwagę, że obrazy pochodzą z różnych witryn stowarzyszonych iz pewnością pochodzą z innej domeny.

+1

Czy mogę zasugerować, że faktycznie dodajesz jedno ze zdjęć, na które pojawia się problem na twoje pytanie. Zapobiegnie to zamykaniu głosów, ponieważ skutecznie reklamujesz swoją witrynę. –

+1

Możesz narysować obraz na płótnie i usunąć całe puste kolumny i wiersze, a następnie przeskalować obrazy do "tego samego" rozmiaru (zachowując proporcje). – Prusse

+2

"Chcę używać javascript zamiast wstępnego przetwarzania obrazów" - Dlaczego? Dlaczego chcesz, aby przeglądarka użytkowników musiała usuwać białe spacje za każdym razem, gdy obraz jest wczytywany, zamiast po prostu robić to raz po stronie serwera, a następnie zapisywać obraz bez białych odstępów do wykorzystania w przyszłości? – h2ooooooo

Odpowiedz

41

Aby przeanalizować puste przestrzenie w obrazie, jedynym sposobem, wiem to, aby załadować ten obraz w 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'; 

Następnie użyj metody getImageData(). Ta metoda zwraca obiekt ImageData, którego można użyć do sprawdzenia danych każdego piksela (koloru).

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

Szczerze mówiąc byłem w stanie przetestować ten kod za dobry powód: Natknąłem niesławnego „Nie można uzyskać dane obrazu z płótna, ponieważ płótno zostało skażone przez dane przekroju pochodzenia.” Wyjątek bezpieczeństwa .

To nie jest błąd, to zamierzona funkcja. Z specs:

The toDataURL(), toDataURLHD(), toBlob(), getImageData() i getImageDataHD() metody sprawdzenia flagi i rzuci SecurityError raczej wyjątek niż wyciek danych cross-origin .

Dzieje się tak, gdy drawImage() ładuje pliki z domen zewnętrznych, co powoduje pochodzenie-Clean flagę płótna, który ma być ustawiona na false, co uniemożliwia dalsze manipulacje danymi.

obawiam trafisz na ten sam problem, ale mimo to, here is the code.

Nawet jeśli działa po stronie klienta, mogę sobie wyobrazić, jak będzie nieszczęśliwy wydajność mądry. Tak więc, jak powiedział Jan, jeśli można pobrać obrazy i wstępnie je przetworzyć po stronie serwera, byłoby lepiej.


Edit: Byłem ciekaw, czy mój kod będzie naprawdę przyciąć zdjęcie, i rzeczywiście tak jest. enter image description here

Można to sprawdzić here

działa tylko w przypadku zdjęć z domeny, jak wspomniano wcześniej. Można wybrać własne zdjęcie z białym tłem i zmienić ostatni wiersz:

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

Oczywiście, trzeba będzie uruchomić kod z domeny, a nie z jsFiddle.


Edit2: Jeśli chcesz przyciąć i skalowanie zachować takie same proporcje, a następnie zmienić

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); 

do

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: Jeden szybki sposób przycinania obrazów w przeglądarce r, ma na celu zrównoleglenie obciążenia pracą poprzez użycie narzędzia Web Workers, co wyjaśnia ten excellent article.

+0

Dziękujemy za szczegółową odpowiedź. Czy nie ma podobnego zabezpieczenia, jak w przypadku JavaScript i JSONP? –

+0

Jeśli witryny stowarzyszone zwracają adres URL obrazu jako JSON, możesz spróbować zawinąć odpowiedź JSON w funkcji javascript, zobacz http://en.wikipedia.org/wiki/JSONP Również nie spodziewam się nowego atrybutu crossorigin HTML5, który pozwala czytać obrazy z obcych domen, ALE serwer (twoje filie) musi to umożliwić, mając nagłówek 'Access-Control-Allow-Origin', zobacz https://developer.mozilla.org/en-US/docs/CORS_Enabled_Image Wprowadziłem tę nową właściwość w kodzie jsFiddle –

+0

@DavidHilditch Zobacz moją zaktualizowaną odpowiedź –

10

Na podstawie świetnej odpowiedzi dostarczonej przez Jose Rui Santos, zmieniłem jego kod do pracy z obiektem image bez biblioteki jQuery do załadowania.

Powrót tej funkcji to przycięty URL danych obrazu, który zostanie użyty bezpośrednio w elemencie obrazu.

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

Dlaczego dodałeś +10; nie ma sensu i sprawiłeś, że straciłem dużo czasu próbując znaleźć błąd –

+0

@IvanCastellanos Dzięki za zmiany! Dodałem go w kodzie, ponieważ przycięty obraz miał tekst, a ja potrzebowałem trochę miejsca na dole i na prawo. Przepraszam za to. – Mohammad

Powiązane problemy