// Near Infinity - An Infinity Engine Browser and Editor // Copyright (C) 2001 - 2005 Jon Olav Hauglid // See LICENSE.txt for license information package org.infinity.resource.graphics; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JScrollPane; import org.infinity.gui.ButtonPanel; import org.infinity.gui.RenderCanvas; import org.infinity.resource.Resource; import org.infinity.resource.ResourceFactory; import org.infinity.resource.ViewableContainer; import org.infinity.resource.key.ResourceEntry; import org.infinity.search.ReferenceSearcher; import org.infinity.util.io.StreamUtils; public final class GraphicsResource implements Resource, ActionListener { private final ResourceEntry entry; private final ButtonPanel buttonPanel = new ButtonPanel(); private BufferedImage image; private JPanel panel; private Palette palette; public GraphicsResource(ResourceEntry entry) throws Exception { this.entry = entry; init(); } // --------------------- Begin Interface ActionListener --------------------- @Override public void actionPerformed(ActionEvent event) { if (buttonPanel.getControlByType(ButtonPanel.Control.FIND_REFERENCES) == event.getSource()) { new ReferenceSearcher(entry, panel.getTopLevelAncestor()); } else if (buttonPanel.getControlByType(ButtonPanel.Control.EXPORT_BUTTON) == event.getSource()) { ResourceFactory.exportResource(entry, panel.getTopLevelAncestor()); } } // --------------------- End Interface ActionListener --------------------- // --------------------- Begin Interface Resource --------------------- @Override public ResourceEntry getResourceEntry() { return entry; } // --------------------- End Interface Resource --------------------- // --------------------- Begin Interface Viewable --------------------- @Override public JComponent makeViewer(ViewableContainer container) { RenderCanvas rcCanvas = new RenderCanvas(image); JScrollPane scroll = new JScrollPane(rcCanvas); scroll.getVerticalScrollBar().setUnitIncrement(16); scroll.getHorizontalScrollBar().setUnitIncrement(16); ((JButton)buttonPanel.addControl(ButtonPanel.Control.FIND_REFERENCES)).addActionListener(this); ((JButton)buttonPanel.addControl(ButtonPanel.Control.EXPORT_BUTTON)).addActionListener(this); panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.add(scroll, BorderLayout.CENTER); panel.add(buttonPanel, BorderLayout.SOUTH); scroll.setBorder(BorderFactory.createLoweredBevelBorder()); return panel; } // --------------------- End Interface Viewable --------------------- public BufferedImage getImage() { return image; } public Palette getPalette() { return palette; } private void init() throws Exception { ByteBuffer buffer = entry.getResourceBuffer(); // Checking signature boolean isBMP = false; if ("BM".equals(StreamUtils.readString(buffer, 0, 2))) { isBMP = true; } image = null; if (isBMP) { int rasteroff = buffer.getInt(10); int width = buffer.getInt(18); int height = buffer.getInt(22); int bitcount = buffer.getShort(28); int compression = buffer.getInt(30); if ((compression == 0 || compression == 3) && bitcount <= 32) { int colsUsed = buffer.getInt(46); // Colorsused if (bitcount <= 8) { if (colsUsed == 0) { colsUsed = 1 << bitcount; } int palSize = 4 * colsUsed; palette = new Palette(buffer, rasteroff - palSize, palSize); } int bytesprline = bitcount * width / 8; int padded = 4 - bytesprline % 4; if (padded == 4) { padded = 0; } image = ColorConvert.createCompatibleImage(width, height, bitcount >= 32); int offset = rasteroff; for (int y = height - 1; y >= 0; y--) { setPixels(buffer, offset, bitcount, bytesprline, y, palette); offset += bytesprline + padded; } } } if (image == null) { try { image = ImageIO.read(entry.getResourceDataAsStream()); } catch (Exception e) { image = null; throw new Exception("Unsupported graphics format"); } } } private void setPixels(ByteBuffer buffer, int offset, int bitcount, int width, int y, Palette palette) { if (bitcount == 4) { int pix = 0; for (int x = 0; x < width; x++) { int color = buffer.get(offset + x) & 0xff; int color1 = (color >> 4) & 0x0f; image.setRGB(pix++, y, palette.getColor(color1)); int color2 = color & 0x0f; image.setRGB(pix++, y, palette.getColor(color2)); } } else if (bitcount == 8) { for (int x = 0; x < width; x++) { image.setRGB(x, y, palette.getColor(buffer.get(offset + x) & 0xff)); } } else if (bitcount == 24) { for (int x = 0; x < width / 3; x++) { int rgb = (buffer.get(offset + 3*x + 2) & 0xff) << 16; rgb |= (buffer.get(offset + 3*x + 1) & 0xff) << 8; rgb |= buffer.get(offset + 3*x) & 0xff; image.setRGB(x, y, rgb); } } else if (bitcount == 32) { for (int x = 0; x < width / 4; x++) { int rgb = buffer.getInt(offset + 4*x); image.setRGB(x, y, rgb); } } } }