Muszę zmienić rozmiar plików PNG, JPEG i GIF. Jak mogę to zrobić za pomocą Java?
Muszę zmienić rozmiar plików PNG, JPEG i GIF. Jak mogę to zrobić za pomocą Java?
Odpowiedzi:
Po załadowaniu obrazu możesz spróbować:
BufferedImage createResizedCopy(Image originalImage,
int scaledWidth, int scaledHeight,
boolean preserveAlpha)
{
System.out.println("resizing...");
int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
Graphics2D g = scaledBI.createGraphics();
if (preserveAlpha) {
g.setComposite(AlphaComposite.Src);
}
g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose();
return scaledBI;
}
FWIW Właśnie wydałem (Apache 2, hostowany na GitHub) prostą bibliotekę skalowania obrazu dla Javy o nazwie imgscalr (dostępna w centrali Maven ).
Biblioteka wdraża kilka różnych podejść do skalowania obrazu (w tym podejście przyrostowe Chrisa Campbella z kilkoma drobnymi ulepszeniami) i albo wybierze najbardziej optymalne podejście, jeśli o to poprosisz, albo da ci najszybsze lub najlepiej wyglądające (jeśli poproś o to).
Użycie jest banalnie proste, tylko kilka statycznych metod. Najprostszy przypadek użycia to:
BufferedImage scaledImage = Scalr.resize(myImage, 200);
Wszystkie operacje zachowują oryginalne proporcje obrazu, więc w tym przypadku prosisz imgscalr o zmianę rozmiaru obrazu w granicach 200 pikseli szerokości i 200 pikseli wysokości i domyślnie automatycznie wybierze najlepiej wyglądające i najszybsze podejście do tego, ponieważ nie było nie określono.
Na początku zdaję sobie sprawę, że wygląda to na autopromocję (tak jest), ale spędziłem sporo czasu na szukaniu w Google dokładnie tego samego tematu i wymyślałem różne wyniki / podejścia / przemyślenia / sugestie i postanowiłem usiąść i napisać prosta implementacja, która rozwiązałaby te 80-85% przypadków użycia, w których masz obraz i prawdopodobnie chcesz dla niego miniatura - tak szybko, jak to możliwe, albo tak dobrze wyglądająca, jak to tylko możliwe (dla tych, którzy próbowali, zauważysz wykonanie Graphics.drawImage nawet z interpolacją BICUBIC do wystarczająco małego obrazu, nadal wygląda jak śmieci).
new ImageScaler(img).resizeTo(...).rotate(...).cropTo(...).toOutputBuffer()
. Ja też lubię twój sposób i myślę, że jest prostszy.
Thumbnailator to otwarta biblioteka do zmiany rozmiaru obrazu dla języka Java z płynnym interfejsem, rozpowszechniana na licencji MIT.
Napisałem tę bibliotekę, ponieważ tworzenie wysokiej jakości miniatur w Javie może być zaskakująco trudne, a wynikowy kod może być dość niechlujny. Dzięki Thumbnailator możliwe jest wyrażanie dość skomplikowanych zadań za pomocą prostego, płynnego interfejsu API.
Prosty przykład
Dla prostego przykładu, zrobienie obrazu i zmiana jego rozmiaru do 100 x 100 (z zachowaniem proporcji oryginalnego obrazu) i zapisanie go do pliku można osiągnąć w jednej instrukcji:
Thumbnails.of("path/to/image")
.size(100, 100)
.toFile("path/to/thumbnail");
Zaawansowany przykład
Wykonywanie złożonych zadań zmiany rozmiaru jest uproszczone dzięki płynnemu interfejsowi Thumbnailator.
Załóżmy, że chcemy wykonać następujące czynności:
0.85
,thumbnail.
dołączeniem na początkuPo przetłumaczeniu na Thumbnailator moglibyśmy wykonać powyższe z następującymi rozwiązaniami:
Thumbnails.of(new File("path/to/directory").listFiles())
.size(100, 100)
.outputFormat("JPEG")
.outputQuality(0.85)
.toFiles(Rename.PREFIX_DOT_THUMBNAIL);
Uwaga dotycząca jakości i szybkości obrazu
Ta biblioteka korzysta również z progresywnej metody skalowania bilinearnego , wyróżnionej w Filthy Rich Clients przez Chet Haase i Romain Guy, w celu generowania wysokiej jakości miniatur przy jednoczesnym zapewnieniu akceptowalnej wydajności w czasie wykonywania.
Nie potrzebujesz do tego biblioteki. Możesz to zrobić z samą Javą.
Chris Campbell ma doskonały i szczegółowy opis skalowania obrazów - zobacz ten artykuł .
Chet Haase i Romain Guy również szczegółowo opisali skalowanie obrazu w swojej książce Filthy Rich Clients .
Java Advanced Imaging jest teraz open source i zapewnia operacje, których potrzebujesz.
Jeśli masz do czynienia z dużymi obrazami lub chcesz uzyskać ładny wygląd, nie jest to proste zadanie w Javie. Po prostu zrobienie tego poprzez zmianę skali za pomocą Graphics2D nie utworzy wysokiej jakości miniatury. Możesz to zrobić za pomocą JAI, ale wymaga to więcej pracy, niż byś sobie wyobrażał, aby uzyskać coś, co wygląda dobrze, a JAI ma paskudny zwyczaj wysadzania naszej JVM błędów OutOfMemory.
Sugeruję użycie ImageMagick jako zewnętrznego pliku wykonywalnego, jeśli możesz sobie z tym poradzić. Jest prosty w użyciu i dobrze spełnia swoje zadanie, więc nie musisz tego robić.
Interfejs API języka Java nie zapewnia standardowej funkcji skalowania obrazów i obniżania jakości obrazu.
Z tego powodu próbowałem użyć cvResize z JavaCV, ale wydaje się, że powoduje to problemy.
Znalazłem dobrą bibliotekę do skalowania obrazów: po prostu dodaj zależność dla "java-image-scaling" w swoim pom.xml.
<dependency>
<groupId>com.mortennobel</groupId>
<artifactId>java-image-scaling</artifactId>
<version>0.8.6</version>
</dependency>
W repozytorium Maven otrzymasz najnowszą wersję tego.
Dawny. W twoim programie java
ResampleOp resamOp = new ResampleOp(50, 40);
BufferedImage modifiedImage = resamOp.filter(originalBufferedImage, null);
Możesz spróbować użyć GraphicsMagick Image Processing System z im4java jako interfejsem wiersza poleceń dla Javy.
Jest wiele zalet GraphicsMagick, ale jedna dla wszystkich:
Wspomniano o Magii Obrazu. Istnieje projekt interfejsu JNI o nazwie JMagick. Nie jest to szczególnie stabilny projekt (a sam Image Magick był znany z tego, że bardzo zmieniał, a nawet łamał kompatybilność). To powiedziawszy, mamy dobre doświadczenia w używaniu JMagicka i kompatybilnej wersji Image Magick w środowisku produkcyjnym do wykonywania skalowania z dużą przepustowością i małym opóźnieniem. Szybkość była znacznie lepsza niż w przypadku całej biblioteki graficznej Java, którą wcześniej próbowaliśmy.
Po prostu użyj odpowiedzi Burkharda, ale dodaj tę linię po utworzeniu grafiki:
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
Możesz również ustawić wartość na BICUBIC, da to obraz o lepszej jakości, ale jest to operacja droższa. Istnieją inne wskazówki dotyczące renderowania, które możesz ustawić, ale odkryłem, że interpolacja daje najbardziej zauważalny efekt. Pamiętaj, że jeśli chcesz dużo powiększyć, kod java najprawdopodobniej będzie bardzo wolny. Zauważyłem, że większe obrazy zaczynają generować opóźnienie około 300% zoomu, nawet przy wszystkich wskazówkach dotyczących renderowania ustawionych na optymalizację pod kątem szybkości nad jakością.
Możesz użyć Marvin (czysta platforma przetwarzania obrazu Java) do tego rodzaju operacji: http://marvinproject.sourceforge.net
Wtyczka skalowania: http://marvinproject.sourceforge.net/en/plugins/scale.html
Okazuje się, że napisanie wydajnego skalera nie jest trywialne. Zrobiłem to raz dla projektu open source: ImageScaler .
Zasadniczo „java.awt.Image # getScaledInstance (int, int, int)” również by się nadawało, ale jest w tym paskudny błąd - szczegółowe informacje można znaleźć w moim linku.
Opracowałem rozwiązanie z swobodnie dostępnymi klasami (AnimatedGifEncoder, GifDecoder i LWZEncoder) dostępnymi do obsługi Animacji GIF.
Możesz pobrać jar jgifcode i uruchomić klasę GifImageUtil. Link: http://www.jgifcode.com
możesz skorzystać z popularnego produktu: miniatury
Jeśli nie chcesz importować imgScalr, takiej jak @Riyad Kalla odpowiedź, którą powyżej przetestowałem, działa dobrze, możesz to zrobić zaczerpniętą z odpowiedzi Petera Walsera @Peter Walser w innej kwestii:
/**
* utility method to get an icon from the resources of this class
* @param name the name of the icon
* @return the icon, or null if the icon wasn't found.
*/
public Icon getIcon(String name) {
Icon icon = null;
URL url = null;
ImageIcon imgicon = null;
BufferedImage scaledImage = null;
try {
url = getClass().getResource(name);
icon = new ImageIcon(url);
if (icon == null) {
System.out.println("Couldn't find " + url);
}
BufferedImage bi = new BufferedImage(
icon.getIconWidth(),
icon.getIconHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
// paint the Icon to the BufferedImage.
icon.paintIcon(null, g, 0,0);
g.dispose();
bi = resizeImage(bi,30,30);
scaledImage = bi;// or replace with this line Scalr.resize(bi, 30,30);
imgicon = new ImageIcon(scaledImage);
} catch (Exception e) {
System.out.println("Couldn't find " + getClass().getName() + "/" + name);
e.printStackTrace();
}
return imgicon;
}
public static BufferedImage resizeImage (BufferedImage image, int areaWidth, int areaHeight) {
float scaleX = (float) areaWidth / image.getWidth();
float scaleY = (float) areaHeight / image.getHeight();
float scale = Math.min(scaleX, scaleY);
int w = Math.round(image.getWidth() * scale);
int h = Math.round(image.getHeight() * scale);
int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
boolean scaleDown = scale < 1;
if (scaleDown) {
// multi-pass bilinear div 2
int currentW = image.getWidth();
int currentH = image.getHeight();
BufferedImage resized = image;
while (currentW > w || currentH > h) {
currentW = Math.max(w, currentW / 2);
currentH = Math.max(h, currentH / 2);
BufferedImage temp = new BufferedImage(currentW, currentH, type);
Graphics2D g2 = temp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(resized, 0, 0, currentW, currentH, null);
g2.dispose();
resized = temp;
}
return resized;
} else {
Object hint = scale > 2 ? RenderingHints.VALUE_INTERPOLATION_BICUBIC : RenderingHints.VALUE_INTERPOLATION_BILINEAR;
BufferedImage resized = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = resized.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(image, 0, 0, w, h, null);
g2.dispose();
return resized;
}
}
Wypróbuj następującą metodę:
ImageIcon icon = new ImageIcon("image.png");
Image img = icon.getImage();
Image newImg = img.getScaledInstance(350, 350, java.evt.Image.SCALE_SMOOTH);
icon = new ImageIcon(img);
JOptionPane.showMessageDialog(null, "image on The frame", "Display Image", JOptionPane.INFORMATION_MESSAGE, icon);