Sunday, June 18, 2017

Java 9'da Görüntü Dosyaları ile Çalışmak


Java 9 ile birlikte görüntü dosyalarına erişim ile ilgili olarak iki önemli yenilik bizi bekliyor:
  • Image IO paketi ile PNG ve JPEG formatlarında görüntü dosyalarını okuyup, yazabiliyorduk. Artık buna çok sayfalı TIFF formatı da eklendi. Bu tür görüntü dosyalarını artık Java Advanced Imaging gibi üçüncü parti bir kütüphane kullanmadan erişebiliyoruz.
  • İkinci yenilik ise bir görüntünün farklı çözünürlükteki kopyaları ile çalışmayı kolaylaştırıyor. Uygulama içinden elimizdeki ekran ya da görüntü işleme algoritması için en uygun çözünürlükteki görüntüye basit bir şekilde ulaşabiliyoruz. 
Örnek uygulamada Roma'nın farklı çözünürlükte çekilmiş görüntüleri ile çalışacağız:
  • rome-1.jpg: 4098 x 4177
  • rome-2.jpg: 2049 x 2089
  • rome-3.jpg: 1025 x 1045
  • rome-4.jpg: 513 x 523

package com.example.java9.features;

import java.awt.Image;
import java.awt.image.BaseMultiResolutionImage;
import java.awt.image.BufferedImage;
import java.awt.image.MultiResolutionImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.imageio.ImageIO;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class MultiResolutiomImageExample {
    public static void main(String[] args) {
        List<String> imageFileNames = List.of("rome-4.jpg","rome-3.jpg","rome-2.jpg","rome-1.jpg");
        final Function<String, BufferedImage> mapToBufferedImage = file -> {
            try {
                return ImageIO.read(new File("build/classes",file));
            } catch (IOException e) {
                return null;
            }
        };
        List<BufferedImage> images = imageFileNames.stream()
                                                   .map(mapToBufferedImage)
                                                   .filter(Objects::nonNull)
                                                   .collect(Collectors.toList());
        System.err.println("images.size():"+images.size());
        MultiResolutionImage multiResolutionImage = new BaseMultiResolutionImage(images.toArray(new Image[0]));
        List<Image> imageVariants = multiResolutionImage.getResolutionVariants();
        System.out.println("number of images: " + imageVariants.size());        
        imageVariants.forEach(System.out::println);
        final Image image1 = multiResolutionImage.getResolutionVariant(1024, 768);
        System.out.println(image1);
        final Image image2 = multiResolutionImage.getResolutionVariant(2049, 2089);
        System.out.println(image2);
       
    }
}

Yukarıda örnek uygulamada Roma'nın dört farklı çözünürlükteki görüntüsünü dosyalardan okuduktan sonra MultiResolutionImage sınıfının yönetimine bırakıyoruz. MultiResolutionImage kurucu fonksiyonu bu görüntüleri BufferedImage tipinden bir dizide en düşük çözünürlükten en yüksek çözünürlüğe doğru sıralı olacak şekilde bizden bekliyor. En uygun çözünürlükte görüntüye ulaşmak için ise MultiResolutionImage sınıfının getResolutionVariant() metodunu kullanıyoruz:
  • multiResolutionImage.getResolutionVariant(1024, 768) çağrısı 1025 x 1045 çözünürlüğe sahip görüntüyü dönerken 
  • multiResolutionImage.getResolutionVariant(2049,2089) çağrısı 2049 x 2089 çözünürlüğe sahip görüntüyü döndü.
Şimdi ise çok sayfalı TIFF dokümanı okuyan basit bir uygulama geliştireceğiz. Bu uygulamada kullanacağımız çok sayfalı TIFF, bir önceki örnekte kullandığımız yukarıda değerleri verilen dört farklı çözünürlükteki görüntüyü içeriyor.

package com.example.java9.features;

import java.awt.Image;
import java.awt.image.BaseMultiResolutionImage;
import java.awt.image.BufferedImage;
import java.awt.image.MultiResolutionImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.*;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class MultiPageTiffExample {

    public static ImageReader tiffReader;

    public static Optional<BufferedImage> read(int index) {
        try {
            return Optional.of(tiffReader.read(index));
        } catch (IOException ex) {
            return Optional.empty();
        }
    }

    public static void main(String[] args) throws FileNotFoundException, IOException {
        InputStream stream = new FileInputStream(new File("build/classes", "/image.tif"));
        tiffReader = ImageIO.getImageReadersByFormatName("tiff").next();

        ImageInputStream input = ImageIO.createImageInputStream(stream);

        tiffReader.setInput(input);

        final int numOfImages = tiffReader.getNumImages(true);
        System.out.println("# of pages: " + numOfImages);

        List<BufferedImage> images = IntStream.range(0, numOfImages)
                .mapToObj(MultiPageTiffExample::read)
                .filter(Optional::isPresent)
                .flatMap(Optional::stream)
                .collect(Collectors.toList());
        MultiResolutionImage multiResolutionImage = new BaseMultiResolutionImage(images.toArray(new Image[0]));
        List<Image> imageVariants = multiResolutionImage.getResolutionVariants();
        System.out.println("number of images: " + imageVariants.size());
        imageVariants.forEach(System.out::println);
        final Image image1 = multiResolutionImage.getResolutionVariant(1024, 768);
        System.out.println(image1);
        final Image image2 = multiResolutionImage.getResolutionVariant(2049, 2089);
        System.out.println(image2);
    }
}

TIFF formatında görüntü dosyalarını okumak için kullanacağımız nesneyi ImageIO.getImageReadersByFormatName("tiff").next() ile alıyoruz.  Uygulamaların kodlarına bu bağlantıdan ulaşabilirsiniz.

No comments:

Post a Comment