Scalanie dwóch obrazów

84

Muszę scalić dwa obrazy (BufferedImage) w Javie. Nie byłoby problemu, gdyby nie było przejrzystości. Obraz podstawowy ma już pewną przezroczystość. Chcę to zachować tak, jak jest i nałożyć na to „maskę”, drugi obraz. Ten drugi obraz nie ma nieprzezroczystych pikseli, w rzeczywistości jest prawie całkowicie przezroczysty, ma tylko kilka mniej przezroczystych pikseli, które dają pewien rodzaj „efektu świetlnego”, jak odruch. Ważny szczegół: nie chcę tego robić na ekranie, z grafiką, muszę uzyskać BufferedImage z wynikowym scaleniem.

Czy ktoś może mi pomóc? Dzięki!

SZCZEGÓŁY: Scal dwa obrazy z zachowaniem przejrzystości. To jest to, co muszę zrobić.

Uwaga: ta maska ​​alfa Set BufferedImage w Javie nie robi tego, czego potrzebuję, ponieważ nie radzi sobie dobrze z dwoma obrazami z przezroczystością - modyfikuje przezroczystość pierwszego obrazu.

GuilhermeA
źródło

Odpowiedzi:

179

Po prostu utwórz nowy BufferedImage z przezroczystością, a następnie pomaluj na nim pozostałe dwa obrazy (z pełną lub półprzezroczystością). Tak to będzie wyglądać:

Obraz plus nakładka

Przykładowy kod (obrazy nazywane są „image.png” i „overlay.png”):

File path = ... // base path of the images

// load source images
BufferedImage image = ImageIO.read(new File(path, "image.png"));
BufferedImage overlay = ImageIO.read(new File(path, "overlay.png"));

// create the new image, canvas size is the max. of both image sizes
int w = Math.max(image.getWidth(), overlay.getWidth());
int h = Math.max(image.getHeight(), overlay.getHeight());
BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

// paint both images, preserving the alpha channels
Graphics g = combined.getGraphics();
g.drawImage(image, 0, 0, null);
g.drawImage(overlay, 0, 0, null);

g.dispose();

// Save as new image
ImageIO.write(combined, "PNG", new File(path, "combined.png"));
Peter Walser
źródło
Czy istnieje sposób, aby drugi obraz znajdował się pośrodku pierwszego?
Ahmed
6
Czy nie powinieneś wywoływać funkcji g.dispose (); na końcu?
m-szalik
Cześć, zastosowałem to podejście i zapisałem tylko drugi obraz, ale nie pierwszy ... Każda pomoc byłaby mile
widziana
@Peter Obraz jest wyszarzony, gdy poprawiam połączony plik jako plik jpeg. Proszę o pomoc
Mohammed shebin
3

Nie mogę udzielić ci konkretnej odpowiedzi, ale java.awt.AlphaComposite to twój przyjaciel. Uzyskasz absolutną kontrolę nad tym, jak chcesz połączyć oba obrazy. Jednak nie jest to proste w użyciu - musisz najpierw nauczyć się trochę teorii grafiki.

Steve McLeod
źródło
3

Nie wiedząc więcej o efekcie, który próbujesz osiągnąć, wskażę tylko, że możesz również rysować bezpośrednio na BufferedImage. Więc wszystko, co możesz zrobić na ekranie, możesz zrobić bezpośrednio na samym obrazie.

Więc jeśli wszystko, czego chcesz, to jedno narysowane na drugim, to jest naprawdę łatwe. Po prostu chwyć obiekt Graphics jako obraz podstawowy i narysuj na nim drugi.

Ponownie, w zależności od dokładnego efektu, który zamierzasz, może to nie zadziałać. Więcej szczegółów pozwoliłoby na lepszą pomoc. Na przykład, czy jest to zadanie dla AlphaComposite, jak wspomina inny respondent, czy niestandardowy ImageOp (lub kombinacja istniejących ImageOps).

PSpeed
źródło
1

scal dowolny typ pliku w pionie.

void mergeFiles(List<String> files, String fileName) {
        int heightTotal = 0;
        int maxWidth = 100;

        List<BufferedImage> images = new ArrayList<>();
        try {
            for (String file : files) {
                BufferedImage image = ImageIO.read(new File(file));
                images.add(image);
            }


        for (BufferedImage bufferedImage : images) {
            heightTotal += bufferedImage.getHeight();
            if (bufferedImage.getWidth() > maxWidth) {
                maxWidth = bufferedImage.getWidth();
            }
        }


        int heightCurr = 0;
        BufferedImage concatImage = new BufferedImage(maxWidth, heightTotal, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = concatImage.createGraphics();
        for (BufferedImage bufferedImage : images) {
            g2d.drawImage(bufferedImage, 0, heightCurr, null);
            heightCurr += bufferedImage.getHeight();
        }

        File compressedImageFile = new File(fileName);
        OutputStream outputStream = new FileOutputStream(compressedImageFile);

        float imageQuality = 0.7f;
        Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersByFormatName("jpeg");

        if (!imageWriters.hasNext())
            throw new IllegalStateException("Writers Not Found!!");

        ImageWriter imageWriter = imageWriters.next();
        ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
        imageWriter.setOutput(imageOutputStream);

        ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();

        //Set the compress quality metrics
        imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        imageWriteParam.setCompressionQuality(imageQuality);

        //Created image
        imageWriter.write(null, new IIOImage(concatImage, null, null), imageWriteParam);

        // close all streams
        outputStream.close();
        imageOutputStream.close();
        imageWriter.dispose();
        log.info(" Files Merged");
        } catch (IOException e) {
            log.error("Error while merging files :::"+e);
            throw new RuntimeException(e);
        }
    }
Kumar Abhishek
źródło