java - 以非常高分辨率绘制

标签 java swing graphics paint

我目前正在尝试以非常高分辨率绘制波形(由于缩放)。因此,波形是在 JScrollPane 中绘制的。我希望能够用它绘制大约 50.000-60.000 像素宽度。

不幸的是,它在大约 34000 像素宽度时停止正确绘制。问题是它不画大约。第一个屏幕尺寸不再存在,但其余部分已正确绘制。由于我在图形方面只有很少的经验,因此我认为您也许能够帮助我决定如何尽可能地解决此问题。

我考虑过通过重新绘制第一个屏幕尺寸(例如使用 repaint(Rectangle))或者将图片分成 3 个或更多帧来处理它。如果我选择第二个选项,我不知道是否应该将其分开并全部绘制在一起,或者仅在视口(viewport)上可见时才绘制它。或者也许还有另一个我想不出的更好的解决方案?

我希望你能帮助我解决这个问题,并节省我大量的时间来尝试一切。提前致谢。

这是所请求的可执行文件。您可以看到宽度约为 34.000 像素的绘图不正确。可以在 System.out 中读取当前像素。绘图不适用于 mp3,因为不受支持。我建议尝试使用 .wav。

主类:

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import java.awt.GridBagLayout;

import java.awt.GridBagConstraints;

public class Main {

private JFrame mainFrame;
private JPanel upperPanel;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                Main window = new Main();
                window.mainFrame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Initialize Application
 */
public Main() {

    initializeMainFrame();
    initializePanels();
}

private void initializePanels() {

    upperPanel = new MainPanel();

    upperPanel.setPreferredSize(new Dimension(1000, 500));

    GridBagConstraints c = new GridBagConstraints();
    c.anchor = GridBagConstraints.NORTH;
    c.weightx = 1.0;
    c.weighty = 1.0;
    c.fill = GridBagConstraints.BOTH;
    c.gridy = 0;
    c.gridwidth = GridBagConstraints.REMAINDER;

    mainFrame.add(upperPanel, c);

}

private void initializeMainFrame() {

    mainFrame = new JFrame("Waveform Example");
    mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    GraphicsEnvironment ge = GraphicsEnvironment
            .getLocalGraphicsEnvironment();
    Rectangle gebounds = ge.getMaximumWindowBounds();
    mainFrame.setSize(gebounds.getSize());
    mainFrame.setLocationRelativeTo(null);
    mainFrame.setVisible(true);
    mainFrame.setLayout(new GridBagLayout());

    JMenuBar menuBar = new JMenuBar();
    JMenu fileMenu = new JMenu("File");

    JMenuItem importAudio = new JMenuItem("Import Audio");

    menuBar.setLayout(new GridBagLayout());
    GridBagConstraints c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.anchor = GridBagConstraints.WEST;
    c.weightx = 0.3;
    c.weighty = 0.3;
    c.gridx = 0;
    c.gridy = 0;

    mainFrame.setJMenuBar(menuBar);
    menuBar.add(fileMenu, c);
    c.gridx = 1;
    c.gridy = 0;

    fileMenu.add(importAudio);

    importAudio.addActionListener(new importAudioActionListener());

}

private class importAudioActionListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent event) {

        File f = getFile();


        if (f != null) {

            AudioInfo audioInfo = createAudioInfo(f);

            mainFrame.remove(upperPanel);

            upperPanel = new MainPanel(audioInfo);

            upperPanel.setPreferredSize(new Dimension(1000, 500));

            GridBagConstraints c = new GridBagConstraints();
            c.anchor = GridBagConstraints.NORTH;
            c.gridy = 0;
            c.weightx = 1.0;
            c.weighty = 1.0;
            c.fill = GridBagConstraints.BOTH;
            c.gridwidth = GridBagConstraints.REMAINDER;

            mainFrame.add(upperPanel, c);

            mainFrame.pack();

        }
    }

    private AudioInfo createAudioInfo(File f) {
        AudioInputStream audioInputStream = null;

        try {

            audioInputStream = AudioSystem.getAudioInputStream(f);

        } catch (UnsupportedAudioFileException e1) {

            System.out.println("Invalid Audio Format");
        } catch (IOException e1) {

            System.out.println("Invalid Input File");
        }

        AudioInfo retInfo = new AudioInfo(audioInputStream,
                (int) f.length());
        return retInfo;
    }

    private File getFile() {
        // New file chooser only shows and accepts MP3 files.
        JFileChooser fc = new JFileChooser();
        fc.setAcceptAllFileFilterUsed(false);
        fc.showOpenDialog(null);

        File f = null;
        try {
            f = fc.getSelectedFile();
        } catch (Exception fnfe) {
            f = null;
            System.out.println("File not found!");
        }
        return f;
    }
}

  }

包含 JPanel 的面板:

   import java.awt.BorderLayout;
  import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.GridBagConstraints;
  import java.awt.GridBagLayout;
 import java.awt.Rectangle;
 import java.awt.event.ComponentEvent;
 import java.awt.event.ComponentListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;

   public class MainPanel extends JPanel implements MouseWheelListener,
    ComponentListener {


private boolean finishedZoom = true;
private int mouseX;
private static final long serialVersionUID = 1L;
private AudioInfo audioInfo;
private int scale = 1;
private Dimension panelSize;
private int mouseXScaled;
private int mouseYScaled;

private JScrollPane scrollPane;
private int sizeNormalizer = 150;
private JPanel thisPanel = this;
private JPanel content;

public MainPanel() {

}

public MainPanel(AudioInfo audioInfo) {
    this.audioInfo = audioInfo;
    this.setLayout(new BorderLayout());

    panelSize = new Dimension(1000, 500);

    content = getContent();

    scrollPane = new JScrollPane(content);
    scrollPane.setPreferredSize(panelSize);
    scrollPane
            .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);


    this.add(scrollPane, BorderLayout.CENTER);
    this.setPreferredSize(panelSize);

    content.addMouseWheelListener(this);
    content.addComponentListener(this);

}

private JPanel getContent() {
    GridBagConstraints c = new GridBagConstraints();
    c.fill = GridBagConstraints.BOTH;
    c.weightx = 1.0;
    c.weighty = 1.0;
    JPanel retContent = new JPanel(false);
    retContent.setPreferredSize(panelSize);
    retContent.setLayout(new GridBagLayout());

    WaveformPanel waveformPanel = new WaveformPanel(audioInfo);
    waveformPanel.setPreferredSize(panelSize);

    retContent.setBackground(Color.green);

    c.gridwidth = GridBagConstraints.REMAINDER; // end row
    retContent.add(waveformPanel, c);

    return retContent;
}

public void mouseWheelMoved(MouseWheelEvent e) {

    boolean changed = false;
    double notches = e.getWheelRotation();
    if (e.isControlDown() && finishedZoom) {

        int newScale = (int) (scale + notches * (-1) * 2);

        int newWidth = (int) ((thisPanel.getPreferredSize().getWidth()) * newScale);

        if (newWidth > content.getPreferredSize().getWidth()) {
            System.out.println("new width original: " + newWidth);
            content.setVisible(false);
            content.setPreferredSize(new Dimension(
                    newWidth,
                    (int) ((thisPanel.getPreferredSize().getHeight() - sizeNormalizer) / 3 * 2)));
            content.setVisible(true);
            mouseXScaled = e.getX() / scale * newScale;
            mouseYScaled = e.getY() / scale * newScale;
            scale = newScale;
            changed = true;

        } else if (newWidth < content.getPreferredSize().getWidth()
                && newWidth > thisPanel.getWidth()) {

            content.setVisible(false);
            content.setPreferredSize(new Dimension(
                    newWidth,
                    (int) ((thisPanel.getPreferredSize().getHeight() - sizeNormalizer) / 3 * 2)));
            content.setVisible(true);
            mouseXScaled = e.getX() / scale * newScale;
            mouseYScaled = e.getY() / scale * newScale;
            scale = newScale;
            changed = true;

        } else if (newWidth <= thisPanel.getWidth()) {
            newWidth = (int) (thisPanel.getPreferredSize().getWidth());
            newScale = 1;
            content.setVisible(false);
            content.setPreferredSize(new Dimension(
                    newWidth,
                    (int) ((thisPanel.getPreferredSize().getHeight() - sizeNormalizer) / 3 * 2)));
            content.setVisible(true);
            mouseXScaled = e.getX() / scale * newScale;
            mouseYScaled = e.getY() / scale * newScale;
            scale = newScale;
        }
        if (changed) {
            finishedZoom = false;
        }
        mouseX = e.getX();

    } else if (!e.isControlDown()) {
        int scrollBarValue =     scrollPane.getHorizontalScrollBar().getValue();
        Rectangle viewRect = scrollPane.getViewport().getViewRect();

        scrollPane
                .getHorizontalScrollBar()
                .setValue(
                        (int) ((int) scrollBarValue       +           ((viewRect.width - 100) * notches)));

    }

}

public int getHorizontalScroll() {
    return scrollPane.getHorizontalScrollBar().getValue();
}

@Override
public void componentHidden(ComponentEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void componentMoved(ComponentEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void componentResized(ComponentEvent arg0) {

    if (mouseXScaled != 0 && mouseYScaled != 0) {

        int scrollBarVal = scrollPane.getHorizontalScrollBar().getValue();

        int newX = (int) (scrollBarVal + mouseXScaled - mouseX);
        scrollPane.getHorizontalScrollBar().setValue(newX);
        finishedZoom = true;

    }

}

@Override
public void componentShown(ComponentEvent arg0) {
    // TODO Auto-generated method stub

}
 }

音频信息类:

import java.io.IOException;
import javax.sound.sampled.AudioInputStream;

  public class AudioInfo {
private static final int NUM_BITS_PER_BYTE = 8;

private AudioInputStream encodedInputSream;
private int[][] encodedSamplesContainer;
private byte[] encodedBuffer;

// cached values
private int sampleMax = 0;
private int sampleMin = 0;
private double biggestSample;

public AudioInfo(AudioInputStream encodedInputStream, int fileSize) {

    encodedBuffer = new byte[fileSize];
    this.encodedInputSream = encodedInputStream;
    encodedBuffer = createSampleArrayCollection(encodedInputStream,
            encodedBuffer);
    encodedSamplesContainer = getSampleArray(encodedBuffer);

    if (sampleMax > sampleMin) {
        biggestSample = sampleMax;
    } else {
        biggestSample = Math.abs(((double) sampleMin));
    }

}

protected int getNumberOfChannels() {


    return 2;

}

/**
 * Reads the audio input stream into a tmp array and then inserts the tmp
 * array into a buffer array. Resets the mark of the audio input stream
 * after finish buffering. Then cuts the array from fileSize*10 to the final
 * size.
 */
private byte[] createSampleArrayCollection(AudioInputStream inputStream,
        byte[] inBuffer) {
    byte[] buffer = new byte[inBuffer.length];
    int sumReadBytes = 0;
    try {
    //  inputStream.mark(Integer.MAX_VALUE);
        //inputStream.reset();

        boolean end = false;

        while (!end) {
            int available = inputStream.available();
            if (available <= 0) {
                end = true;
            }
            if (!end) {
                byte[] tmp = new byte[available];

                int readBytes = inputStream.read(tmp);

                tmp = cutArray(tmp, readBytes);
                insertArray(buffer, tmp, sumReadBytes);
                sumReadBytes += readBytes;

            }

        }

        //inputStream.reset();

    } catch (IOException e) {
        e.printStackTrace();
    }

    buffer = cutArray(buffer, sumReadBytes);

    return buffer;

}

/**
 * 
 * @param cutThis
 *            array that has to be cut
 * @param cutPoint
 *            index at which the array will be cut off
 * @return the buffer array cut off at the point of cutpoint
 */
private byte[] cutArray(byte[] cutThis, int cutPoint) {

    byte[] tmp = new byte[cutPoint];

    for (int i = 0; i < tmp.length; i++) {
        tmp[i] = cutThis[i];

    }

    return tmp;
}

/**
 * 
 * @param insertIntoThis
 *            the array you want to insert in the other
 * @param tmp
 *            the array that is going to be inserted
 */
private byte[] insertArray(byte[] insertIntoThis, byte[] tmp,
        int nextEmptyField) {
    for (int i = 0; i < tmp.length; i++) {
        insertIntoThis[nextEmptyField] = tmp[i];
        nextEmptyField++;

    }
    return insertIntoThis;
}

/**
 * 
 * @param eightBitByteArray
 *            Array of an eight bit byte array.
 * @return int audio information array for every channel.
 */
private int[][] getSampleArray(byte[] eightBitByteArray) {
    int[][] toReturn = new int[getNumberOfChannels()][eightBitByteArray.length
            / (2 * getNumberOfChannels()) + 1];
    int index = 0;

    // loop through the byte[]
    for (int t = 0; t + 4 < eightBitByteArray.length;) {
        // for each iteration, loop through the channels
        for (int a = 0; a < getNumberOfChannels(); a++) {
            // do the byte to sample conversion
            // see AmplitudeEditor for more info

            int low = (int) eightBitByteArray[t];
            t++;
            int high = (int) eightBitByteArray[t];
            t++;
            int sample = (high << 8) + (low & 0x00ff);

            if (sample < sampleMin) {
                sampleMin = sample;
            } else if (sample > sampleMax) {
                sampleMax = sample;
            }

            // set the value.

            toReturn[a][index] = sample;

        }
        index++;

    }
    return toReturn;
}

/**
 * 
 * @param panelHeight
 * @return calculated yScaleFactor
 */
public double getYScaleFactor(int panelHeight) {
    return (panelHeight / (biggestSample * 2 * 1.5));
}

/**
 * 
 * @param channel
 *            number of the channel you want the audio information of
 * @return int array of the audio information of the given channel.
 */
protected int[] getAudio(int channel) {
    return encodedSamplesContainer[channel];
}

/**
 * 
 * @param xScale
 * @return calculates the increment for given xScale
 */
protected int getIncrement(double xScale) {
    try {
        int increment = (int) (encodedSamplesContainer[0].length / (encodedSamplesContainer[0].length * xScale));
        return increment;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return -1;
}

  }

波形面板类别:

    import javax.swing.*;

   import java.awt.*;

   public class WaveformPanel extends JPanel {

private static final long serialVersionUID = 1L;
private static final Color BACKGROUND_COLOR = Color.black;
private static final Color REFERENCE_LINE_COLOR = Color.blue;
private static final Color WAVEFORM_COLOR = Color.blue;

private AudioInfo helper;
private int[] samples;

public WaveformPanel(AudioInfo helper) {
    super();
    this.helper = helper;
    setBackground(BACKGROUND_COLOR);
    samples = helper.getAudio(0);

}

/**
 * Paints the component of the melted channel audio data.
 */
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    int lineHeight = getHeight() / 2;
    g.setColor(REFERENCE_LINE_COLOR);
    g.drawLine(0, lineHeight, (int) getWidth(), lineHeight);

    drawWaveform(g, samples);

}

protected double getXScaleFactor(int panelWidth) {
    double width = (double) panelWidth;
    return (width / ((double) samples.length));
}

private double getIncrement(double xScale) {
    try {
        double increment = (samples.length / (samples.length * xScale));
        return increment;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return -1;
}

/**
 * @param g
 *            graphic of this panel
 * @param samples
 *            audio samples of a channel
 * 
 *            Draws a waveform with given input on a graphic.
 */
protected void drawWaveform(Graphics g, int[] samples) {

    int buffer = 30;
    if (samples == null) {
        return;
    }

    double oldX = 0;
    double xIndex = 0;

    double increment = getIncrement(getXScaleFactor(getWidth() - buffer * 2));

    g.setColor(WAVEFORM_COLOR);
    System.out.println("width: " + this.getWidth());

    double t = 0;

    int drawLength = samples.length;

    for (; t < drawLength; t += increment) {
        double scaleFactor = helper.getYScaleFactor(getHeight());
        double scaledSample = samples[(int) t] * scaleFactor;
        double y = ((getHeight() / 2) - (scaledSample));
        double yMirror = ((getHeight() / 2) + scaledSample);

        g.drawLine((int) (oldX + buffer), (int) yMirror,
                (int) (xIndex + buffer), (int) y);

        xIndex++;
        oldX = xIndex;
    }

}

   }

最佳答案

作为替代方案,请参阅此 MCTaRE,它成功渲染了宽度两倍的图像。将其滚动到半宽(或任何宽度)以查看..没有伪影的图像。

请注意,我在该示例中调用了 setPreferredSize 以保存一些代码行,但请参阅 Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? (是的。)

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

class BigImageWaveform {

    public static void main(String[] args) {
        final BufferedImage bi = new BufferedImage(
            2*34000, 500, BufferedImage.TYPE_INT_RGB);
        draw(bi);
        Runnable r = new Runnable() {
            @Override
            public void run() {
                JScrollPane jsp = new JScrollPane(
                    new JLabel(new ImageIcon(bi)),
                    JScrollPane.VERTICAL_SCROLLBAR_NEVER,
                    JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
                Dimension d = jsp.getPreferredSize();
                jsp.setPreferredSize(new Dimension(1000, (int)d.getHeight()));
                JOptionPane.showMessageDialog(null, jsp);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }

    public static void draw(BufferedImage bi) {
        Graphics2D g = bi.createGraphics();
        int w = bi.getWidth();
        int h = bi.getHeight();
        GradientPaint gp = new GradientPaint(
            0f,0f,Color.RED,
            101f,0f,Color.GREEN,true);
        g.setPaint(gp);
        g.fillRect(0,0,w,h);
        gp = new GradientPaint(
            0f,0f,new Color(0,0,255,128),
            97f,103f,new Color(220,0,220,164), true);
        g.setPaint(gp);
        g.fillRect(0,0,w,h);
        gp = new GradientPaint(
            0f,0f,new Color(0,0,0,0),
            (float)w,0f,new Color(0,0,0,128), true);
        g.setPaint(gp);
        g.fillRect(0,0,w,h);
        g.dispose();
    }
}

关于java - 以非常高分辨率绘制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22057038/

相关文章:

java - JTextArea中如何使用html标签

java - 仅从字符串的右侧删除空格

Java向keyReleased添加时间?

c++ - QGLWidget::renderText 边界框

Java 为什么我不能使用图形在面板上绘制

html - 创建一个免费的选择图像 map

java - 处理输入和输出时, "faster"会是什么?

java - Windows操作系统中系统重启后如何获取旧进程ID?

java - 将 JPanel 添加到 JFrame 的成功率为 50%

java - 如何检测外部 Java 应用程序中的按钮何时被按下?