正如我在问题标题中所声明的那样,我将要对给 定png图像的特定区域进行某种编辑,以通过 单击它来逐像素更改颜色,也许可以帮助自己放大该区域…
我之所以陷入困境,是因为我不知道,到目前为止,我还没有找到一种 显示png的解决方案,该png具有一个“网格”,该网格划分每个像素。
我的意思是,像填字游戏这样的细线可以“突出”每个 像素。
请指出正确的方向!
好的,基本上,这是一个非常“简单”的缩放过程。 图像中的每个像素都由一个具有大小的“单元”表示。每个单元格都 填充有像素的颜色。然后将一个简单的网格覆盖在顶部。
您可以使用滑块更改缩放比例(使网格变大或 变小)。
该示例还利用工具提示支持来显示像素颜色
这个例子虽然没有提供编辑。将 添加MouseListener到,EditorPane并使用与该 getToolTipText方法相同的算法,找到需要更新的像素,这将是一件容易的事。
我的示例使用的是大型精灵(177x345),旨在提供 可变大小的精灵。较小或固定大小的精灵将提供更好的 性能。
import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JViewport; import javax.swing.Scrollable; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class Main { public static void main(String[] args) { new Main(); } public Main() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new SpriteEditorSpane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } catch (IOException ex) { ex.printStackTrace(); } } }); } public class SpriteEditorSpane extends JPanel { private JLabel sprite; private JSlider zoom; private EditorPane editorPane; public SpriteEditorSpane() throws IOException { setLayout(new GridBagLayout()); BufferedImage source = ImageIO.read(new File("sprites/Doctor-01.png")); sprite = new JLabel(new ImageIcon(source)); editorPane = new EditorPane(); editorPane.setSource(source); zoom = new JSlider(2, 10); zoom.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { editorPane.setGridSize(zoom.getValue()); } }); zoom.setValue(2); zoom.setPaintTicks(true); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.gridheight = GridBagConstraints.REMAINDER; add(sprite, gbc); gbc.gridx++; gbc.gridheight = 1; gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1; gbc.weighty = 1; add(new JScrollPane(editorPane), gbc); gbc.gridy++; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1; gbc.weighty = 0; add(zoom, gbc); } } public class EditorPane extends JPanel implements Scrollable { private BufferedImage source; private BufferedImage gridBuffer; private int gridSize = 2; private Color gridColor; private Timer updateTimer; public EditorPane() { updateTimer = new Timer(250, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { doBufferUpdate(); revalidate(); repaint(); } }); updateTimer.setRepeats(false); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { updateBuffer(); } }); setGridColor(new Color(128, 128, 128, 128)); setToolTipText("Sprite"); } @Override public Dimension getPreferredSize() { return source == null ? new Dimension(200, 200) : new Dimension(source.getWidth() * gridSize, source.getHeight() * gridSize); } public void setGridColor(Color color) { if (color != gridColor) { this.gridColor = color; updateBuffer(); } } public Color getGridColor() { return gridColor; } public void setSource(BufferedImage image) { if (image != source) { this.source = image; updateBuffer(); } } public void setGridSize(int size) { if (size != gridSize) { this.gridSize = size; updateBuffer(); } } public BufferedImage getSource() { return source; } public int getGridSize() { return gridSize; } @Override public String getToolTipText(MouseEvent event) { Point p = event.getPoint(); int x = p.x / getGridSize(); int y = p.y / getGridSize(); BufferedImage source = getSource(); String tip = null; if (x < source.getWidth() && y < source.getHeight()) { Color pixel = new Color(source.getRGB(x, y), true); StringBuilder sb = new StringBuilder(128); sb.append("<html><table><tr><td>"); sb.append("R:").append(pixel.getRed()); sb.append(" G:").append(pixel.getGreen()); sb.append(" B:").append(pixel.getBlue()); sb.append(" A:").append(pixel.getAlpha()); String hex = String.format("#%02x%02x%02x%02x", pixel.getRed(), pixel.getGreen(), pixel.getBlue(), pixel.getAlpha()); sb.append("</td></tr><tr><td bgcolor=").append(hex); sb.append("width=20 height=20> </td></tr></table>"); tip = sb.toString(); } return tip; } @Override public Point getToolTipLocation(MouseEvent event) { Point p = new Point(event.getPoint()); p.x += 8; p.y += 8; return p; } protected void doBufferUpdate() { BufferedImage source = getSource(); int gridSize = getGridSize(); gridBuffer = null; if (source != null) { gridBuffer = new BufferedImage(source.getWidth() * gridSize, source.getHeight() * gridSize, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = gridBuffer.createGraphics(); for (int row = 0; row < source.getHeight(); row++) { for (int col = 0; col < source.getWidth(); col++) { int xPos = col * gridSize; int yPos = row * gridSize; Color pixel = new Color(source.getRGB(col, row), true); g2d.setColor(pixel); g2d.fillRect(xPos, yPos, gridSize, gridSize); g2d.setColor(getGridColor()); g2d.drawRect(xPos, yPos, gridSize, gridSize); } } g2d.dispose(); } else if (getWidth() > 0 && getHeight() > 0) { gridBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = gridBuffer.createGraphics(); g2d.setColor(gridColor); for (int xPos = 0; xPos < getWidth(); xPos += gridSize) { g2d.drawLine(xPos, 0, xPos, getHeight()); } for (int yPos = 0; yPos < getHeight(); yPos += gridSize) { g2d.drawLine(0, yPos, getWidth(), yPos); } g2d.dispose(); } } protected void updateBuffer() { updateTimer.restart(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); if (gridBuffer != null) { g2d.drawImage(gridBuffer, 0, 0, this); } g2d.dispose(); } @Override public Dimension getPreferredScrollableViewportSize() { return new Dimension(200, 200); } @Override public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { return 128; } @Override public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { return 128; } @Override public boolean getScrollableTracksViewportWidth() { Container parent = getParent(); return parent instanceof JViewport && parent.getWidth() > getPreferredSize().width; } @Override public boolean getScrollableTracksViewportHeight() { Container parent = getParent(); return parent instanceof JViewport && parent.getHeight() > getPreferredSize().height; } } }
生成“网格”时,整体性能相当慢,您可能 可以使用byte[] bytes = ((DataBufferByte)gridBuffer.getRaster().getDataBuffer()).getData()它将 为您提供byte像素阵列,但是在我的测试中,并没有 太大的不同。