簡體   English   中英

處理海量大jpg

[英]Processing huge amount of large jpgs

我正在編寫一個程序,部分只是為了好玩,部分是為了幫助我處理一堆我想分成幾類進行打印的數字圖片。 主要思想是它應該在單個列中顯示圖片,並在每張圖片旁邊有一組帶有類別名稱的復選框。 我選中所需的復選框,按“開始!” 按鈕,圖片將被復制到子文件夾中,具體取決於所選的復選框。

現在,一切都差不多完成了——除了一件事。 有問題的圖片是大jpg,每個大約7-8MB,大約有700張。 如果我嘗試一次加載它們,自然地,將它們全部加載需要大量內存和時間。 那么,有沒有好的解決辦法呢? 我的兩個想法如下。

1) 一次加載 10 張圖片並在某處設置下一個/上一個按鈕。 我不喜歡這個想法,因為它添加了不需要的元素。 2) 使應用程序在滾動到新圖片時加載新圖片並卸載滾動過去的圖片。 我真的喜歡這個主意。

有人可以指出我正確的方向,至於我如何實施后一個想法嗎? 我只在 Google 上找到了一個相關鏈接,但我不能說它對我有幫助,我對代碼的某些部分感到有些困惑。

如果縮略圖就足夠了,這個答案包括一種簡單的重新采樣方法並引用了一些權衡。 如果沒有,此答案概述了顯示和緩存最近圖像的一般方法。

在任何一種情況下, JTable的默認Boolean 渲染器/編輯器都是JCheckBox CheckOne就是一個例子。

您必須為所有圖片創建縮略圖,您可以將縮略圖保存在內存中。 那可能需要很多時間。

那么你要么准備好解決問題。 否則縮略圖將無法全部放入內存中。 如果是這種情況:您加載 30-40 個,並在滾動期間檢測滾動方向,然后在單獨的線程中加載下一組。

如果加載速度比用戶滾動速度慢,那么您會為此類“尚未加載的圖片”顯示默認的占位符圖像

您可以縮小所有圖像以使用更少的 RAM。 例如,此代碼將所有圖像縮小到 200x200。 這樣你就可以在 100MB 中容納 1000 張圖片。

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
import java.io.File;

public class Scroll extends JPanel {
    public static void main(String[] args) throws Exception {
        JFrame frame = new JFrame();
        JPanel panel = new Scroll();

        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        for(int i = 0; i < 10; i++) {
            JPanel buttonPanel = new JPanel();
            JRadioButton b1 = new JRadioButton("button 1");
            JRadioButton b2 = new JRadioButton("button 2");
            JRadioButton b3 = new JRadioButton("button 3");
            ButtonGroup group = new ButtonGroup();
            group.add(b1);
            group.add(b2);
            group.add(b3);
            buttonPanel.add(b1);
            buttonPanel.add(b2);
            buttonPanel.add(b3);

            BufferedImage buffer = new BufferedImage(200,200,BufferedImage.TYPE_INT_RGB);
            Graphics2D g = buffer.createGraphics();

            BufferedImage image = ImageIO.read(new File("image.jpg"));
            g.scale(buffer.getWidth()*1.0/image.getWidth(),
                    buffer.getHeight()*1.0/image.getHeight());
            g.drawImage(image, 0, 0, null);
            g.dispose();
            JLabel imageLabel = new JLabel(new ImageIcon(buffer));
            JSplitPane splitPane = new JSplitPane();
            splitPane.add(imageLabel, JSplitPane.LEFT);
            splitPane.add(buttonPanel, JSplitPane.RIGHT);
            panel.add(splitPane);
        }
        JScrollPane spane = new JScrollPane(panel);
        frame.add(spane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500,600);
        frame.setVisible(true);
    }
}

如果您想在圖像變得可見時動態加載它們,您必須為每個圖像使用空的 JPanel 而不是 ImageIcons,然后覆蓋這些 JPanel 的paint方法。 只有在 JPanel 可見時才會調用paint方法。 因此,最簡單的解決方案是始終在paint方法中從磁盤加載圖像,然后將其繪制到屏幕上。

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
import java.io.File;

public class Scroll extends JPanel {
    public static void main(String[] args) throws Exception {
        JFrame frame = new JFrame();
        JPanel panel = new Scroll();

        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        for(int i = 0; i < 10; i++) {
            JPanel buttonPanel = new JPanel();
            JRadioButton b1 = new JRadioButton("button 1");
            JRadioButton b2 = new JRadioButton("button 2");
            JRadioButton b3 = new JRadioButton("button 3");
            ButtonGroup group = new ButtonGroup();
            group.add(b1);
            group.add(b2);
            group.add(b3);
            buttonPanel.add(b1);
            buttonPanel.add(b2);
            buttonPanel.add(b3);

            JPanel imagePanel = new JPanel() {
                {
                    BufferedImage image = ImageIO.read(new File("image.jpg"));
                    setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
                    image.flush();
                }
                @Override
                public void paint(Graphics g) {
                    try {
                        BufferedImage image = ImageIO.read(new File("image.jpg"));
                        g.drawImage(image, 0, 0, null);
                        image.flush();
                    } catch(Exception e) {
                    }
                }
            };

            JSplitPane splitPane = new JSplitPane();
            splitPane.add(imagePanel, JSplitPane.LEFT);
            splitPane.add(buttonPanel, JSplitPane.RIGHT);
            panel.add(splitPane);
        }
        JScrollPane spane = new JScrollPane(panel);
        frame.add(spane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500,600);
        frame.setVisible(true);
    }
}

如果這是一個“使用一次就扔掉”的程序,我不會費心去解決這個問題。 我會使用命令行為每張圖片生成縮略圖,並在我的程序中使用這些生成的縮略圖。 在內存中保留 700 個縮略圖應該是可行的。

如果這不是一個選項,我會從JTable開始。 您可以創建一個TableModel而不必將所有圖像加載到內存中。 您只需要知道圖像計數。 JTable只希望渲染當時可見的圖像。 警告可能是在渲染器要求它們的那一刻加載圖像可能為時已晚。 我可以想象,當您必須加載幾 MB 大小的圖像時, JTable將無法順利運行。 但這可能可以通過使用填充有工作線程的緩存來解決。 因此,如果渲染器請求第 5 個圖像,您還將前 5 個圖像和 5 個下一個圖像加載到緩存中。

另請注意,如果您正在移動圖片 iso 復制它們,這可能會影響您的TableModel因為您目錄中的圖像數量將發生變化。 一定要考慮到這一點!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM