2015-09-26 47 views
8

Biorąc pod uwagę obraz z kanałem alfa (przezroczystość), chciałbym usunąć pustą przestrzeń między granicami obrazu a rzeczywistym obrazem. Należy wykonać to zadanie w tle lub z ekranem ładowania, z dopuszczalnym czasem pracy, aby nie zakłócać komfortu użytkownika.Jak usunąć pustą przestrzeń wokół obrazu w systemie Android?

enter image description here

Jak mogę osiągnąć ten wynik?

Odpowiedz

17

Miałem trudności ze znalezieniem najlepszych praktyk, a nawet porad, aby rozwiązać mój problem. Opierając się na this anwer by JannGabriel, który przycina obraz prawym i dolnym zmniejszając rozmiar obrazu, udało mi się zrobić krok dalej, a także usunąć górne i lewe spacje i ogólnie poprawić czas opracowania. Wynik jest dobry i obecnie używam go w moim projekcie. Jestem całkiem nowy w programowaniu Androida i wszelkie rady dotyczące tej metody są mile widziane.

public static Bitmap TrimBitmap(Bitmap bmp) { 
    int imgHeight = bmp.getHeight(); 
    int imgWidth = bmp.getWidth(); 


    //TRIM WIDTH - LEFT 
    int startWidth = 0; 
    for(int x = 0; x < imgWidth; x++) { 
     if (startWidth == 0) { 
      for (int y = 0; y < imgHeight; y++) { 
       if (bmp.getPixel(x, y) != Color.TRANSPARENT) { 
        startWidth = x; 
        break; 
       } 
      } 
     } else break; 
    } 


    //TRIM WIDTH - RIGHT 
    int endWidth = 0; 
    for(int x = imgWidth - 1; x >= 0; x--) { 
     if (endWidth == 0) { 
      for (int y = 0; y < imgHeight; y++) { 
       if (bmp.getPixel(x, y) != Color.TRANSPARENT) { 
        endWidth = x; 
        break; 
       } 
      } 
     } else break; 
    } 



    //TRIM HEIGHT - TOP 
    int startHeight = 0; 
    for(int y = 0; y < imgHeight; y++) { 
     if (startHeight == 0) { 
      for (int x = 0; x < imgWidth; x++) { 
       if (bmp.getPixel(x, y) != Color.TRANSPARENT) { 
        startHeight = y; 
        break; 
       } 
      } 
     } else break; 
    } 



    //TRIM HEIGHT - BOTTOM 
    int endHeight = 0; 
    for(int y = imgHeight - 1; y >= 0; y--) { 
     if (endHeight == 0) { 
      for (int x = 0; x < imgWidth; x++) { 
       if (bmp.getPixel(x, y) != Color.TRANSPARENT) { 
        endHeight = y; 
        break; 
       } 
      } 
     } else break; 
    } 


    return Bitmap.createBitmap(
      bmp, 
      startWidth, 
      startHeight, 
      endWidth - startWidth, 
      endHeight - startHeight 
    ); 

} 

Objaśnienie: Dla każdej strony obrazu, pętli FOR jest uruchamiany w celu sprawdzenia, czy nie zawiera piksele nie kolor przezroczysty, wracając pierwszy nieprzejrzyste pikseli przydatna współrzędnych. W tym celu opracowujemy współrzędne, używając jako podstawy wymiaru przeciwnego niż wymiar do przycięcia: aby znaleźć y, zeskanuj x dla każdego y.

Aby sprawdzić, gdzie kończy się pionowe Top spacja, uruchamia następujące czynności:

  1. początkowa wynosi od górnego rzędu (y = 0)
  2. Sprawdza wszystkie kolumny z rzędu (x od 0 do imageWidth)
  3. Jeśli zostanie znaleziony nieprzezroczysty piksel, przerwij pętlę i zapisz współrzędną y. W przeciwnym razie kontynuuj.
  4. Po zakończeniu kolumn przejdź do następnego wiersza (y + 1) i rozpocznij sprawdzanie kolumn. Przerwij, jeśli nieprzejrzysty piksel został już znaleziony.

Podobne metody są stosowane dla innych wymiarów, zmieniając tylko kierunek skanowania.

Po uzyskał 4 współrzędne pierwszych przydatnych pikseli obrazu, metoda Bitmap.createBitmap jest wywoływana z oryginalnej bitmapy jako obrazu bazowego, a użyteczne pikseli współrzędne jako lewego górnego i prawego dolnego limitów dla zmiany rozmiaru .

Uwaga 1: Warto pamiętać, że współrzędne 0, 0 jest równa lewy górny.

Uwaga 2: Końcowa szerokość i wysokość w Bitmap.createBitmap są zmniejszane o nową początkową współrzędną względną, w przeciwnym razie nowy obraz będzie nieprawidłowo przesuwać granice w prawym dolnym rogu. Wyobraź sobie: masz obraz 100x100px, więc z końcowymi współrzędnymi 100, 100. Zmiana współrzędnych początkowych na 50,50 spowoduje, że końcowe współrzędne prostokąta opracowania wynoszą 150 150 (100 oryginalnych współrzędnych + 50 zmodyfikowanych punktów początkowych), przesuwając je poza oryginalne obramowania obrazu. Aby tego uniknąć, nowa współrzędna końcowa jest zmniejszana o nową współrzędną początkową (100 + 50 nowych początkowych współrzędnych - 50 nowych początkowych korekt współrzędnych)

Uwaga 3: w oryginalnej odpowiedzi zaznaczenie wszystkich pikseli w danym kierunek jest uruchamiany przy użyciu tego samego wymiaru współrzędnej, aby znaleźć, zwracając najbardziej zaawansowany użyteczny piksel.Sprawdzenie przeciwnego wymiaru i zatrzymanie przy pierwszym użytecznym pikselu zwiększyło wydajność.

+1

Twój przykładowy kod będzie przycinać przynajmniej jeden piksel, nawet jeśli obraz ma przejrzystą kolumny lub wiersza. Lepiej jest użyć sposobu opisanego w 'http: // stackoverflow.com/a/886979/1043882' zamiast' if (startWidth == 0) 'i innych podobnych wypowiedzi. – hasanghaforian

+0

'' startHeight' startWidth' i nie powinien być ustawiony na 0 na początku, bo jeśli obraz nie ma pustej przestrzeni na górze i po lewej stronie Twojego for-pętle potrwa do końca. Więc tracisz czas obliczeniowy równy "2 * szerokości * wysokości". Myślę, że lepiej ustawić je na "-1". – Ruslan