/******************************************************************************* * Copyright (c) 2015 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. *******************************************************************************/ package jsettlers.graphics.debug; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import javax.swing.JPanel; /** * Debug class that displays a file as an image. * * @author michael * */ public class DataImage extends JPanel implements MouseListener, MouseMotionListener { /** * */ private static final long serialVersionUID = 6066076752384349596L; private final byte[] data; private int offset = 0; private int pixelLength = 1; // in bytes private long redMask = 0xff; private long greenMask = 0x0000; private long blueMask = 0x0000; private int width = 128; // in pixel private int height = 200; private int currentMarked = 0; private boolean littleEndian = true; private int pixelSize = 3; public DataImage(byte[] data) { this.data = data; this.addMouseListener(this); this.addMouseMotionListener(this); for (int i = 64; i < 100000; i += 128) { System.out.println(getData(i, 1)); } } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; for (int index = 0; index < getImageHeight() * getImageWidth(); index++) { int pos = pixelIndexToDataPos(index); long current = getData(pos, this.pixelLength); Color c = new Color(getMasked(current, this.redMask), getMasked(current, this.greenMask), getMasked(current, this.blueMask)); g2d.setColor(c); Point screen = dataPosToScreen(pos); g2d.fillRect(screen.x, screen.y, this.pixelSize, this.pixelSize); } paintMarkedPoint(g2d); } /** * Uses a mask and maps the result to 0..1 * * @param pos * @param greenMask2 * @return */ private float getMasked(long toMask, long mask) { long maxValue = 1; // one bigger than max value long resultValue = 0; for (int bitIndex = 63; bitIndex >= 0; bitIndex--) { long currentBit = toMask & (1 << bitIndex); long maskBit = mask & (1 << bitIndex); if (maskBit != 0) { resultValue *= 2; if (currentBit != 0) { resultValue += 1; } maxValue *= 2; } } if (maxValue <= 1) { return .0f; } else { return ((float) resultValue) / (maxValue - 1); } } /** * Gets a data block in the current endianness. * * @param pos * @param length * @return */ private long getData(int pos, int length) { if (pos < 0 || pos + length >= this.data.length) { return 0; } long result = 0; for (int i = 0; i < length && i < 8; i++) { int resultByte; if (this.littleEndian) { resultByte = i; } else { resultByte = length - 1 - i; } result |= (0xffl & this.data[pos + i]) << (resultByte * 8); } // if ((pos & 0x04) != 0) { result += pos; // } else { // result -= pos; // } result &= 0xff; if (pos % 128 < 64) { result = 0xff - result; } // result |= (pos & 0xffff) << 8; if (result < 100 || result > 155) { return 0; } else { return result; } // return result; } @Override public Dimension getPreferredSize() { return new Dimension(this.width, getImageHeight()); } public void setOffset(int offset) { this.offset = offset; this.repaint(); } public int getOffset() { return this.offset; } public void setPixelLength(int pixelLength) { this.pixelLength = pixelLength; this.repaint(); } public int getPixelLength() { return this.pixelLength; } public void setImageWidth(int width) { this.width = width; this.repaint(); } public int getImageWidth() { return this.width; } public void setImageHeight(int height) { this.height = height; this.repaint(); } public int getImageHeight() { return this.height; } private int screenToDataPos(Point p) { int x = p.x / this.pixelSize; int y = p.y / this.pixelSize; return this.offset + (y * getImageWidth() + x) * getPixelLength(); } private Point dataPosToScreen(int pos) { int y = (pos - this.offset) / getPixelLength() / getImageWidth(); int x = (pos - this.offset) / getPixelLength() - y * getImageWidth(); return new Point(x * this.pixelSize, y * this.pixelSize); } private int pixelIndexToDataPos(int index) { return index * getPixelLength() + this.offset; } private void paintMarkedPoint(Graphics2D g) { Point pos = dataPosToScreen(this.currentMarked); int realCurrentMarked = screenToDataPos(pos); g.setColor(Color.RED); g.drawRect(pos.x - 1, pos.y - 1, this.pixelSize + 2, this.pixelSize + 2); String str = "" + realCurrentMarked + ":"; /* * for (int i = 0; i < getPixelLength(); i++) { str += " " + Integer.toHexString(0xff & data[i]); } */ long pixel = getData(realCurrentMarked, getPixelLength()); str += " 0x" + String.format("%0" + (getPixelLength() * 2) + "x", pixel); int fontHeight = g.getFontMetrics().getHeight() + 4; g.setColor(Color.WHITE); g.fillRect(0, getHeight() - fontHeight, getWidth(), fontHeight); g.setColor(Color.BLACK); g.drawString(str, 2, getHeight() - 2); } private void mouseDownOver(Point point) { this.currentMarked = screenToDataPos(point); repaint(); } @Override public void mouseClicked(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { mouseDownOver(e.getPoint()); } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseDragged(MouseEvent e) { mouseDownOver(e.getPoint()); } @Override public void mouseMoved(MouseEvent e) { } public void setLittleEndian(boolean littleEndian) { this.littleEndian = littleEndian; this.repaint(); } public boolean isLittleEndian() { return this.littleEndian; } public void setRedMask(long redMask) { this.redMask = redMask; this.repaint(); } public long getRedMask() { return this.redMask; } public void setGreenMask(long greenMask) { this.greenMask = greenMask; this.repaint(); } public long getGreenMask() { return this.greenMask; } public void setBlueMask(long blueMask) { this.blueMask = blueMask; this.repaint(); } public long getBlueMask() { return this.blueMask; } /** * moves the marker * * @param x * @param y */ public void moveMarked(int x, int y) { this.currentMarked += (x + y * getImageWidth()) * getPixelLength(); repaint(); } }