今回のプログラムにさらに描画機能を追加すればACEDRAWはかなり完成に近づくことになります。
いままではJavaのGraphics2Dを使用して直線などを描画しようと思っていたのですが、なんか使いにくいので独自の描画ルーチンを作って使おうと思います。
JavaのGraphics2Dのどこが使いにくいかというと、ANDやORといった論理演算で描画することができなかったり、TYPE_BYTE_BINARYやTYPE_BYTE_INDEXEDでイメージを作ってもインデックス番号を指定して描画することができないところです。
以下のパレットデータと
private final int paletts[][] = { // CPN CPn CpN Cpn cPN cPn cpN cpn {0x000000,0x000000,0x000000,0x000000,0xffffff,0xffffff,0xffffff,0xffffff}, // cur {0xe00000,0xe00000,0x000000,0x000000,0xffb0b0,0xffb0b0,0xffffff,0xffffff}, // cur,prv {0x0000e0,0x000000,0x0000e0,0x000000,0xb0c0ff,0xffffff,0xb0c0ff,0xffffff}, // cur,nxt {0xd000d0,0xe00000,0x0000e0,0x000000,0xffb0ff,0xffb0b0,0xb0c0ff,0xffffff} // all }; |
private void updateImg() { int bc,bp,bn; int pal,ix; int srcp = 0; pal = 0; if(frmPBtn.isSelected() && (curFrmNo > 0)) pal = pal + 1; if(frmNBtn.isSelected() && (curFrmNo < totalFrms-1)) pal = pal + 2; for(int y=0; y<imgHeight; y++) { for(int x=0; x<imgByteWidth; x++) { bc = curFrmImg[srcp]; bp = prvFrmImg[srcp]; bn = nxtFrmImg[srcp++]; for(int i=0; i<8; i++) { ix = ((bc >> (7-i)) & 1)*4 + ((bp >> (7-i)) & 1)*2 + ((bn >> (7-i)) & 1); mainImg.setRGB(x*8+i,y,paletts[pal][ix]); } } } grpPnl.repaint(); } |
// Java版AceDrawのためのステップ // 「シンプルACDビュワー2」SimpleAcdViewer2.java // Copyright(c)2006 A.Hiramatsu import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.io.*; import java.util.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.filechooser.*; public class SimpleAcdViewer2 { private final int imgWidth = 320; private final int imgByteWidth = imgWidth / 8; private final int imgHeight = 240; private final int animeFrmSize = 9728; private final int animeFrmImgBytes = imgByteWidth * imgHeight; private final int animeFrmHeadSize = 128; private class AnimeFrame { boolean mark; byte[] img; private AnimeFrame() { this.mark = false; this.img = new byte[animeFrmImgBytes]; } private void setMark(boolean b) { this.mark = b; } private boolean getMark() { return this.mark; } private void setImg(byte[] src) { int n = src.length; if(n > animeFrmImgBytes) n = animeFrmImgBytes; for(int i=0; i<n; i++) { this.img[i] = src[i]; } } private byte[] getImg() { return this.img; } }; private ArrayList<AnimeFrame> aniFrms = new ArrayList<AnimeFrame>(); private final int paletts[][] = { // CPN CPn CpN Cpn cPN cPn cpN cpn {0x000000,0x000000,0x000000,0x000000,0xffffff,0xffffff,0xffffff,0xffffff}, // cur {0xe00000,0xe00000,0x000000,0x000000,0xffb0b0,0xffb0b0,0xffffff,0xffffff}, // cur,prv {0x0000e0,0x000000,0x0000e0,0x000000,0xb0c0ff,0xffffff,0xb0c0ff,0xffffff}, // cur,nxt {0xd000d0,0xe00000,0x0000e0,0x000000,0xffb0ff,0xffb0b0,0xb0c0ff,0xffffff} // all }; private byte[] fileHeadBuf = new byte[animeFrmSize]; private byte[] frameHeadBuf = new byte[animeFrmHeadSize]; private byte[] frameImgBuf = new byte[animeFrmImgBytes]; private byte[] curFrmImg; private byte[] prvFrmImg; private byte[] nxtFrmImg; private int curFrmNo; private int totalFrms; private JFrame mainFrm; private JFileChooser fChoose = new JFileChooser("."); private JLabel lblFrmIndicate; private JToggleButton frmPBtn; private JToggleButton frmNBtn; private BufferedImage mainImg = new BufferedImage(imgWidth,imgHeight, BufferedImage.TYPE_INT_RGB); private JPanel grpPnl = new JPanel() { public void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(mainImg,0,0,this); } }; private void updateImg() { int bc,bp,bn; int pal,ix; int srcp = 0; pal = 0; if(frmPBtn.isSelected() && (curFrmNo > 0)) pal = pal + 1; if(frmNBtn.isSelected() && (curFrmNo < totalFrms-1)) pal = pal + 2; for(int y=0; y<imgHeight; y++) { for(int x=0; x<imgByteWidth; x++) { bc = curFrmImg[srcp]; bp = prvFrmImg[srcp]; bn = nxtFrmImg[srcp++]; for(int i=0; i<8; i++) { ix = ((bc >> (7-i)) & 1)*4 + ((bp >> (7-i)) & 1)*2 + ((bn >> (7-i)) & 1); mainImg.setRGB(x*8+i,y,paletts[pal][ix]); } } } grpPnl.repaint(); } private void doFileOpen() { File f; int n,p; int rlen = 0; long fsize; String s; boolean canRead = false; FileInputStream fi = null; AnimeFrame aniFrm; n = fChoose.showOpenDialog(null); if(n==JFileChooser.APPROVE_OPTION ) { f = fChoose.getSelectedFile(); if(f != null) { s = fChoose.getName(f).toUpperCase(); canRead = true; if(s.length()>4) { if(s.substring(s.length()-4).equals(".ACD")) { try { fi = new FileInputStream(f); } catch(Throwable fe) { new JOptionPane().showMessageDialog(mainFrm,"ファイルのオープンに失敗しました","Error", JOptionPane.ERROR_MESSAGE); canRead = false; } if(canRead) { try { rlen = fi.read(fileHeadBuf); } catch(Throwable fe) { new JOptionPane().showMessageDialog(mainFrm,"ファイルの入力中にエラーが発生しました","Error", JOptionPane.ERROR_MESSAGE); canRead = false; } } if(canRead) { fsize = f.length(); totalFrms = ((int)fileHeadBuf[8] & 0xff) + (((int)fileHeadBuf[9] & 0xff) << 8) + (((int)fileHeadBuf[10] & 0xff) << 16); curFrmNo = 0; aniFrms.clear(); lblFrmIndicate.setText(Integer.toString(curFrmNo+1)+ " / "+Integer.toString(totalFrms)); if((rlen < animeFrmSize) || (fileHeadBuf[0] != 0x41) || (fileHeadBuf[1] != 0x43) || (fileHeadBuf[2] != 0x44) || (fileHeadBuf[3] != 0x00) || (totalFrms < 1) || (fileHeadBuf[11] != 0) || (fsize != (long)animeFrmSize * (totalFrms + 1)) ){ new JOptionPane().showMessageDialog(mainFrm,"ファイルヘッダが壊れています","Error", JOptionPane.ERROR_MESSAGE); canRead = false; } if(canRead) { for(int i=0; i < totalFrms; i++) { try { fi.read(frameHeadBuf); fi.read(frameImgBuf); } catch(Throwable fe) { new JOptionPane().showMessageDialog(mainFrm,"ファイルの入力中にエラーが発生しました","Error", JOptionPane.ERROR_MESSAGE); canRead = false; } if(!canRead) break; aniFrm = new AnimeFrame(); if(frameHeadBuf[0]!=0) aniFrm.setMark(true); aniFrm.setImg(frameImgBuf); aniFrms.add(aniFrm); } } } } else { new JOptionPane().showMessageDialog(mainFrm,"ファイルの拡張子が.ACDではありません","Error", JOptionPane.ERROR_MESSAGE); canRead = false; } } } } if(canRead) { curFrmImg = aniFrms.get(curFrmNo).getImg(); if(curFrmNo < totalFrms-1) { nxtFrmImg = aniFrms.get(curFrmNo+1).getImg(); } updateImg(); } } private ActionListener actLsn = new ActionListener() { public void actionPerformed(ActionEvent e) { if(e.getActionCommand()=="Open") { doFileOpen(); } else if(e.getActionCommand()=="eXit") { System.exit(0); } else { } } }; MouseListener frmFBtnLsn = new MouseAdapter() { public void mousePressed(MouseEvent e) { if(curFrmNo < totalFrms-1) { curFrmNo++; prvFrmImg = curFrmImg; curFrmImg = aniFrms.get(curFrmNo).getImg(); if(curFrmNo < totalFrms-1) { nxtFrmImg = aniFrms.get(curFrmNo+1).getImg(); } updateImg(); lblFrmIndicate.setText(Integer.toString(curFrmNo+1)+ " / "+Integer.toString(totalFrms)); } } }; MouseListener frmBBtnLsn = new MouseAdapter() { public void mousePressed(MouseEvent e) { if(curFrmNo > 0) { curFrmNo--; nxtFrmImg = curFrmImg; curFrmImg = aniFrms.get(curFrmNo).getImg(); if(curFrmNo > 0) { prvFrmImg = aniFrms.get(curFrmNo-1).getImg(); } updateImg(); lblFrmIndicate.setText(Integer.toString(curFrmNo+1)+ " / "+Integer.toString(totalFrms)); } } }; MouseListener frmFMBtnLsn = new MouseAdapter() { public void mousePressed(MouseEvent e) { int frmsv = curFrmNo; if((curFrmNo < totalFrms-1) && (aniFrms.get(curFrmNo).getMark())) { curFrmNo++; } while(curFrmNo < totalFrms-1) { if(! aniFrms.get(curFrmNo).getMark()) { curFrmNo++; } } if(curFrmNo != frmsv) { curFrmImg = aniFrms.get(curFrmNo).getImg(); if(curFrmNo > 0) { prvFrmImg = aniFrms.get(curFrmNo-1).getImg(); } if(curFrmNo < totalFrms-1) { nxtFrmImg = aniFrms.get(curFrmNo+1).getImg(); } updateImg(); lblFrmIndicate.setText(Integer.toString(curFrmNo+1)+ " / "+Integer.toString(totalFrms)); } } }; MouseListener frmBMBtnLsn = new MouseAdapter() { public void mousePressed(MouseEvent e) { int frmsv = curFrmNo; if((curFrmNo > 0) && (aniFrms.get(curFrmNo).getMark())) { curFrmNo--; } while(curFrmNo > 0) { if(! aniFrms.get(curFrmNo).getMark()) { curFrmNo--; } } if(curFrmNo != frmsv) { curFrmImg = aniFrms.get(curFrmNo).getImg(); if(curFrmNo > 0) { prvFrmImg = aniFrms.get(curFrmNo-1).getImg(); } if(curFrmNo < totalFrms-1) { nxtFrmImg = aniFrms.get(curFrmNo+1).getImg(); } updateImg(); lblFrmIndicate.setText(Integer.toString(curFrmNo+1)+ " / "+Integer.toString(totalFrms)); } } }; ItemListener frmPBtnLsn = new ItemListener() { public void itemStateChanged(ItemEvent e) { updateImg(); } }; ItemListener frmNBtnLsn = new ItemListener() { public void itemStateChanged(ItemEvent e) { updateImg(); } }; private void initProg() { curFrmImg = new byte[animeFrmImgBytes]; prvFrmImg = new byte[animeFrmImgBytes]; nxtFrmImg = new byte[animeFrmImgBytes]; for(int i=0; i < animeFrmImgBytes;i++) { curFrmImg[i] = (byte)0xff; prvFrmImg[i] = (byte)0xff; nxtFrmImg[i] = (byte)0xff; } } private void makeFrame() { JFrame.setDefaultLookAndFeelDecorated(true); JDialog.setDefaultLookAndFeelDecorated(true); JFrame mainFrm = new JFrame("シンプルACDビュワー2"); mainFrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel mainPnl = new JPanel(new BorderLayout(4,4)); JMenuBar mainMenu = new JMenuBar(); grpPnl.setPreferredSize(new Dimension(imgWidth,imgHeight)); JPanel frmFBPnl = new JPanel(new GridLayout(1,6,2,2)); JButton frmBMBtn = new JButton("<<"); frmBMBtn.addMouseListener(frmBMBtnLsn); JButton frmBBtn = new JButton("<"); frmBBtn.addMouseListener(frmBBtnLsn); JButton frmFBtn = new JButton(">"); frmFBtn.addMouseListener(frmFBtnLsn); JButton frmFMBtn = new JButton(">>"); frmFMBtn.addMouseListener(frmFMBtnLsn); frmPBtn = new JToggleButton("P"); frmPBtn.addItemListener(frmPBtnLsn); frmNBtn = new JToggleButton("N"); frmNBtn.addItemListener(frmNBtnLsn); frmFBPnl.add(frmBMBtn); frmFBPnl.add(frmBBtn); frmFBPnl.add(frmFBtn); frmFBPnl.add(frmFMBtn); frmFBPnl.add(frmPBtn); frmFBPnl.add(frmNBtn); JPanel frmInfoPnl = new JPanel(new BorderLayout(2,2)); lblFrmIndicate = new JLabel("0 / 0"); JLabel lblFrmFrame = new JLabel("Frame:"); frmInfoPnl.add(lblFrmFrame,BorderLayout.WEST); frmInfoPnl.add(lblFrmIndicate,BorderLayout.CENTER); JPanel frmCtrlPnl = new JPanel(new BorderLayout(8,4)); frmCtrlPnl.add(frmInfoPnl,BorderLayout.NORTH); frmCtrlPnl.add(frmFBPnl,BorderLayout.CENTER); mainPnl.add(grpPnl,BorderLayout.CENTER); mainPnl.add(frmCtrlPnl,BorderLayout.SOUTH); mainPnl.setBorder(new EmptyBorder(4,4,4,4)); JMenu fileMenu = new JMenu("File"); fileMenu.setMnemonic(KeyEvent.VK_F); JMenuItem fileOpen = new JMenuItem("Open",KeyEvent.VK_O); fileOpen.addActionListener(actLsn); JMenuItem fileeXit = new JMenuItem("eXit",KeyEvent.VK_X); fileeXit.addActionListener(actLsn); fileMenu.add(fileOpen); fileMenu.add(fileeXit); mainMenu.add(fileMenu); mainFrm.getContentPane().add(mainPnl); mainFrm.setJMenuBar(mainMenu); mainFrm.pack(); mainFrm.setVisible(true); updateImg(); } public static void main(final String[] args) { SimpleAcdViewer2 myProg = new SimpleAcdViewer2(); myProg.initProg(); myProg.makeFrame(); } } |