2009-05-03 15 views
12

Mam aplikację internetową napisaną w języku Java (Spring, Hibernate/JPA, Struts2), w której użytkownicy mogą przesyłać obrazy i przechowywać je w systemie plików. Chciałbym przeskalować te obrazy, aby miały stały rozmiar do wyświetlenia na stronie. Jakie biblioteki lub wbudowane funkcje oferują najlepsze wyniki? Będę pod uwagę następujące kryteria w podejmowaniu swojej decyzji (w tej kolejności):Jaki jest najlepszy sposób skalowania obrazów w Javie?

  • free/open source (istotne)
  • Łatwy do wdrożenia
  • jakość wyników
  • Wydajność
  • Rozmiar Plik wykonywalny:

Odpowiedz

4

Zobacz/przeczytaj Java Image I/O API. Następnie zmień rozmiar na AffineTransform.

Również, here's pełny przykład przy użyciu java.awt.Image.

+0

Podany przykład dotyczy 'getScaledInstance()', a nie AffineTransform. Więc co to jest? Czytałem mieszane recenzje, że 'getScaledInstance' nie jest tak wydajne ... – gdbj

4

Sprawdź również w bibliotece java-image-scaling. Stworzyło lepszej jakości obrazy, które ImageIO.

0

Najlepsze narzędzie do edycji obrazu to ImageMagick i jest to open source.

Istnieją dwa interfejsy dla języka Java:

JMagick który wykorzystuje interfejs JNI do ImageMagick

i

im4java co to interfejs wiersza polecenia dla ImageMagick

9

naprawdę polecam dając wygląd: imgscalr.

jest wydany na licencji Apache 2, gościł na GitHub, zostały rozmieszczone w kilku już aplikacji internetowych, ma bardzo prosty, ale pedantically documented API ma kod, który działa około 2 poważnych błędów graficznych w JDK dla Ciebie przejrzysty że zauważysz tylko, jeśli nagle zaczniesz otrzymywać "czarne" obrazy po operacji skalowania lub okropnie wyglądających wynikach, uzyskasz najlepsze możliwe wyniki dostępne w Javie, jest dostępna przez Mavena, a także ZIP i jest po prostu jedna klasa.

Podstawowe użycie wygląda następująco:

BufferedImage img = ImageIO.read(...); // load image 
BufferedImage scaledImg = Scalr.resize(img, 320); 

Jest to najprostsza rozmowa gdzie biblioteka wykorzysta najlepiej odgadnąć jakości, honorować swoje proporcje obrazu i dopasować wynik w oknie 320x320 ograniczenia. UWAGA, ramka ograniczająca jest po prostu maksymalną wartością W/H, ponieważ proporcje obrazu są honorowane, wynikowy obraz nadal będzie honorował to, powiedzmy 320x200.

Jeśli chcesz zastąpić tryb automatyczny i zmusić go do uzyskania najlepszego wyniku, a nawet zastosować bardzo łagodny filtr antyaliasingowy, aby wyglądał jeszcze lepiej (szczególnie dobrze dla miniatur), to połączenie będzie wyglądać następująco:

BufferedImage img = ImageIO.read(...); // load image 
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 
             150, 100, Scalr.OP_ANTIALIAS); 

Są to tylko przykłady, API jest szeroki i obejmuje wszystko, od bardzo prostych przypadków użycia do bardzo specjalistycznych.Możesz nawet przekazać swoje własne BufferedImageOps, które mają być zastosowane do obrazu (a biblioteka automatycznie naprawi dla ciebie sześcioletni błąd BufferedImageOp JDK!).

Jest dużo więcej rzeczy do skalowania obrazów w Javie z powodzeniem, że biblioteka robi dla ciebie, na przykład zawsze utrzymując obraz w jednym z najlepiej obsługiwanych typów obrazu RGB lub ARGB podczas pracy na nim. Pod pokrywami potok przetwarzania obrazu Java2D cofa się do gorszego oprogramowania, jeśli typ obrazu wykorzystywany do jakichkolwiek operacji na obrazie jest słabo obsługiwany.

Jeśli wszystko to brzmi jak ból głowy, to jest coś takiego ... dlatego napisałem bibliotekę i otworzyłem ją, więc ludzie mogli zmienić rozmiar swoich zdjęć i przejść do ich życia bez konieczności martwienia się o to.

Nadzieję, że pomaga.

0

Próbowałem imgscalr w porównaniu do standardowej Java 1.6 i nie mogę powiedzieć, że jest lepiej.

Co Próbowałem to

BufferedImage bufferedScaled = Scalr.resize(sourceImage, Method.QUALITY, 8000, height); 

i

Image scaled = sourceImage.getScaledInstance(-1, height, Image.SCALE_SMOOTH); 
    BufferedImage bufferedScaled = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_RGB); 
    bufferedScaled.getGraphics().drawImage(scaled, 0, 0, null); 

niektóre 5 minut testowania moim oku mam wrażenie, że druga rzecz (pure Java 1.6) daje lepsze rezultaty.

-1

stwierdziliśmy, że jest szybsze:

public static BufferedImage getScaledInstance(final BufferedImage img, final int targetWidth, final int targetHeight, 
               final Object hint) { 
    final int type = BufferedImage.TYPE_INT_RGB; 
    int drawHeight = targetHeight; 
    int drawWidth = targetWidth; 
    final int imageWidth = img.getWidth(); 
    final int imageHeight = img.getHeight(); 
    if ((imageWidth <= targetWidth) && (imageHeight <= targetHeight)) { 
     logger.info("Image " + imageWidth + "/" + imageHeight + " within desired scale"); 
     return img; 
    } 
    final double sar = ((double) imageWidth)/((double) imageHeight); 
    if (sar != 0) { 
     final double tar = ((double) targetWidth)/((double) targetHeight); 
     if ((Math.abs(tar - sar) > .001) && (tar != 0)) { 
      final boolean isSoureWider = sar > (targetWidth/targetHeight); 
      if (isSoureWider) { 
       drawHeight = (int) (targetWidth/sar); 
      } 
      else { 
       drawWidth = (int) (targetHeight * sar); 
      } 
     } 
    } 
    logger.info("Scaling image from " + imageWidth + "/" + imageHeight + " to " + drawWidth + "/" + drawHeight); 
    final BufferedImage result = new BufferedImage(drawWidth, drawHeight, type); 
    try { 
     final Graphics2D g2 = result.createGraphics(); 
     try { 
      if (hint != null) { 
       g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint); 
      } 
      g2.drawImage(img, 0, 0, drawWidth, drawHeight, null); 
     } 
     finally { 
      g2.dispose(); 
     } 
     return result; 
    } 
    finally { 
     result.flush(); 
    } 
} 
1

wiem, że to jest bardzo stare pytanie, ale mam własne rozwiązanie tego przy użyciu standardowego API Javy

import java.awt.*; 
import java.awt.event.*; 
import javax.imageio.* 
import java.awt.image.*; 

BufferedImage im, bi, bi2; 
Graphics2D gfx; 
int imWidth, imHeight, dstWidth, dstHeight; 
int DESIRED_WIDTH = 500, DESIRED_HEIGHT = 500; 

im = ImageIO.read(new File(filePath)); 
imWidth = im.getWidth(null); 
imHeight = im.getHeight(null); 

dstWidth = DESIRED_WIDTH; 
dstHeight = (dstWidth * imHeight)/imWidth; 

bi = new BufferedImage(dstWidth, dstHeight, im.getType()); 

gfx = bi.createGraphics(); 
gfx.drawImage(im, 0, 0, dstWidth, dstHeight, 0, 0, imWidth, imHeight, null); 

bi2 = new BufferedImage(DESIRED_WIDTH, DESIRED_HEIGHT, im.getType()); 
gfx = bi2.createGraphics(); 

gfx.drawImage(bi, 0, 0, DESIRED_WIDTH, DESIRED_HEIGHT, null); 

ImageIO.write(bi2, "jpg", new File(filePath)); 

Jestem pewien, że można być ulepszone i dostosowane.

Powiązane problemy