Создание миниатюр изображений с использованием Java

#java #image-manipulation

#java #обработка изображений

Вопрос:

У меня есть приложение, в котором мне нужно выбрать папку, содержащую изображения, и отобразить миниатюры этих изображений с использованием Java. Я не имею ни малейшего представления о том, как представлять изображения в формате миниатюр.

Любые ресурсы, такие как примеры кода, теория или ссылки, были бы действительно полезны.

Спасибо

Комментарии:

1. Какой бы вы хотели размер миниатюр? Некоторые изображения могут быть больше в ширину, чем в высоту; должны ли они масштабироваться одинаково в направлении x и в направлении y?

Ответ №1:

У меня есть этот код, который я использую в одном из своих проектов. Я нашел в сети некоторое время назад (не уверен, где, но если кто-нибудь узнает это, пожалуйста, дайте мне знать, чтобы я мог сослаться на это):

 private static byte[] createThumbnail(byte[] bytes)
{
    try
    {
        double scale;
        int sizeDifference, originalImageLargestDim;
        Image inImage = ImageIO.read(new ByteArrayInputStream(bytes));

        //find biggest dimension        
        if(inImage.getWidth(null) > inImage.getHeight(null))
        {
            scale = (double)LARGEST_DIMENSION/(double)inImage.getWidth(null);
            sizeDifference = inImage.getWidth(null) - LARGEST_DIMENSION;
            originalImageLargestDim = inImage.getWidth(null);
        }
        else
        {
            scale = (double)LARGEST_DIMENSION/(double)inImage.getHeight(null);
            sizeDifference = inImage.getHeight(null) - LARGEST_DIMENSION;
            originalImageLargestDim = inImage.getHeight(null);
        }
        //create an image buffer to draw to
        BufferedImage outImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB); //arbitrary init so code compiles
        Graphics2D g2d;
        AffineTransform tx;
        if(scale < 1.0d) //only scale if desired size is smaller than original
        {
            int numSteps = sizeDifference / 100;
            int stepSize = sizeDifference / numSteps;
            int stepWeight = stepSize/2;
            int heavierStepSize = stepSize   stepWeight;
            int lighterStepSize = stepSize - stepWeight;
            int currentStepSize, centerStep;
            double scaledW = inImage.getWidth(null);
            double scaledH = inImage.getHeight(null);
            if(numSteps % 2 == 1) //if there's an odd number of steps
                centerStep = (int)Math.ceil((double)numSteps / 2d); //find the center step
            else
                centerStep = -1; //set it to -1 so it's ignored later
            Integer intermediateSize = originalImageLargestDim, previousIntermediateSize = originalImageLargestDim;
            for(Integer i=0; i<numSteps; i  )
            {
                if(i 1 != centerStep) //if this isn't the center step
                {
                    if(i == numSteps-1) //if this is the last step
                    {
                        //fix the stepsize to account for decimal place errors previously
                        currentStepSize = previousIntermediateSize - LARGEST_DIMENSION;
                    }
                    else
                    {
                        if(numSteps - i > numSteps/2) //if we're in the first half of the reductions
                            currentStepSize = heavierStepSize;
                        else
                            currentStepSize = lighterStepSize;
                    }
                }
                else //center step, use natural step size
                {                        
                    currentStepSize = stepSize;
                }
                intermediateSize = previousIntermediateSize - currentStepSize;
                scale = (double)intermediateSize/(double)previousIntermediateSize;
                scaledW = (int)scaledW*scale;
                scaledH = (int)scaledH*scale;
                outImage = new BufferedImage((int)scaledW, (int)scaledH, BufferedImage.TYPE_INT_RGB);
                g2d = outImage.createGraphics();
                g2d.setBackground(Color.WHITE);
                g2d.clearRect(0, 0, outImage.getWidth(), outImage.getHeight());
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                tx = new AffineTransform();
                tx.scale(scale, scale);
                g2d.drawImage(inImage, tx, null);
                g2d.dispose();
                inImage = new ImageIcon(outImage).getImage();
                previousIntermediateSize = intermediateSize;
            }                
        }
        else
        {
            //just copy the original
            outImage = new BufferedImage(inImage.getWidth(null), inImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
            g2d = outImage.createGraphics();
            g2d.setBackground(Color.WHITE);
            g2d.clearRect(0, 0, outImage.getWidth(), outImage.getHeight());
            tx = new AffineTransform();
            tx.setToIdentity(); //use identity matrix so image is copied exactly
            g2d.drawImage(inImage, tx, null);
            g2d.dispose();
        }
        //JPEG-encode the image and write to file.
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os);
        encoder.encode(outImage);
        return os.toByteArray();
    }
    catch(Exception e)
    {
        throw new RuntimeException(e);
    }
}
  

Ответ №2:

Следующий код масштабирует все изображение в область. Вы можете скопировать-вставить код и запустить его, чтобы посмотреть, что он делает.

Интересным является вызов, g2d.drawImage(img, 0, 0, thumb.getWidth() - 1, thumb.getHeight() - 1, 0, 0, img.getWidth() - 1, img.getHeight() - 1, null); который копирует изображение в миниатюру, масштабируя его по размеру.

Если вам нужны другие масштабирования для сохранения соотношения сторон, вы могли бы использовать scale() на g2d или выбрать другие исходные координаты.

 import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

public class ThumbnailFactory {

    public ThumbnailFactory() {
    }

    public void run(String folder) {
        File dir = new File(folder);
        for (File file : dir.listFiles()) {
            createThumbnail(file);
        }
    }

    private void createThumbnail(File file) {
        try {
            // BufferedImage is the best (Toolkit images are less flexible)
            BufferedImage img = ImageIO.read(file);
            BufferedImage thumb = createEmptyThumbnail();

            // BufferedImage has a Graphics2D
            Graphics2D g2d = (Graphics2D) thumb.getGraphics(); 
            g2d.drawImage(img, 0, 0, 
                          thumb.getWidth() - 1,
                          thumb.getHeight() - 1, 
                          0, 0, 
                          img.getWidth() - 1,
                          img.getHeight() - 1, 
                          null);
            g2d.dispose();
            ImageIO.write(thumb, "PNG", createOutputFile(file));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private File createOutputFile(File inputFile) {
        // You'll want something better than this...
        return new File(inputFile.getAbsolutePath() 
                          ".thumb.png");
    }

    private BufferedImage createEmptyThumbnail() {
        return new BufferedImage(100, 200, 
                                 BufferedImage.TYPE_INT_RGB);
    }

    public static void main(String[] args) {
        ThumbnailFactory fac = new ThumbnailFactory();
        fac.run("c:\images");
    }
}