diff --git a/pom.xml b/pom.xml index e43cd5f..3c91035 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,5 @@ - 4.0.0 info.istlab.Zemi01 @@ -24,6 +25,37 @@ 3.8.1 test + + + org.piccolo2d + piccolo2d-core + 3.0.1 + + + + org.piccolo2d + piccolo2d-examples + 3.0.1 + + + + org.piccolo2d + piccolo2d-extras + 3.0.1 + + + + + org.apache.commons + commons-lang3 + 3.12.0 + + + + net.java.linoleum + jlfgr + 1_0 + @@ -44,8 +76,8 @@ jar-with-dependencies @@ -67,4 +99,4 @@ - + \ No newline at end of file diff --git a/src/main/java/info/istlab/Zemi01/ClipboardImage.java b/src/main/java/info/istlab/Zemi01/ClipboardImage.java new file mode 100644 index 0000000..c849570 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/ClipboardImage.java @@ -0,0 +1,84 @@ +package info.istlab.Zemi01; + +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; + +/** + * https://stackoverflow.com/questions/7834768/setting-images-to-clipboard-java + */ +public class ClipboardImage { + /** + * Retrieve an image from the system clipboard. + * + * @return the image from the clipboard or null if no image is found + */ + public static Image read() { + Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null); + + try { + if (t != null && t.isDataFlavorSupported(DataFlavor.imageFlavor)) { + Image image = (Image) t.getTransferData(DataFlavor.imageFlavor); + return image; + } + } catch (Exception e) { + } + + return null; + } + + /** + * Place an image on the system clipboard. + * + * @param image - the image to be added to the system clipboard + */ + public static void write(Image image) { + if (image == null) + throw new IllegalArgumentException("Image can't be null"); + + ImageTransferable transferable = new ImageTransferable(image); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(transferable, null); + } + + static class ImageTransferable implements Transferable { + private Image image; + + public ImageTransferable(Image image) { + this.image = image; + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException { + if (isDataFlavorSupported(flavor)) { + return image; + } else { + throw new UnsupportedFlavorException(flavor); + } + } + + public boolean isDataFlavorSupported(DataFlavor flavor) { + return flavor == DataFlavor.imageFlavor; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { DataFlavor.imageFlavor }; + } + } + + public static void main(String[] args) { + Image image = Toolkit.getDefaultToolkit().createImage("???.jpg"); + ClipboardImage.write(image); + + javax.swing.ImageIcon icon = new javax.swing.ImageIcon(ClipboardImage.read()); + javax.swing.JLabel label = new javax.swing.JLabel(icon); + + javax.swing.JFrame frame = new javax.swing.JFrame(); + frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); + frame.getContentPane().add(label); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff --git a/src/main/java/info/istlab/Zemi01/Launcher.java b/src/main/java/info/istlab/Zemi01/Launcher.java index 164c28e..6622633 100644 --- a/src/main/java/info/istlab/Zemi01/Launcher.java +++ b/src/main/java/info/istlab/Zemi01/Launcher.java @@ -15,9 +15,10 @@ public class Launcher extends JPanel implements ActionListener { String[] options; + public static JFrame frame; public static void show(String[] opts) { - JFrame jf = new JFrame("Launcher"); + JFrame jf = frame = new JFrame("Launcher"); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.getContentPane().add(new Launcher(opts)); diff --git a/src/main/java/info/istlab/Zemi01/ScreenCapture.java b/src/main/java/info/istlab/Zemi01/ScreenCapture.java index b11897b..dc23a36 100644 --- a/src/main/java/info/istlab/Zemi01/ScreenCapture.java +++ b/src/main/java/info/istlab/Zemi01/ScreenCapture.java @@ -10,8 +10,10 @@ import javax.imageio.ImageIO; +import info.istlab.Zemi01.imgview.ImageEditorFrame; + public class ScreenCapture { - public static void capture(Rectangle maybe, String dirPath) { + public static void capture(Rectangle captureRect, String dirPath) { Toolkit.getDefaultToolkit().beep(); File dir = new File(dirPath); @@ -25,15 +27,16 @@ // // メインウィンドウの右にあることを想定するため、メインウィンドウの位置とサイズを取得 // Point pos = MainWindow.frame.getLocation(); // Dimension dim = MainWindow.frame.getSize(); - // Rectangle maybe = new Rectangle(pos.x + dim.width, pos.y, 564, 322); - // System.out.println(maybe.toString()); + // Rectangle captureRect = new Rectangle(pos.x + dim.width, pos.y, 564, 322); + // System.out.println(captureRect.toString()); // Rectangle screenSize = new // Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); // Rectangle screenSize = new // Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); - BufferedImage screenShot = robot.createScreenCapture(maybe); + BufferedImage screenShot = robot.createScreenCapture(captureRect); ImageIO.write(screenShot, "png", file); + // short[][][] brgb = bufferedImage2ByteArray(screenShot); // replace(screenShot, brgb); // 水色を黒(0x030303)に変換 // // うさこれエリアを探索(画像中心から、上下左右にボーダーを探索していく。) @@ -54,8 +57,13 @@ } catch (IOException e) { e.printStackTrace(); } + // 編集ウィンドウを表示する。 + ImageEditorFrame ief = ImageEditorFrame.createFromFile(file, Launcher.frame); + // ief.setSize(captureRect.getSize()); + ief.setLocation(captureRect.getLocation()); } + // private static byte[][] bitmap2map(BufferedImage screenShot, Rectangle area) { // int x = area.x; // int y = area.y; diff --git a/src/main/java/info/istlab/Zemi01/imgview/BUtil.java b/src/main/java/info/istlab/Zemi01/imgview/BUtil.java new file mode 100644 index 0000000..c7f2a5e --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/BUtil.java @@ -0,0 +1,394 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.TreeMap; + +import org.piccolo2d.PNode; +import org.piccolo2d.activities.PActivity; +import org.piccolo2d.util.PBounds; + +public class BUtil { + public static int getArea(PBounds pb) { + double w = pb.getWidth(); + double h = pb.getHeight(); + return (int) (w * h); + } + + public static PBounds zoomBounds(PBounds pb, double rate) { + double x = pb.getX(); + double y = pb.getY(); + double w = pb.getWidth(); + double h = pb.getHeight(); + double nw = w * rate; + double nh = h * rate; + double nx = x - (nw - w) / 2; + double ny = y - (nh - h) / 2; + return new PBounds(nx, ny, nw, nh); + } + + public static PBounds zoomBoundsX(PBounds pb, double rate) { + double x = pb.getX(); + double y = pb.getY(); + double w = pb.getWidth(); + double h = pb.getHeight(); + double nw = w * rate; + double nh = h; + double nx = x - (nw - w) / 2; + double ny = y - (nh - h) / 2; + return new PBounds(nx, ny, nw, nh); + } + + public static PBounds plusBounds(PBounds pb, int plusx, int plusy) { + double x = pb.getX(); + double y = pb.getY(); + double w = pb.getWidth(); + double h = pb.getHeight(); + double nw = w + plusx; + double nh = h + plusy; + double nx = x - (nw - w) / 2; + double ny = y - (nh - h) / 2; + return new PBounds(nx, ny, nw, nh); + } + + public static PBounds plusBounds(Rectangle2D pb, int plusx, int plusy) { + double x = pb.getX(); + double y = pb.getY(); + double w = pb.getWidth(); + double h = pb.getHeight(); + double nw = w + plusx; + double nh = h + plusy; + double nx = x - (nw - w) / 2; + double ny = y - (nh - h) / 2; + return new PBounds(nx, ny, nw, nh); + } + + // pos = {0, 1, 2, 3 } = {full, top, middle, bottom}; + public static PBounds halfBounds(PBounds pb, int pos) { + double x = pb.getX(); + double y = pb.getY(); + double w = pb.getWidth(); + double h = pb.getHeight(); + if (pos == 0) { + return pb; + } + if (pos == 1) { + double nx = x; + double ny = y; + double nw = w; + double nh = h / 2; + return new PBounds(nx, ny, nw, nh); + } + if (pos == 2) { + double nx = x; + double ny = y + h / 4; + double nw = w; + double nh = h / 2; + return new PBounds(nx, ny, nw, nh); + } + if (pos == 3) { + double nx = x; + double ny = y + h / 2; + double nw = w; + double nh = h / 2; + return new PBounds(nx, ny, nw, nh); + } + return null; + } + + public static PBounds explainBounds(PBounds firstpb, PBounds panelpb, + PBounds cameraview, double width) { + double fpbw = firstpb.width; + double zoom = width / fpbw; + PBounds tempb = zoomBoundsX(firstpb, zoom); + + double preferredheight = width * cameraview.height / cameraview.width; + + double tx = tempb.x; + double ty = tempb.y; + double tw = tempb.width; + double th = tempb.height; + double px = panelpb.x; + double py = panelpb.y; + double pw = panelpb.width; + double ph = panelpb.height; + if (tx < px) { + tx = px; + } + if (px + pw < tx + tw) { + tx = (px + pw) - tw; + } + double tcy = ty + th / 2; + ty = tcy - preferredheight / 2; + th = preferredheight; + if (ty < py) { + ty = py; + } + if (py + ph < ty + th) { + ty = (py + ph) - th; + } + return new PBounds(tx, ty, tw, th); + } + + /** + * 引数で与えられた同じサイズの箱を,大きな箱の縦横比をみながら + * レイアウトする + */ + public static int fitBoxesToBounds(ArrayList boxes, PBounds parent, double xgap, double ygap){ + int num = boxes.size(); + int sqrtnum = (int) Math.sqrt(num); + double ratediff = Double.MAX_VALUE; + double parentrate = parent.getWidth()/parent.getHeight(); +// System.out.println("Parent "+parentrate); + TreeMap resultRates = new TreeMap(); + + while(true){ + double fitrate = fitrate(boxes, sqrtnum, xgap, ygap); + resultRates.put(Math.abs(parentrate - fitrate), sqrtnum); +// System.out.println(" "+fitrate); + if (ratediff < Math.abs(parentrate - fitrate)) break; + if (boxes.size()<2) break; + ratediff = Math.abs(parentrate - fitrate); + if (fitrate < parentrate){ + sqrtnum++; + } else { + sqrtnum--; + } + } + ArrayList intres = new ArrayList(resultRates.values()); + return intres.get(0); + + } + static double fitrate(ArrayList boxes, int horizontalNum, double xgap, double ygap){ + double x = 0, y = 0, w = 0, h = 0; + int horizonCount = 0; +// System.out.print("Try "+horizontalNum); + for(PNode pn: boxes){ + x += pn.getFullBoundsReference().getWidth() + xgap; + if (y < pn.getFullBoundsReference().getHeight()) y = pn.getFullBoundsReference().getHeight(); + horizonCount++; + if (horizonCount == horizontalNum){ + h += y + ygap; + if (w < x) w = x; + horizonCount = 0; + y = 0; + x = 0; + } + } + h += y + ygap; + if (w < x) w = x; + return w/h; + } + public static ArrayList layout(ArrayList boxes, int horizontalNum, double xgap, double ygap, int animsec, PBounds returnPB){ + ArrayList palist = new ArrayList(); + + double x = 0, y = 0, ymax = 0, h = 0; + int horizonCount = 0; + for(PNode pn: boxes){ + PActivity pa = pn.animateToPositionScaleRotation(x, y, 1, 0, animsec); +// System.out.println("x y "+x+" "+y); + palist.add(pa); + if (returnPB != null) { + PBounds aPB = new PBounds(pn.getFullBoundsReference()); + aPB.setOrigin(x,y); + returnPB.add(aPB); + } + x += pn.getFullBoundsReference().getWidth() + xgap; + if (ymax < pn.getFullBoundsReference().getHeight()) ymax = pn.getFullBoundsReference().getHeight(); + horizonCount++; + if (horizonCount == horizontalNum){ + horizonCount = 0; + h = h + ymax + ygap; + y = h; + x = 0; + ymax = 0; + } + } + return palist; + } + + public static ArrayList layout(ArrayList boxes, int horizontalNum, double xgap, double ygap, int animsec, PBounds returnPB, int xoffset, int yoffset){ + ArrayList palist = new ArrayList(); + + double x = xoffset, y = yoffset, ymax = 0, h = 0; + int horizonCount = 0; + for(PNode pn: boxes){ + PActivity pa = pn.animateToPositionScaleRotation(x, y, 1, 0, animsec); +// System.out.println("x y "+x+" "+y); + palist.add(pa); + if (returnPB != null) { + PBounds aPB = new PBounds(pn.getFullBoundsReference()); + aPB.setOrigin(x,y); + returnPB.add(aPB); + } + x += pn.getFullBoundsReference().getWidth() + xgap; + if (ymax < pn.getFullBoundsReference().getHeight()) ymax = pn.getFullBoundsReference().getHeight(); + horizonCount++; + if (horizonCount == horizontalNum){ + horizonCount = 0; + h = h + ymax + ygap; + y = h + yoffset; + x = xoffset; + ymax = 0; + } + } + return palist; + } + public static Point2D addPoints(Point2D... origins){ + double x = 0, y = 0; + for(Point2D p : origins){ + x += p.getX(); + y += p.getY(); + } + return new Point2D.Double(x,y); + } + + public static Point2D getTopRight(PBounds pb) { + double x = pb.getX(); + double y = pb.getY(); + x += pb.getWidth(); + return new Point2D.Double(x,y); + } + + public static Point2D getBottomLeft(PBounds pb, double xyplus) { + double x = pb.getX(); + double y = pb.getY(); + y += pb.getHeight(); + x -= xyplus; + y += xyplus; + return new Point2D.Double(x,y); + } + + public static Point2D getBottomRight(PBounds pb, double xyplus) { + double x = pb.getX(); + double y = pb.getY(); + x += pb.getWidth(); + y += pb.getHeight(); + x += xyplus; + y += xyplus; + return new Point2D.Double(x,y); + } + public static Point2D getBottomCenter(PBounds pb, double yplus) { + double x = pb.getX(); + double y = pb.getY(); + x += pb.getWidth()/2; + y += pb.getHeight() + yplus; + return new Point2D.Double(x,y); + } + public static Point2D getBottom1_3(PBounds pb, double yplus) { + double x = pb.getX(); + double y = pb.getY(); + x += pb.getWidth()/3; + y += pb.getHeight() + yplus; + return new Point2D.Double(x,y); + } + public static Point2D getBottom2_3(PBounds pb, double yplus) { + double x = pb.getX(); + double y = pb.getY(); + x += pb.getWidth()*2/3; + y += pb.getHeight() + yplus; + return new Point2D.Double(x,y); + } + public static Point2D getLeftPart(PBounds pb, double rate, double xminus) { + double x = pb.getX(); + double y = pb.getY(); + x -= xminus; + y += pb.getHeight()*rate; + return new Point2D.Double(x,y); + } + public static Point2D getRightPart(PBounds pb, double rate, double xplus) { + double x = pb.getX(); + double y = pb.getY(); + x += pb.getWidth() + xplus; + y += pb.getHeight()*rate; + return new Point2D.Double(x,y); + } + + public static ArrayList matrixPointsInDirection(double unitw, double unith, + double topcx, double topcy, + int xcol, int yrow, int direction /*0,1,2,3*/){ + ArrayList ret = new ArrayList(); + + double topw = unitw * xcol; + double toph = unith * yrow; + double topx = topcx - topw/2; + double topy = topcy - toph/2; + + if (direction%2==1){ + int tmp = yrow; + yrow = xcol; + xcol = tmp; +// double tmpd = toph; +// toph = topw; +// topw = tmpd; + topx = topcx - (toph/2); + topy = topcy - (topw/2); +// tmpd = unith; +// unith = unitw; +// unitw = tmpd; + } + + if (direction==0){ + for(int j=0;j-1;j--){ + for(int i=xcol-1;i>-1;i--){ + Point2D p = new Point2D.Double(topx + unitw * i, topy + unith * j); + ret.add(p); + System.out.println(p.toString()); + } + } + } else if (direction==1){ + for(int i=xcol-1;i>-1;i--){ + for(int j=0;j-1;j--){ + Point2D p = new Point2D.Double(topx + unitw * i, topy + unith * j); + ret.add(p); + System.out.println(p.toString()); + } + } + } + return ret; + } + public static ArrayList layoutMatrixPointsInDirection( + ArrayList boxes, int direction, + int xcol, int yrow, double topx, double topy, int animsec, PBounds returnPB){ + ArrayList palist = new ArrayList(); + + PNode pn2 = boxes.get(0); + ArrayList points = matrixPointsInDirection(pn2.getWidth(), pn2.getHeight(), + topx, topy, xcol, yrow, direction); + + int count = 0; + for(PNode pn: boxes){ + Point2D p = points.get(count); + double x = p.getX(); + double y = p.getY(); + pn.setOffset(x,y); // なぜか,アニメーションがうまく動作しないため,直接位置を変更 + + PActivity pa = pn.animateToPositionScaleRotation(x, y, 1, 0, animsec); + palist.add(pa); + if (returnPB != null) { + PBounds aPB = new PBounds(pn.getFullBoundsReference()); + aPB.setOrigin(x,y); + returnPB.add(aPB); + } + count++; + } + return palist; + } +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/CaptureCallback.java b/src/main/java/info/istlab/Zemi01/imgview/CaptureCallback.java new file mode 100644 index 0000000..73e572f --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/CaptureCallback.java @@ -0,0 +1,5 @@ +package info.istlab.Zemi01.imgview; + +public interface CaptureCallback { + public void finished(byte[] bb); +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/EditorPopupMenu.java b/src/main/java/info/istlab/Zemi01/imgview/EditorPopupMenu.java new file mode 100644 index 0000000..7fa8d88 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/EditorPopupMenu.java @@ -0,0 +1,159 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.KeyStroke; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; + + +public class EditorPopupMenu extends JPopupMenu { + private static final long serialVersionUID = 7335274008959965219L; + + ImageEditor editor; + ImageEditor_ZoomRegionHandler zoom; + public EditorPopupMenu(ImageEditor _editor, ImageEditor_ZoomRegionHandler _zoom){ + editor = _editor; zoom = _zoom; + + this.setLightWeightPopupEnabled(false); + JMenuItem menuItem = new JMenuItem("cancel"); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + zoom.selection.removeFromParent(); + } + }); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0)); + this.add(menuItem); + + this.addSeparator(); + + menuItem = new JMenuItem("選択範囲で切り取り"); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, 0)); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println(zoom.layerb.toString()); + int[] rect = new int[4]; + rect[0] = (int) zoom.layerb.getX(); + rect[1] = (int) zoom.layerb.getY(); + rect[2] = (int) zoom.layerb.getWidth(); + rect[3] = (int) zoom.layerb.getHeight(); + + ByteArrayInputStream input = new ByteArrayInputStream(editor.img.sourcebytes); + + ByteArrayOutputStream imgbaos = ScrCapture.crop(input, "PNG", rect); + + editor.replace(new MyPImage(imgbaos.toByteArray(),false) , true); //record history + } + }); + this.add(menuItem); + + this.addSeparator(); + + menuItem = new JMenuItem("選択範囲にモザイク(小)をかける"); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 0)); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println(zoom.layerb.toString()); + int[] rect = new int[4]; + rect[0] = (int) zoom.layerb.getX(); rect[1] = (int) zoom.layerb.getY(); + rect[2] = (int) zoom.layerb.getWidth(); rect[3] = (int) zoom.layerb.getHeight(); + + ByteArrayInputStream input = new ByteArrayInputStream(editor.img.sourcebytes); + ByteArrayOutputStream imgbaos = ScrCapture.pixelize(input, "PNG", rect, 3); //PIXEL_SIZE + editor.replace(new MyPImage(imgbaos.toByteArray(),false) , true); //record history + } + }); + this.add(menuItem); + + menuItem = new JMenuItem("選択範囲にモザイク(大)をかける"); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0)); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println(zoom.layerb.toString()); + int[] rect = new int[4]; + rect[0] = (int) zoom.layerb.getX(); rect[1] = (int) zoom.layerb.getY(); + rect[2] = (int) zoom.layerb.getWidth(); rect[3] = (int) zoom.layerb.getHeight(); + + ByteArrayInputStream input = new ByteArrayInputStream(editor.img.sourcebytes); + ByteArrayOutputStream imgbaos = ScrCapture.pixelize(input, "PNG", rect, 6); //PIXEL_SIZE + editor.replace(new MyPImage(imgbaos.toByteArray(),false) , true); //record history + } + }); + this.add(menuItem); + + this.addSeparator(); + + menuItem = new JMenuItem("選択範囲を枠(赤)で囲む"); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0)); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println(zoom.layerb.toString()); + int[] rect = new int[4]; + rect[0] = (int) zoom.layerb.getX(); rect[1] = (int) zoom.layerb.getY(); + rect[2] = (int) zoom.layerb.getWidth(); rect[3] = (int) zoom.layerb.getHeight(); + + ByteArrayInputStream input = new ByteArrayInputStream(editor.img.sourcebytes); + ByteArrayOutputStream imgbaos = ScrCapture.drawrect(input, "PNG", rect, 3, new double[]{255,0,0}); //LINE_SIZE + editor.replace(new MyPImage(imgbaos.toByteArray(),false) , true); //record history + } + }); + this.add(menuItem); + + menuItem = new JMenuItem("選択範囲を枠(緑)で囲む"); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, 0)); + + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println(zoom.layerb.toString()); + int[] rect = new int[4]; + rect[0] = (int) zoom.layerb.getX(); rect[1] = (int) zoom.layerb.getY(); + rect[2] = (int) zoom.layerb.getWidth(); rect[3] = (int) zoom.layerb.getHeight(); + + ByteArrayInputStream input = new ByteArrayInputStream(editor.img.sourcebytes); + ByteArrayOutputStream imgbaos = ScrCapture.drawrect(input, "PNG", rect, 3, new double[]{0,255,0}); //LINE_SIZE + editor.replace(new MyPImage(imgbaos.toByteArray(),false) , true); //record history + } + }); + this.add(menuItem); + menuItem = new JMenuItem("選択範囲を枠(青)で囲む"); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, 0)); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println(zoom.layerb.toString()); + int[] rect = new int[4]; + rect[0] = (int) zoom.layerb.getX(); rect[1] = (int) zoom.layerb.getY(); + rect[2] = (int) zoom.layerb.getWidth(); rect[3] = (int) zoom.layerb.getHeight(); + + ByteArrayInputStream input = new ByteArrayInputStream(editor.img.sourcebytes); + ByteArrayOutputStream imgbaos = ScrCapture.drawrect(input, "PNG", rect, 3, new double[]{0,0,255}); //LINE_SIZE + editor.replace(new MyPImage(imgbaos.toByteArray(),false) , true); //record history + } + }); + this.add(menuItem); + + this.addPopupMenuListener(new PopupMenuListener() { + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + // zoom.selection.removeFromParent(); + } + @Override + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + zoom.selection.removeFromParent(); + } + @Override + public void popupMenuCanceled(PopupMenuEvent e) { + zoom.selection.removeFromParent(); + } + }); + + } + + + +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/ImageEdit_FinishCallback.java b/src/main/java/info/istlab/Zemi01/imgview/ImageEdit_FinishCallback.java new file mode 100644 index 0000000..e76843c --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/ImageEdit_FinishCallback.java @@ -0,0 +1,5 @@ +package info.istlab.Zemi01.imgview; + +public interface ImageEdit_FinishCallback { + public void edit_finished(byte[] bb); +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/ImageEditor.java b/src/main/java/info/istlab/Zemi01/imgview/ImageEditor.java new file mode 100644 index 0000000..d0ca888 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/ImageEditor.java @@ -0,0 +1,309 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JOptionPane; + +import org.piccolo2d.event.PInputEvent; +import org.piccolo2d.event.PInputEventFilter; +import org.piccolo2d.util.PPaintContext; + +import info.istlab.Zemi01.ClipboardImage; + +/** + * 画像編集パネル + * + * @author miuramo + * + */ + +public class ImageEditor extends MyPCanvas implements KeyListener, WindowListener { + + private static final long serialVersionUID = -3976359681845338950L; + + JFrame parent; + + String path; + MyPImage img; + Dimension displayDimension; + + ImageEditor_ZoomRegionHandler zoomRegionHandler; + + ImageEditor_MenuToolbarAction toolbar; + + ArrayList history = new ArrayList(); + int history_position = -1; + + // カーソルキーを押したときに移動する単位移動量 + private double keyMoveUnit = 10; + + public void fit(int msec) { + if (toolbar.getAction("isToubai").isSelected()) { + getCamera().animateViewToTransform(new AffineTransform(), msec); + } else { + getCamera().animateViewToCenterBounds(img.getBounds(), true, msec); + } + } + + public void fullFit(int msec) { + if (toolbar.getAction("isToubai").isSelected()) { + getCamera().animateViewToTransform(new AffineTransform(), msec); + } else { + getCamera().animateViewToCenterBounds(getLayer().getFullBounds(), true, msec); + } + } + + public Dimension getPreferredSize() { + return displayDimension; + } + + public void replace(MyPImage newimg, boolean record_history) { + img.removeFromParent(); + img = newimg; + if (record_history) { + history.add(img); + history_position = history.size() - 1; + } + getLayer().addChild(img); + if (toolbar.getAction("isToubai").isSelected()) { + getCamera().animateViewToTransform(new AffineTransform(), 1); + } else { + getCamera().animateViewToCenterBounds(img.getBounds(), true, 1); + } + } + + public void switching(int pos) { + MyPImage pimg = null; + try { + pimg = history.get(pos); + } catch (Exception e) { + } + if (pimg != null) { + replace(pimg, false);// do + history_position = pos; + } + } + + public ImageEditor(JFrame _parent, byte[] bb) { + parent = _parent; + img = new MyPImage(bb, false); + history.add(img); + history_position = history.size() - 1; + + setBackground(Color.gray); + + displayDimension = new Dimension((int) (img.getWidth()), (int) (img.getHeight())); + + getLayer().addChild(img); + + addKeyListener(this); + + // zoom + removeInputEventListener(getZoomEventHandler()); + zoomRegionHandler = new ImageEditor_ZoomRegionHandler(this); + zoomRegionHandler.setEventFilter(new PInputEventFilter(InputEvent.BUTTON3_MASK)); + addInputEventListener(zoomRegionHandler); + + zoomRegionHandler.popup = new EditorPopupMenu(this, zoomRegionHandler); + + // pan + // addInputEventListener(getPanEventHandler()); + getPanEventHandler().setAutopan(false); + getPanEventHandler().setMinDragStartDistance(10); + getPanEventHandler().setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); + + // namerakaJCBMI = new JCheckBoxMenuItem("なめらか表示 [CTRL+r]"); + // namerakaJCBMI.setSelected(true); + // デフォルトは,なめらか表示をONにする. + setDefaultRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); + + toolbar = new ImageEditor_MenuToolbarAction(this); + toolbar.foldToolbarText(true); + + // toubaiJCBMI = new JCheckBoxMenuItem(toolbar.getAction("isToubai")); + // toubaiJCBMI.setSelected(false); + + ImageEditor_PopupMenuEventHandler manipuptextEventHandler = new ImageEditor_PopupMenuEventHandler(this); + manipuptextEventHandler.setEventFilter(new PInputEventFilter(InputEvent.BUTTON3_MASK)); + addInputEventListener(manipuptextEventHandler); + + } + + public JFrame getFrame() { + return parent; + } + + public void keyPressed(PInputEvent e) { + switch (e.getKeyCode()) { + case KeyEvent.VK_Q: // exit + if (e.isControlDown()) { + exitprocess(); + } + break; + case KeyEvent.VK_Z: // undo + if (e.isControlDown()) { + switching(history_position - 1); + } + break; + case KeyEvent.VK_Y: // redo + if (e.isControlDown()) { + switching(history_position + 1); + } + break; + case KeyEvent.VK_ENTER: // toggle zoom ratio + toolbar.getAction("isToubai").doClick(); + break; + case KeyEvent.VK_SEMICOLON: // enlarge + if (e.isShiftDown()) { + ByteArrayInputStream input = new ByteArrayInputStream(img.sourcebytes); + ByteArrayOutputStream imgbaos = ScrCapture.scale(input, "PNG", 1.1); + replace(new MyPImage(imgbaos.toByteArray(), false), true); // record history + } + break; + case KeyEvent.VK_MINUS: // shrink + ByteArrayInputStream input2 = new ByteArrayInputStream(img.sourcebytes); + ByteArrayOutputStream imgbaos2 = ScrCapture.scale(input2, "PNG", 0.9); + replace(new MyPImage(imgbaos2.toByteArray(), false), true); // record history + break; + case KeyEvent.VK_S: // sharpness + if (e.isControlDown()) { + ByteArrayInputStream input = new ByteArrayInputStream(img.sourcebytes); + ByteArrayOutputStream imgbaos = ScrCapture.sharpen(input, "PNG"); + replace(new MyPImage(imgbaos.toByteArray(), false), true); // record history + } + break; + case KeyEvent.VK_ESCAPE: // home + fit(1000); + break; + case KeyEvent.VK_UP: + cam.translateView(0, keyMoveUnit); + break; + case KeyEvent.VK_DOWN: + cam.translateView(0, -keyMoveUnit); + break; + case KeyEvent.VK_LEFT: + cam.translateView(keyMoveUnit, 0); + break; + case KeyEvent.VK_RIGHT: + cam.translateView(-keyMoveUnit, 0); + break; + // case KeyEvent.VK_CONTROL: + // isCtrlPressed = true; + // System.out.println("ctrl"); + // break; + } + } + + public void keyTyped(KeyEvent arg0) { + } + + public void keyPressed(KeyEvent arg0) { + keyPressed(new PInputEvent(null, arg0)); + } + + public void keyReleased(KeyEvent arg0) { + } + + ImageEdit_FinishCallback editcallback; + + public void setFinishCallbackObj(ImageEdit_FinishCallback _editcallback) { + editcallback = _editcallback; + } + + public void exitprocess() { + if (editcallback == null) { + System.out.println("editcallbackが設定されていません。"); + parent.dispose(); + System.gc(); + } else { + int res = JOptionPane.showConfirmDialog(parent, "現在の画像で確定して,保存してよろしいですか?\n\n保存しないで終了する場合は「いいえ」を選択してください.", + "画像を保存しますか?", JOptionPane.YES_NO_CANCEL_OPTION); + if (res == JOptionPane.YES_OPTION) { + if (editcallback != null) + editcallback.edit_finished(img.sourcebytes); + + parent.dispose(); + System.gc(); + } else if (res == JOptionPane.NO_OPTION) { + parent.dispose(); + System.gc(); + } + } + } + + @Override + public void windowOpened(WindowEvent e) { + } + + @Override + public void windowClosing(WindowEvent e) { + exitprocess(); + } + + @Override + public void windowClosed(WindowEvent e) { + } + + @Override + public void windowIconified(WindowEvent e) { + } + + @Override + public void windowDeiconified(WindowEvent e) { + } + + @Override + public void windowActivated(WindowEvent e) { + } + + @Override + public void windowDeactivated(WindowEvent e) { + } + + /** + * クリップボードに保存 + */ + public void copyToClipboard() { + System.out.println("Copied to clipboard!"); + ClipboardImage.write(img.getImage()); + } + + /** + * ファイルに保存 + */ + public void save() { + if (fileForSave != null) { + BufferedImage bufimg = img.getBufferedImage(); + try { + ImageIO.write(bufimg, "png", fileForSave); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + System.out.println("Output file is not specified yet."); + + } + } + + File fileForSave; + + public void setFileForSave(File file) { + fileForSave = file; + } + +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/ImageEditorFrame.java b/src/main/java/info/istlab/Zemi01/imgview/ImageEditorFrame.java new file mode 100644 index 0000000..f71f1a5 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/ImageEditorFrame.java @@ -0,0 +1,140 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.Dimension; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.nio.file.Paths; + +import javax.swing.JFrame; + +import info.istlab.Zemi01.Launcher; + +public class ImageEditorFrame extends JFrame implements KeyListener, Runnable { + private static final long serialVersionUID = 5548394183560045355L; + ImageEditor editor; + JFrame parent; + + public static void main(String[] args) { + Path p1 = Paths.get(""); + Path p2 = p1.toAbsolutePath(); + System.out.println(p2.toString()); + + ImageEditorFrame ivf = new ImageEditorFrame(ScrCapture.readBytesFromFile("test.png"), null); + // ivf.setSize(300,200); + Dimension winSize = ivf.getSize(); + ivf.setLocation(Launcher.centerOfScreen(winSize)); + ivf.setVisible(true); + } + + public static byte[] readBytesFromFile(String filepath) { + InputStream fos = null; + DataInputStream dos = null; + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try { + fos = new FileInputStream(filepath); + dos = new DataInputStream(fos); + int len; + byte buf[] = new byte[1024]; + while ((len = dos.read(buf)) != -1) { + output.write(buf, 0, len); + } + dos.close(); + fos.close(); + } catch (IOException iex) { + iex.printStackTrace(System.out); + } + return output.toByteArray(); + } + + public static ImageEditorFrame createFromFile(File file, JFrame _parent) { + byte[] bb = readBytesFromFile(file.getAbsolutePath()); + ImageEditorFrame ief = new ImageEditorFrame(bb, _parent); + ief.setFileForSave(file); + return ief; + } + + /** + * ファイルを開いたとき、上書き保存するファイル情報を ImageEditorに引き渡す + * @param file + */ + private void setFileForSave(File file) { + editor.setFileForSave(file); + } + + public ImageEditorFrame(byte[] bb, JFrame _parent) { + super("マウス右ドラッグで範囲選択&編集 Enter で等倍表示 [CTRL]+[q] で終了(編集確定) "); + parent = _parent; + + editor = new ImageEditor(this, bb); + getContentPane().add(editor); + + pack(); + validate(); + // editor.fit(1000); + + // setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + + addWindowListener(editor); + addKeyListener(editor); + + // Dimension scrsize = Toolkit.getDefaultToolkit().getScreenSize(); + // setLocation(0, scrsize.height - getHeight()); + setVisible(true); + // 1秒まってから、editor.fit(1000); + Thread wait_fit_thread = new Thread(this); + wait_fit_thread.start(); + + } + + public void keyPressed(KeyEvent e) { + // if (e.getKeyCode() == 86 && e.isControlDown()){ // Ctrl-V = 貼り付け + // pasteImage(); + // } + if (e.getKeyCode() == 81 && e.isControlDown()) { // Ctrl-Q = 終了 + // if (modified && editor != null){ + // int res = JOptionPane.showConfirmDialog(ImageIconFrame.this, "Replace + // Image?","Confirm",JOptionPane.YES_NO_OPTION); + // if (res == JOptionPane.YES_OPTION){ + // System.out.println("Update Image!!"); + // editor.callback(img, true); + // } + // } + dispose(); + System.gc(); + } + } + + public void keyReleased(KeyEvent e) { + // TODO 自動生成されたメソッド・スタブ + + } + + public void keyTyped(KeyEvent e) { + // TODO 自動生成されたメソッド・スタブ + + } + + public ImageEditor getImageEditor() { + return editor; + } + + @Override + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + editor.fit(1000); + + } + +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/ImageEditor_MenuToolbarAction.java b/src/main/java/info/istlab/Zemi01/imgview/ImageEditor_MenuToolbarAction.java new file mode 100644 index 0000000..abba81b --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/ImageEditor_MenuToolbarAction.java @@ -0,0 +1,92 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.AffineTransform; + +import javax.swing.JFrame; +import javax.swing.JToolBar; + +/** + * メニューとツールバーを構成するための便利クラス + * @author miuramo + * + */ +public class ImageEditor_MenuToolbarAction extends QuickMenuActionManager { + // スーパークラスでの定義 + // protected KeepOrderHash> menurepos; // "File"=> ArrayList + // protected Hashtable name2act; + // protected Hashtable name2tbutton; + + ImageEditor editor; + JFrame jf; + public ImageEditor_MenuToolbarAction(ImageEditor _satn){ + editor = _satn; + jf = _satn.getFrame(); //attach target + + addAction("View",new MyAction("isToubai","general/Zoom","全体表示/等倍表示 [Enter]",true)); + //直前に追加したMyActionについて,処理を追加する + addHandler_Action(new ActionListener() { + public void actionPerformed(ActionEvent e) { + MyAction mya = (MyAction) e.getSource();//トグル状態を教えてくれるMyAction + if (!mya.isSelected()){ + editor.getCamera().animateViewToTransform(new AffineTransform(), 1); + } else { + editor.getCamera().animateViewToCenterBounds(editor.img.getBounds(), true, 1); + } + } + }); + getAction("isToubai").setSelected(false); + + addAction("View",new MyAction("InitView","navigation/Home","表示状態の初期化 [Esc]")); + addHandler_Action(new ActionListener() { + public void actionPerformed(ActionEvent e) { + editor.fit(1); + } + }); + + addAction("Edit",new MyAction("Undo","general/Undo","元に戻す [CTRL+Z]")); + //直前に追加したMyActionについて,処理を追加する + addHandler_Action(new ActionListener() { + public void actionPerformed(ActionEvent e) { + editor.switching(editor.history_position-1); + } + }); + addAction("Edit",new MyAction("Redo","general/Redo","やり直し [CTRL+Y]")); + //直前に追加したMyActionについて,処理を追加する + addHandler_Action(new ActionListener() { + public void actionPerformed(ActionEvent e) { + editor.switching(editor.history_position+1); + } + }); + + addAction("Export",new MyAction("Copy","general/Copy","コピー [CTRL+C]")); + //直前に追加したMyActionについて,処理を追加する + addHandler_Action(new ActionListener() { + public void actionPerformed(ActionEvent e) { + editor.copyToClipboard(); + } + }); + addAction("Export",new MyAction("Save","general/Save","保存 [CTRL+S]")); + //直前に追加したMyActionについて,処理を追加する + addHandler_Action(new ActionListener() { + public void actionPerformed(ActionEvent e) { + editor.save(); + } + }); + //初期状態は選択不可に(どちらの書き方でも可) + // lastOne.setEnabled(false); +// name2act.get("Reload").setEnabled(false); + +// jf.setJMenuBar(getMenuBar()); + JToolBar tb = getToolBar(editor); + tb.addKeyListener(editor); + jf.getContentPane().add(tb, BorderLayout.NORTH); + +// getAction("NotifyOnNew").setSelected(true); +// getAction("ReLayoutOnNew").setSelected(false); + + + } +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/ImageEditor_PopupMenuEventHandler.java b/src/main/java/info/istlab/Zemi01/imgview/ImageEditor_PopupMenuEventHandler.java new file mode 100644 index 0000000..abf6731 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/ImageEditor_PopupMenuEventHandler.java @@ -0,0 +1,217 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.Point2D; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +import org.piccolo2d.PNode; +import org.piccolo2d.event.PDragSequenceEventHandler; +import org.piccolo2d.event.PInputEvent; +import org.piccolo2d.nodes.PPath; + + +/** + * PageBrowser内から呼ばれる,認識マーク(領域)編集用イベントハンドラ + * + * @author miuramo + * + */ +public class ImageEditor_PopupMenuEventHandler extends PDragSequenceEventHandler { + ImageEditor editor; + + Point2D pressp, campressp; + + Point2D dragp, camdragp; + + Point2D releap, camreleap; + + PPath region; + + int dragcount = 0; + + boolean wasShown = false; + + PNode presstarget, releatarget; + + JPopupMenu popup; + + public static Font defaultFont = new Font("sansserif", Font.PLAIN, 30); + + public ImageEditor_PopupMenuEventHandler(ImageEditor pe) { + editor = pe; + popup = new JPopupMenu(); + popup.setLightWeightPopupEnabled(false); + JMenuItem menuItem = new JMenuItem("cancel"); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + wasShown = false; + } + }); + popup.add(menuItem); + + popup.addSeparator(); + + //等倍 + JCheckBoxMenuItem menuItem3 = new JCheckBoxMenuItem(editor.toolbar.getAction("isToubai")); +// menuItem3.addActionListener(new ActionListener() { +// public void actionPerformed(ActionEvent e) { +// JCheckBoxMenuItem jcbmi = (JCheckBoxMenuItem)e.getSource(); +// if (jcbmi.isSelected()){ +// editor.getCamera().animateViewToTransform(new AffineTransform(), 1); +// } else { +// editor.getCamera().animateViewToCenterBounds(editor.img.getBounds(), true, 1); +// } +// wasShown = false; +// } +// }); + popup.add(menuItem3); + + menuItem = new JMenuItem(editor.toolbar.getAction("InitView")); + popup.add(menuItem); + + popup.addSeparator(); + +// //なめらか +// JCheckBoxMenuItem menuItem2 = editor.namerakaJCBMI; +// menuItem2.addActionListener(new ActionListener() { +// public void actionPerformed(ActionEvent e) { +// JCheckBoxMenuItem jcbmi = (JCheckBoxMenuItem)e.getSource(); +// if (jcbmi.isSelected()){ +// editor.setDefaultRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); +// } else { +// editor.setDefaultRenderQuality(PPaintContext.LOW_QUALITY_RENDERING); +// } +// wasShown = false; +// } +// }); + // popup.add(menuItem2); + + menuItem = new JMenuItem("画像全体の縮小 [-]"); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ByteArrayInputStream input = new ByteArrayInputStream(editor.img.sourcebytes); + ByteArrayOutputStream imgbaos = ScrCapture.scale(input, "PNG", 0.9); + editor.replace(new MyPImage(imgbaos.toByteArray(),false) , true); //record history + } + }); + popup.add(menuItem); + + menuItem = new JMenuItem("画像全体の拡大 [+]"); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ByteArrayInputStream input = new ByteArrayInputStream(editor.img.sourcebytes); + ByteArrayOutputStream imgbaos = ScrCapture.scale(input, "PNG", 1.1); + editor.replace(new MyPImage(imgbaos.toByteArray(),false) , true); //record history + } + }); + popup.add(menuItem); + + menuItem = new JMenuItem("シャープネス [CTRL+S]"); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ByteArrayInputStream input = new ByteArrayInputStream(editor.img.sourcebytes); + ByteArrayOutputStream imgbaos = ScrCapture.sharpen(input, "PNG"); + editor.replace(new MyPImage(imgbaos.toByteArray(),false) , true); //record history + } + }); + popup.add(menuItem); + + + popup.addSeparator(); + +// menuItem = new JMenuItem("元に戻す(undo) [CTRL+z]"); + menuItem = new JMenuItem(editor.toolbar.getAction("Undo")); + popup.add(menuItem); + +// menuItem = new JMenuItem("やり直し(redo) [CTRL+y]"); + menuItem = new JMenuItem(editor.toolbar.getAction("Redo")); + popup.add(menuItem); + + popup.addSeparator(); + + + menuItem = new JMenuItem("編集操作を完了して閉じる [CTRL+q]"); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + editor.exitprocess(); + } + }); + popup.add(menuItem); + } + + public void startDrag(PInputEvent e) { + // wasShown = popup.isShowing(); + System.out.println(wasShown); + super.startDrag(e); + // pressp = e.getPosition(); + //// System.out.println("startDrag"); + campressp = e.getPositionRelativeTo(editor.cam); + // presstarget = e.getPickedNode(); + //// System.out.println(presstarget.toString()); + // + // region = new PPath(new PBounds(pressp, 0, 0)); + // // region.transformBy(at); + // // pagebrowser.studentpanel.addChild(region); + dragcount = 0; + } + + public void drag(PInputEvent e) { + super.drag(e); + // dragp = e.getPosition(); + // // dragp = e.getPositionRelativeTo(pagebrowser.layer); + // camdragp = e.getPositionRelativeTo(pagebrowser.cam); + // + // // if (region != null) + // // region.setPathToRectangle((int) pressp.getX(), (int) pressp.getY(), + // // (int) (dragp.getX() - pressp.getX()), + // // (int) (dragp.getY() - pressp.getY())); + dragcount++; + } + + public void endDrag(PInputEvent e) { + super.endDrag(e); + // releatarget = e.getPickedNode(); + // System.out.println("endDrag"); + // releap = e.getPosition(); + // releap = e.getPositionRelativeTo(pagebrowser.layer); + // camreleap = e.getPositionRelativeTo(pagebrowser.cam); + // System.out.println("dragcount "+dragcount); + if (wasShown) { + popup.setVisible(false); + wasShown = false; + } else if (dragcount< 2){ + wasShown = true; + popup.show(editor, (int) campressp.getX(), (int) campressp.getY()); + } + // if (region != null) { + // double w = region.getWidth(); + // double h = region.getHeight(); + // if (w < 5.0 || h < 5.0) { + // popup.show(pagebrowser, (int) campressp.getX(), (int) campressp.getY()); + // } else { + // // // 表示する文字を入力してもらう + // // String txt = MultiLinerTextInputDialog.showDialog(pagebrowser.getFrame(), "", pagebrowser); + // // if (txt != null){ + // // PText pt = new PText(txt); + // // pt.setFont(defaultFont);//ここで,デフォルトサイズ30に + // // pt.setGreekThreshold(1.0f); + // //// pt.setBounds(region.getBounds()); + // // pt.setScale(region.getWidth()/pt.getWidth()); + // // pt.setOffset(region.getBounds().getOrigin()); + // // pagebrowser.studentpanel.addChild(pt); + // // } + // } + // // pagebrowser.studentpanel.removeChild(region); + // region = null; + // } + + // pagebrowser.undoManager.record(); + } +} \ No newline at end of file diff --git a/src/main/java/info/istlab/Zemi01/imgview/ImageEditor_ZoomRegionHandler.java b/src/main/java/info/istlab/Zemi01/imgview/ImageEditor_ZoomRegionHandler.java new file mode 100644 index 0000000..de99f08 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/ImageEditor_ZoomRegionHandler.java @@ -0,0 +1,135 @@ +package info.istlab.Zemi01.imgview; + + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Stroke; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import javax.swing.JPopupMenu; + +import org.piccolo2d.PCanvas; +import org.piccolo2d.event.PDragSequenceEventHandler; +import org.piccolo2d.event.PInputEvent; +import org.piccolo2d.util.PAffineTransform; +import org.piccolo2d.util.PBounds; + +/** + * ATNWindowで右ドラッグしながら青色のズーム範囲矩形を表示し,ズームする機能を実現するクラス + * @author miuramo + * + */ +public class ImageEditor_ZoomRegionHandler extends PDragSequenceEventHandler { + PCanvas viewer; + + PPPath selection; + + private Stroke[] strokes = null; + + private float strokeNum = 0; + + final static int NUM_STROKES = 20; + + final static int DASH_WIDTH = 5; + + Point2D cmp; // ドラッグ開始座標 + + Point2D cp; //ドラッグ中の座標 + + Point2D max_ext_cp; // 左上方向(通常とは逆方向)一番遠くにドラッグしたときの座標 +// double dist_max_ext_cp; //そのときの距離 + PBounds initialBounds; //ドラッグ開始時の視野 + + JPopupMenu popup = null; + + public ImageEditor_ZoomRegionHandler(PCanvas _viewer) { + this.viewer = _viewer; + + float[] dash = { DASH_WIDTH, DASH_WIDTH }; + strokes = new Stroke[NUM_STROKES]; + for (int i = 0; i < NUM_STROKES; i++) { + strokes[i] = new BasicStroke(2, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, 1, dash, i); + } + } + + public void startDrag(PInputEvent e) { + super.startDrag(e); + cmp = e.getPositionRelativeTo(viewer.getCamera()); + max_ext_cp = cmp; // 初期化 + selection = new PPPath(); + selection.setPathToRectangle((float) cmp.getX(), (float) cmp.getY(), 0, + 0); + selection.setStrokePaint(Color.red);//青色 + selection.setPaint(null); + selection.setStroke(strokes[0]); + viewer.getCamera().addChild(selection); + initialBounds = viewer.getCamera().getViewBounds(); + } + + public void drag(PInputEvent e) { + super.drag(e); + cp = e.getPositionRelativeTo(viewer.getCamera()); + + + + PAffineTransform at = viewer.getCamera().getViewTransform(); + globalb = viewer.getLayer().getFullBounds(); + Rectangle2D viewrect = new Rectangle2D.Double(); + at.transform(globalb, viewrect); + +// System.out.println("viewrect : "+viewrect.toString()); +// System.out.println("selectio : "+selection.getBounds().toString()); + double cp_cmp_x = (cp.getX() - cmp.getX()); + double cp_cmp_y = (cp.getY() - cmp.getY()); + //check bounds limit + if (cp.getX() > viewrect.getX()+viewrect.getWidth()) { + cp_cmp_x = viewrect.getX()+viewrect.getWidth() - cmp.getX(); + } + if (cp.getY() > viewrect.getY()+viewrect.getHeight()) { + cp_cmp_y = viewrect.getY()+viewrect.getHeight() - cmp.getY(); + } + selection.setPathToRectangle((float) cmp.getX(), (float) cmp.getY(), + (float)cp_cmp_x-1, (float)cp_cmp_y-1); //-1しないと,画像の範囲外になって,cropできない場合がある + + // 右下にドラッグしているときの,青い点線矩形の点線パターンを変化させる + float origStrokeNum = strokeNum; + strokeNum = (strokeNum + 0.3f) % NUM_STROKES; + if ((int) strokeNum != (int) origStrokeNum) { + selection.setStroke(strokes[(int) strokeNum]); + } + +// 左上方向(通常とは逆方向)一番遠くにドラッグしたときの処理 + if (cp_cmp_x < 0 || cp_cmp_y < 0){ +// PCamera pc = viewer.getCamera(); +// float f; +// if (cp_cmp_x < 0) f = Math.abs((float)(viewer.getWidth()/(viewer.getWidth() - cp.distance(cmp)))); +// else f = Math.abs((float)((viewer.getWidth() - cp.distance(cmp))/viewer.getWidth())); +//// System.out.println("f "+f); +// PBounds pb = BUtil.zoomBounds(initialBounds, f); +// pc.animateViewToCenterBounds(pb, true, 0); + } + } + + Rectangle2D globalb; + Rectangle2D layerb; + public void endDrag(PInputEvent e) { + super.endDrag(e); + cp = e.getPositionRelativeTo(viewer.getCamera()); + if (cmp.getX() < cp.getX() && cmp.getY() < cp.getY()) { + // カメラ座標から,グローバル(パネル)座標への変換 + PAffineTransform at = viewer.getCamera().getViewTransform(); + globalb = selection.getGlobalBounds(); + layerb = new Rectangle2D.Double(); + at.inverseTransform(globalb, layerb); +// viewer.getCamera().animateViewToCenterBounds(layerb, true, 1000); + + if (popup != null){ + popup.show(viewer, (int)(cp.getX()), (int)(cp.getY())); + } else { + selection.removeFromParent(); + } + } + } +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/ImageViewer.java b/src/main/java/info/istlab/Zemi01/imgview/ImageViewer.java new file mode 100644 index 0000000..cdd3d2e --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/ImageViewer.java @@ -0,0 +1,139 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; + +import org.piccolo2d.event.PInputEvent; +import org.piccolo2d.event.PInputEventFilter; +import org.piccolo2d.util.PPaintContext; + + +/** + * Microsoft Windowsのシェルで,ファイルをドラッグしてJavaのパネルにドロップしたときに, + * ドロップされたファイルのパスを引き渡すためのインタフェース + * + * @author miuramo + * + */ + + +public class ImageViewer extends MyPCanvas implements KeyListener { + + private static final long serialVersionUID = -3976359681845338950L; + + JFrame parent; + + String path; + MyPImage img; + Dimension displayDimension; + + ImageViewer_ZoomRegionHandler zoomRegionHandler; + + JCheckBoxMenuItem namerakaJCBMI; + + // カーソルキーを押したときに移動する単位移動量 + private double keyMoveUnit = 10; + + public void fit() { + getCamera().animateViewToCenterBounds(img.getBounds(), true, 1000); + } + public void fullFit() { + getCamera().animateViewToCenterBounds(getLayer().getFullBounds(), true, 1000); + } + public Dimension getPreferredSize(){ + return displayDimension; + } + + public ImageViewer(JFrame _parent, String _path){ + path = _path; + parent = _parent; + img = new MyPImage(path); + + setBackground(Color.gray); + + displayDimension = new Dimension((int)(img.getWidth()/2),(int)(img.getHeight()/2)); + + getLayer().addChild(img); + + addKeyListener(this); + + //zoom + removeInputEventListener(getZoomEventHandler()); + zoomRegionHandler = new ImageViewer_ZoomRegionHandler(this); + zoomRegionHandler.setEventFilter(new PInputEventFilter(InputEvent.BUTTON3_MASK)); + addInputEventListener(zoomRegionHandler); + + //pan +// addInputEventListener(getPanEventHandler()); + getPanEventHandler().setAutopan(false); + getPanEventHandler().setMinDragStartDistance(10); + getPanEventHandler().setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); + + // popupmenu + namerakaJCBMI = new JCheckBoxMenuItem("なめらか表示 [CTRL+r]"); + namerakaJCBMI.setSelected(true); + ImageViewer_PopupMenuEventHandler manipuptextEventHandler = new ImageViewer_PopupMenuEventHandler(this); + manipuptextEventHandler.setEventFilter(new PInputEventFilter(InputEvent.BUTTON3_MASK)); + addInputEventListener(manipuptextEventHandler); + + //デフォルトは,なめらか表示をOFFにする.(みにくいので) + setDefaultRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); + } + + public JFrame getFrame() { + return parent; + } + + public void keyPressed(PInputEvent e) { + switch (e.getKeyCode()) { + case KeyEvent.VK_Q: // exit + if (e.isControlDown()) { + parent.dispose(); + System.gc(); + } + break; + case KeyEvent.VK_R: // exit + if (e.isControlDown()) { + namerakaJCBMI.doClick(); + } + break; + case KeyEvent.VK_ESCAPE: //home + fit(); + break; + case KeyEvent.VK_UP: + cam.translateView(0, -keyMoveUnit); + break; + case KeyEvent.VK_DOWN: + cam.translateView(0, keyMoveUnit); + break; + case KeyEvent.VK_LEFT: + cam.translateView( -keyMoveUnit, 0); + break; + case KeyEvent.VK_RIGHT: + cam.translateView(keyMoveUnit, 0); + break; + // case KeyEvent.VK_CONTROL: + // isCtrlPressed = true; + // System.out.println("ctrl"); + // break; + } + } + + public void keyTyped(KeyEvent arg0) { + } + + public void keyPressed(KeyEvent arg0) { + keyPressed(new PInputEvent(null, arg0)); + } + + public void keyReleased(KeyEvent arg0) { + } + +} + diff --git a/src/main/java/info/istlab/Zemi01/imgview/ImageViewerFrame.java b/src/main/java/info/istlab/Zemi01/imgview/ImageViewerFrame.java new file mode 100644 index 0000000..a3582e0 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/ImageViewerFrame.java @@ -0,0 +1,60 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +import javax.swing.JFrame; + +public class ImageViewerFrame extends JFrame implements KeyListener { + private static final long serialVersionUID = 5548394183560045355L; + ImageViewer canvas; + JFrame parent; + + public ImageViewerFrame(String path, JFrame _parent){ + super("[CTRL]+[q] で終了 Esc で全表示 マウス右選択 で範囲ズーム"); + parent = _parent; + + canvas = new ImageViewer(this, path); + getContentPane().add(canvas); + + + pack(); + validate(); +// setVisible(true); +// setState(JFrame.ICONIFIED); + +// setSize(592,876); +// setSize(592,880); + canvas.fit(); + + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + addKeyListener(canvas); + } + + + public void keyPressed(KeyEvent e) { +// if (e.getKeyCode() == 86 && e.isControlDown()){ // Ctrl-V = 貼り付け +// pasteImage(); +// } + if (e.getKeyCode() == 81 && e.isControlDown()){ // Ctrl-Q = 終了 +// if (modified && editor != null){ +// int res = JOptionPane.showConfirmDialog(ImageIconFrame.this, "Replace Image?","Confirm",JOptionPane.YES_NO_OPTION); +// if (res == JOptionPane.YES_OPTION){ +// System.out.println("Update Image!!"); +// editor.callback(img, true); +// } +// } + dispose(); + System.gc(); + } + } + public void keyReleased(KeyEvent e) { + // TODO 自動生成されたメソッド・スタブ + + } + public void keyTyped(KeyEvent e) { + // TODO 自動生成されたメソッド・スタブ + + } +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/ImageViewer_PopupMenuEventHandler.java b/src/main/java/info/istlab/Zemi01/imgview/ImageViewer_PopupMenuEventHandler.java new file mode 100644 index 0000000..3a0b62c --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/ImageViewer_PopupMenuEventHandler.java @@ -0,0 +1,161 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.Point2D; + +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +import org.piccolo2d.PNode; +import org.piccolo2d.event.PDragSequenceEventHandler; +import org.piccolo2d.event.PInputEvent; +import org.piccolo2d.nodes.PPath; +import org.piccolo2d.util.PPaintContext; + +/** + * PageBrowser内から呼ばれる,認識マーク(領域)編集用イベントハンドラ + * + * @author miuramo + * + */ +public class ImageViewer_PopupMenuEventHandler extends PDragSequenceEventHandler { + ImageViewer pagebrowser; + + Point2D pressp, campressp; + + Point2D dragp, camdragp; + + Point2D releap, camreleap; + + PPath region; + + int dragcount = 0; + + boolean wasShown = false; + + PNode presstarget, releatarget; + + JPopupMenu popup; + + public static Font defaultFont = new Font("sansserif", Font.PLAIN, 30); + + public ImageViewer_PopupMenuEventHandler(ImageViewer pe) { + pagebrowser = pe; + popup = new JPopupMenu(); + popup.setLightWeightPopupEnabled(false); + JMenuItem menuItem = new JMenuItem("cancel"); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + wasShown = false; + } + }); + popup.add(menuItem); + + menuItem = new JMenuItem("全画面 [Esc]"); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + pagebrowser.fit(); + wasShown = false; + } + }); + popup.add(menuItem); + + //なめらか + JCheckBoxMenuItem menuItem2 = pagebrowser.namerakaJCBMI; +// menuItem2.setSelected(true); + menuItem2.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JCheckBoxMenuItem jcbmi = (JCheckBoxMenuItem)e.getSource(); + if (jcbmi.isSelected()){ + pagebrowser.setDefaultRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); + } else { + pagebrowser.setDefaultRenderQuality(PPaintContext.LOW_QUALITY_RENDERING); + } + wasShown = false; + } + }); + popup.add(menuItem2); + + + menuItem = new JMenuItem("閉じる [CTRL+q]"); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + pagebrowser.parent.dispose(); + System.gc(); + } + }); + popup.add(menuItem); + } + + public void startDrag(PInputEvent e) { +// wasShown = popup.isShowing(); + System.out.println(wasShown); + super.startDrag(e); + // pressp = e.getPosition(); + //// System.out.println("startDrag"); + campressp = e.getPositionRelativeTo(pagebrowser.cam); + // presstarget = e.getPickedNode(); + //// System.out.println(presstarget.toString()); + // + // region = new PPath(new PBounds(pressp, 0, 0)); + // // region.transformBy(at); + // // pagebrowser.studentpanel.addChild(region); + dragcount = 0; + } + + public void drag(PInputEvent e) { + super.drag(e); + // dragp = e.getPosition(); + // // dragp = e.getPositionRelativeTo(pagebrowser.layer); + // camdragp = e.getPositionRelativeTo(pagebrowser.cam); + // + // // if (region != null) + // // region.setPathToRectangle((int) pressp.getX(), (int) pressp.getY(), + // // (int) (dragp.getX() - pressp.getX()), + // // (int) (dragp.getY() - pressp.getY())); + dragcount++; + } + + public void endDrag(PInputEvent e) { + super.endDrag(e); + // releatarget = e.getPickedNode(); + // System.out.println("endDrag"); + // releap = e.getPosition(); + // releap = e.getPositionRelativeTo(pagebrowser.layer); + // camreleap = e.getPositionRelativeTo(pagebrowser.cam); + // System.out.println("dragcount "+dragcount); + if (wasShown) { + popup.setVisible(false); + wasShown = false; + } else if (dragcount< 2){ + wasShown = true; + popup.show(pagebrowser, (int) campressp.getX(), (int) campressp.getY()); + } + // if (region != null) { + // double w = region.getWidth(); + // double h = region.getHeight(); + // if (w < 5.0 || h < 5.0) { + // popup.show(pagebrowser, (int) campressp.getX(), (int) campressp.getY()); + // } else { + // // // 表示する文字を入力してもらう + // // String txt = MultiLinerTextInputDialog.showDialog(pagebrowser.getFrame(), "", pagebrowser); + // // if (txt != null){ + // // PText pt = new PText(txt); + // // pt.setFont(defaultFont);//ここで,デフォルトサイズ30に + // // pt.setGreekThreshold(1.0f); + // //// pt.setBounds(region.getBounds()); + // // pt.setScale(region.getWidth()/pt.getWidth()); + // // pt.setOffset(region.getBounds().getOrigin()); + // // pagebrowser.studentpanel.addChild(pt); + // // } + // } + // // pagebrowser.studentpanel.removeChild(region); + // region = null; + // } + + // pagebrowser.undoManager.record(); + } +} \ No newline at end of file diff --git a/src/main/java/info/istlab/Zemi01/imgview/ImageViewer_ZoomRegionHandler.java b/src/main/java/info/istlab/Zemi01/imgview/ImageViewer_ZoomRegionHandler.java new file mode 100644 index 0000000..f74ef26 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/ImageViewer_ZoomRegionHandler.java @@ -0,0 +1,110 @@ +package info.istlab.Zemi01.imgview; + + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Stroke; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import org.piccolo2d.PCamera; +import org.piccolo2d.PCanvas; +import org.piccolo2d.event.PDragSequenceEventHandler; +import org.piccolo2d.event.PInputEvent; +import org.piccolo2d.util.PAffineTransform; +import org.piccolo2d.util.PBounds; + + +/** + * ATNWindowで右ドラッグしながら青色のズーム範囲矩形を表示し,ズームする機能を実現するクラス + * @author miuramo + * + */ +public class ImageViewer_ZoomRegionHandler extends PDragSequenceEventHandler { + PCanvas viewer; + + PPPath selection; + + private Stroke[] strokes = null; + + private float strokeNum = 0; + + final static int NUM_STROKES = 10; + + final static int DASH_WIDTH = 15; + + Point2D cmp; // ドラッグ開始座標 + + Point2D cp; //ドラッグ中の座標 + + Point2D max_ext_cp; // 左上方向(通常とは逆方向)一番遠くにドラッグしたときの座標 +// double dist_max_ext_cp; //そのときの距離 + PBounds initialBounds; //ドラッグ開始時の視野 + + public ImageViewer_ZoomRegionHandler(PCanvas _viewer) { + this.viewer = _viewer; + + float[] dash = { DASH_WIDTH, DASH_WIDTH }; + strokes = new Stroke[NUM_STROKES]; + for (int i = 0; i < NUM_STROKES; i++) { + strokes[i] = new BasicStroke(2, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, 1, dash, i); + } + } + + public void startDrag(PInputEvent e) { + super.startDrag(e); + cmp = e.getPositionRelativeTo(viewer.getCamera()); + max_ext_cp = cmp; // 初期化 + selection = new PPPath(); + selection.setPathToRectangle((float) cmp.getX(), (float) cmp.getY(), 0, + 0); + selection.setStrokePaint(Color.blue);//青色 + selection.setPaint(null); + selection.setStroke(strokes[0]); + viewer.getCamera().addChild(selection); + initialBounds = viewer.getCamera().getViewBounds(); + } + + public void drag(PInputEvent e) { + super.drag(e); + cp = e.getPositionRelativeTo(viewer.getCamera()); + float cp_cmp_x = (float)(cp.getX() - cmp.getX()); + float cp_cmp_y = (float)(cp.getY() - cmp.getY()); + + selection.setPathToRectangle((float) cmp.getX(), (float) cmp.getY(), + cp_cmp_x, cp_cmp_y); + + // 右下にドラッグしているときの,青い点線矩形の点線パターンを変化させる + float origStrokeNum = strokeNum; + strokeNum = (strokeNum + 0.3f) % NUM_STROKES; + if ((int) strokeNum != (int) origStrokeNum) { + selection.setStroke(strokes[(int) strokeNum]); + } + +// 左上方向(通常とは逆方向)一番遠くにドラッグしたときの処理 + if (cp_cmp_x < 0 || cp_cmp_y < 0){ + PCamera pc = viewer.getCamera(); + float f; + if (cp_cmp_x < 0) f = Math.abs((float)(viewer.getWidth()/(viewer.getWidth() - cp.distance(cmp)))); + else f = Math.abs((float)((viewer.getWidth() - cp.distance(cmp))/viewer.getWidth())); +// System.out.println("f "+f); + PBounds pb = BUtil.zoomBounds(initialBounds, f); + pc.animateViewToCenterBounds(pb, true, 0); + } + } + + public void endDrag(PInputEvent e) { + super.endDrag(e); + cp = e.getPositionRelativeTo(viewer.getCamera()); + selection.removeFromParent(); + if (cmp.getX() < cp.getX() && cmp.getY() < cp.getY()) { + // カメラ座標から,グローバル(パネル)座標への変換 + PAffineTransform at = viewer.getCamera().getViewTransform(); + Rectangle2D globalb = selection.getGlobalBounds(); + Rectangle2D layerb = new Rectangle2D.Double(); + at.inverseTransform(globalb, layerb); + viewer.getCamera().animateViewToCenterBounds(layerb, true, 1000); + } + } +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/InfoGetter.java b/src/main/java/info/istlab/Zemi01/imgview/InfoGetter.java new file mode 100644 index 0000000..603a3c8 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/InfoGetter.java @@ -0,0 +1,570 @@ +package info.istlab.Zemi01.imgview; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; + +import org.apache.commons.lang3.SystemUtils; + +// import org.apache.commons.lang.SystemUtils; +// import org.apache.http.HttpEntity; +// import org.apache.http.entity.ContentType; +// import org.apache.http.entity.mime.MultipartEntityBuilder; +// import org.apache.http.entity.mime.content.StringBody; + +// import jp.ac.jaist.css.common.io.FileReadWriter; +// import mbs.security.Encrypter; + +public class InfoGetter { + // public String uid; + // public OSName os; + // public String name; + public String hostip; + + // public int id; + // public int lecture_id; + // public Lecture lecture; + // public String last; + // public String first; + + public int seatnum; + + // public boolean startNetService = true; + // public String passHash=null; + // Poster poster = new Poster(); + + // String last_inputted_report_src_id = null; + + // public ArrayList activeLectures; + // public ArrayList activeAssigns;//画面レポートのみ + + // public InfoGetter(){ + // getUid(); + // getHostIp(); + // getOs(); + // System.out.println(getOsNameString()); + // activeLectures = new ArrayList(); + // activeAssigns = new ArrayList(); + + // if (os == OSName.LINUX){ + // getName(); + // } else { + // Shusseki.TEACHERIMAGE = "img.png"; + // // startNetService = false; + // } + // if (hostip.startsWith("150.69.14")){ + // if (os == OSName.WINDOWS){ + // System.out.println("Do not open port: "+hostip); + + // startNetService = false; + // } + // if (os == OSName.LINUX){ + // Shusseki.PROTOCOL = "https://"; + // startNetService = false; + // } + // } + // } + + // public void logintolec(Shusseki shusseki){ + // if (startNetService){ + + // String res; + // // ig.uid = "admin"; //TODO:デバッグ用なので,あとで直す + // if (name != null){ + // // + // System.out.println(PROTOCOL+server+Shusseki.miuraattr+"/users/getinfo/"+ig.uid+"/"+ig.hostip+"/"+ig.name.replaceAll("\\ + // ", "/")); + // res = + // Poster.get(Shusseki.PROTOCOL+Shusseki.server+Shusseki.miuraattr+"/users/getinfo/"+uid+"/"+hostip+"/"+name.replaceAll("\\ + // ", "/")); + // } else { + // res = + // Poster.get(Shusseki.PROTOCOL+Shusseki.server+Shusseki.miuraattr+"/users/getinfo/"+uid+"/"+hostip+"/null/null"); + // } + // // System.out.println(res); + // int lecid = 0; + // Lecture lec = null; + // if (res.indexOf("nouser")>-1){ + // //nouser + // int a = JOptionPane.showConfirmDialog(null, "新しいアカウント "+uid+" を作成しますか?\n"+ + // "(「はい」を押すと登録サイトが開きます)", "まだアカウントがありません", JOptionPane.YES_NO_OPTION, + // JOptionPane.WARNING_MESSAGE); + // if (a == JOptionPane.YES_OPTION){ + // shusseki.BrowserUtil_openURL(Shusseki.PROTOCOL+Shusseki.server+Shusseki.miuraattr+"/users/stuadd/0/"+uid+"/"+first+"/"+last+"/"+hostip); + // shusseki.Systemexit(0); + // } else { + + // } + // } else { + // System.out.println(res); + // String[] lines = res.split("\n"); + // //ユーザ情報の追加 + // appendInfo(lines[0]); + // int countlec = Integer.parseInt(lines[1]); + // // System.out.println(ig.toString()); + // if (countlec == 0){ + // //講義がまだ登録されてない + // int a = JOptionPane.showConfirmDialog(null, "こんにちは,"+last+first+"さん!\n\n" + + // "まだ講義が登録されていません.登録しますか?","講義を登録してください",JOptionPane.YES_NO_OPTION, + // JOptionPane.WARNING_MESSAGE); + // if (a == JOptionPane.YES_OPTION){ + // shusseki.autologin(-1,"firefox"); + // // BrowserUtil_openURL(PROTOCOL+server+Shusseki.miuraattr+"/"); + // } + // shusseki.Systemexit(0); + // } else if (countlec == 1){ + // appendLecture(lines[2]); + // lec = new Lecture(lines[2]); + // } else if (countlec >= 2){ + // for(int i=2;i<2+countlec;i++){ + // appendLecture(lines[i]); + // } + // // System.out.println("size "+ig.activeLectures.size()); + // SingleSelector sel = new SingleSelector(activeLectures, + // null, "出席する講義を選択してください"); + // sel.setVisible(true); + // // System.out.println("select"); + // lec = sel.selectedObj; + // } + + // if (lec == null) { + // // System.out.println("not selected"); return; + // JOptionPane.showMessageDialog(null, "講義が選択されませんでした.\n\n" + + // "(終了します)"); + // shusseki.Systemexit(0); + // } + // lecid = lec.id; + // lecture = lec; //ボタンをおしただけ(出席)でも,画像はおくるかもしれないので,登録はする. + + // int a = JOptionPane.showConfirmDialog(null, "こんにちは,"+last+first+"さん!\n\n" + + // "講義:"+lec.toString()+" + // に出席報告しますか?\n\n(注:レポート作成等の授業外活動では「いいえ」を押してください)","出席報告の確認",JOptionPane.YES_NO_OPTION, + // JOptionPane.QUESTION_MESSAGE); + // if (a == JOptionPane.YES_OPTION){ + // MultipartEntityBuilder mpeb = MultipartEntityBuilder.create(); + // StringBody login = new StringBody(uid, ContentType.TEXT_PLAIN); + // StringBody uid = new StringBody(String.valueOf(id), ContentType.TEXT_PLAIN); + // StringBody lecid_b = new StringBody(String.valueOf(lec.id), + // ContentType.TEXT_PLAIN); + // StringBody hostip_b = new StringBody(hostip, ContentType.TEXT_PLAIN); + // HttpEntity en = mpeb.addPart("login",login) + // .addPart("lecid", lecid_b) + // .addPart("uid", uid) + // .addPart("hostip", hostip_b).build(); + // String res2 = Poster.post(en, + // Shusseki.PROTOCOL+Shusseki.server+Shusseki.miuraattr+"/lectures/attenddirect"); + // System.out.println(res2); + // // if (res2.indexOf("duplicate error")>-1){ + // // JOptionPane.showMessageDialog(null, "すでに講義"+lec.toString()+" + // には出席報告済みでした."); + // // } + // } + // if (lecid > 0){ + // a = JOptionPane.showConfirmDialog(null, + // "可能なら自動ログインして,出席状況を確認しますか?","自動ログイン",JOptionPane.YES_NO_OPTION, + // JOptionPane.QUESTION_MESSAGE); + // if (a == JOptionPane.YES_OPTION){ + // shusseki.autologin(lecid,"firefox"); + // } + // } + // //本当はinit(),ackinit()をここに入れる + // } + // } + // } + + // public void getUid(){ + // uid = System.getProperty("user.name"); + // // System.out.println(uid); + // } + // public void getOs(){ + // os = getOsName(); + // } + + // public void getName(){ + // //fingerコマンドは,学生ではアクセス禁止になっているので,かわりにsetuidしたプログラムを用いる + // String command = "/usr/bin/finger -m "+uid; + // // String command = "/home/t/miura/bin/myfinger"; + // // System.out.println("command: "+command); + // Process process = null; + // try { + // process = Runtime.getRuntime().exec(command); + // } catch (IOException e1) { + // e1.printStackTrace(); + // return; + // } + // InputStream is = process.getInputStream(); + // BufferedReader br = new BufferedReader(new InputStreamReader(is)); + // String line; + // try { + // while ((line = br.readLine()) != null) { + // // System.out.println(line); + // if (line.indexOf("no such user")>-1){ + // name = "null null"; + // continue; + // // return; + // } + // if (line.indexOf("Name:")>-1){ + // int pos = line.indexOf("Name:"); + // name = line.substring(pos+6); + // System.out.println("found: "+name); + // String[] a = name.split(" "); + // last = capitalize(a[1]); + // first = capitalize(a[0]); + + // return; + // } + // } + // } catch (IOException e) { + // e.printStackTrace(); + // } + // } + + // //実際にはつかっていない + // public void createAccountIfNotExist() { + // String res; + // // ig.uid = "admin"; //TODO:デバッグ用なので,あとで直す + // if (uid == null){ + // uid = JOptionPane.showInputDialog(null, + // "情報科学センターのアカウント名(例:j111000s)を入力してください","出席システムの認証",JOptionPane.INFORMATION_MESSAGE); + // if (uid == null) { + // JOptionPane.showMessageDialog(null, "終了します."); + // System.exit(0); + // } + // } + // System.out.println("uid="+uid); + // res = + // Poster.get(Shusseki.PROTOCOL+Shusseki.server+Shusseki.miuraattr+"/users/getinfo/"+uid+"/"+hostip); + + // if (res.indexOf("nouser")>-1){ + // //nouser + // // int a = JOptionPane.showConfirmDialog(null, "新しいアカウント "+uid+" を作成しますか?\n"+ + // // "(「はい」を押すと登録画面になります)", "出席システムにまだアカウントがありません", JOptionPane.YES_NO_OPTION, + // JOptionPane.INFORMATION_MESSAGE); + // // if (a == JOptionPane.YES_OPTION){ + // // createAccount(); + // // } else { + // // JOptionPane.showMessageDialog(null, "アカウント作成しないで終了します."); + // // System.exit(0); + // // } + // JOptionPane.showMessageDialog(null, "対応するアカウントがありませんでしたので終了します."); + // System.exit(0); + // } else { + + // if (passHash == null){ + // while(true){ + // String pass=null; + // JPasswordField passwordField = new JPasswordField(); + // passwordField.setEchoChar('●'); + // passwordField.addKeyListener(new java.awt.event.KeyAdapter() { + // @Override + // public void keyPressed(java.awt.event.KeyEvent kEvt) { + // if (kEvt.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) { + // kEvt.consume(); + // // auto generate TAB + Enter keypress events + // try { + // java.awt.Robot robot = new java.awt.Robot(); + // robot.setAutoDelay(30); + // robot.keyPress(java.awt.event.KeyEvent.VK_TAB); + // robot.keyRelease(java.awt.event.KeyEvent.VK_TAB); + // robot.keyPress(java.awt.event.KeyEvent.VK_SPACE); + // robot.keyRelease(java.awt.event.KeyEvent.VK_SPACE); + // } + // catch (java.awt.AWTException awtEx) { + // awtEx.printStackTrace(); + // } + // } + // } + // }); + + // Object[] obj = {"出席システムに登録したパスワードを入力してください.\n\n", passwordField}; + // Object stringArray[] = {"OK","Cancel"}; + // if (JOptionPane.showOptionDialog(null, obj, "出席システムの認証", + // JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, stringArray, + // obj) == JOptionPane.YES_OPTION) + // pass = new String(passwordField.getPassword()); + + // // String pass = JOptionPane.showInputDialog(null, + // "出席システムに登録したパスワードを入力してください."); + // if (pass == null){ + // JOptionPane.showMessageDialog(null, "終了します."); + // System.exit(0); + // } else { + // passHash = Encrypter.getHash(pass, Encrypter.ALG_SHA1); + // } + + // //check account + // res = + // Poster.get(Shusseki.PROTOCOL+Shusseki.server+Shusseki.miuraattr+"/users/checklogininfo/"+uid+"/"+passHash); + // System.out.println(res); + // if (res.indexOf("accept")>-1){ + // String[] ress = res.split(" "); + // id = Integer.valueOf(ress[1]); + // break; + // } else { + // passHash = null; + // } + // } + // } + // JOptionPane.showMessageDialog(null,uid+"さんのアカウント確認しました","本人確認完了",JOptionPane.INFORMATION_MESSAGE); + // System.out.println("id="+id); + // } + // } + + // public void checkHomeDirState(){ + // //statコマンドで,ホームディレクトリのモードを得る + // String command = "/usr/bin/stat /home/t/"+uid+" -c %a "; + // // String command = "/home/t/miura/bin/myfinger"; + // // System.out.println("command: "+command); + // Process process = null; + // try { + // process = Runtime.getRuntime().exec(command); + // } catch (IOException e1) { + // e1.printStackTrace(); + // return; + // } + // InputStream is = process.getInputStream(); + // BufferedReader br = new BufferedReader(new InputStreamReader(is)); + // String line; + // try { + // while ((line = br.readLine()) != null) { + // System.out.println(line); + // if (!line.startsWith("700") ){ //TODO:miuraなら,試験モードにしない + // if (!uid.equals("miura")) siken_mode(); else + // System.out.println("miuraなら,試験モードにしない"); + // } + // } + // } catch (IOException e) { + // e.printStackTrace(); + // } + // } + // public void siken_mode(){ + // String command2 = "/edu/bin/siken-mode"; + // // String command = "/home/t/miura/bin/myfinger"; + // // System.out.println("command2: "+command2); + // Process process2 = null; + // try { + // process2 = Runtime.getRuntime().exec(command2); + // } catch (IOException e1) { + // e1.printStackTrace(); + // return; + // } + // InputStream is = process2.getInputStream(); + // BufferedReader br = new BufferedReader(new InputStreamReader(is)); + // String line=null; + // try { + // while ((line = br.readLine()) != null) { + // System.out.println(line); + // } + // } catch (IOException e) { + // e.printStackTrace(); + // } + // } + + // public static String capitalize(String s) { + // if (s.length() == 0) return s; + // return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); + // } + + public void getHostIp() { + // IPの取得 + StringBuffer sb = new StringBuffer(); + Enumeration enuIfs = null; + try { + enuIfs = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException e1) { + e1.printStackTrace(); + } + if (null != enuIfs) { + while (enuIfs.hasMoreElements()) { + NetworkInterface ni = (NetworkInterface) enuIfs.nextElement(); + Enumeration enuAddrs = ni.getInetAddresses(); + while (enuAddrs.hasMoreElements()) { + InetAddress in4 = (InetAddress) enuAddrs.nextElement(); + if (in4.getHostAddress().indexOf(":") > 0) + continue; // IPV6 address + if (!in4.getHostAddress().equals("127.0.0.1")) { + if (sb.length() > 0) + sb.append("/"); + sb.append(in4.getHostAddress()); + // シート番号(複数のインタフェースがあったとき,単純に上書き...) + seatnum = Integer.parseInt(in4.getHostAddress().split("\\.")[3]); + } + } + } + } + hostip = sb.toString(); + } + + // public String toString() { + // return (uid + " " + name + " " + hostip + " " + id + " " + lecture_id + " " + last + " " + first); + // } + + // ユーザ情報の追加 + // public void appendInfo(String string) { + // // public int id; + // // public int lecture_id; + // // public String last; + // // public String first; + // // System.out.println("InfoGetter line 402: "+string); + // String[] a = string.split(" "); + // id = Integer.parseInt(a[0]); + // lecture_id = Integer.parseInt(a[2]); + // last = a[3]; + // first = a[4]; + // } + + // public void appendLecture(String s) { + // Lecture l = new Lecture(s); + // activeLectures.add(l); + // // System.out.println(l.toString()); + // } + + // public void appendAssign(String s) { + // Assign a = new Assign(s); + // activeAssigns.add(a); + // } + + // public Lecture findLecture(int lecid) { + // for (Lecture l : activeLectures) { + // if (l.id == lecid) + // return l; + // } + // return null; + // } + + // レポートソース + // public void getReportSrc() { + // String repid = JOptionPane.showInputDialog(Shusseki.theapp, "input report id", last_inputted_report_src_id); + // if (repid != null) { + // String res = Poster.get(Shusseki.PROTOCOL + Shusseki.server + Shusseki.miuraattr + "/reports/getreportsrc/" + // + repid + "/hoge"); + // System.out.println(res); + // String[] lines = res.split("\r\n"); + // FileReadWriter.putLines(repid + ".c", lines); + // last_inputted_report_src_id = repid; + // } else { + // repid = last_inputted_report_src_id; + // } + + // String command2 = "/usr/bin/timeout 15 /usr/bin/konsole --noclose -e /edu/bin/ecc " + repid + ".c"; + // // String command = "/home/t/miura/bin/myfinger"; + // // System.out.println("command2: "+command2); + // Process process2 = null; + // try { + // process2 = Runtime.getRuntime().exec(command2); + // } catch (IOException e1) { + // e1.printStackTrace(); + // return; + // } + // InputStream is = process2.getInputStream(); + // BufferedReader br = new BufferedReader(new InputStreamReader(is)); + // String line = null; + // try { + // while ((line = br.readLine()) != null) { + // System.out.println(line); + // } + // } catch (IOException e) { + // e.printStackTrace(); + // } + + // } + + // // レポートソース + // public void getReportSrcF() { + // String repid = JOptionPane.showInputDialog(Shusseki.theapp, "input report id", last_inputted_report_src_id); + // if (repid != null) { + // String res = Poster.get(Shusseki.PROTOCOL + Shusseki.server + Shusseki.miuraattr + "/reports/getreportsrc/" + // + repid + "/hoge"); + // System.out.println(res); + // String[] lines = res.split("\r\n"); + // FileReadWriter.putLines(repid + ".f", lines); + // last_inputted_report_src_id = repid; + // } else { + // repid = last_inputted_report_src_id; + // } + + // String command2 = "/usr/bin/timeout 15 /usr/bin/konsole --noclose -e /edu/bin/e77 " + repid + ".f"; + // // String command = "/home/t/miura/bin/myfinger"; + // // System.out.println("command2: "+command2); + // Process process2 = null; + // try { + // process2 = Runtime.getRuntime().exec(command2); + // } catch (IOException e1) { + // e1.printStackTrace(); + // return; + // } + // InputStream is = process2.getInputStream(); + // BufferedReader br = new BufferedReader(new InputStreamReader(is)); + // String line = null; + // try { + // while ((line = br.readLine()) != null) { + // System.out.println(line); + // } + // } catch (IOException e) { + // e.printStackTrace(); + // } + + // } + + /** OSの種別 */ + public enum OSName { + AIX, HP_UX, IRIX, LINUX, MAC, MAC_OSX, OS2, SOLARIS, SUN_OS, WINDOWS, UNKNOWN + } + + /** + * OS名を取得する。 + * + * @return OS名 + */ + public static final OSName getOsName() { + if (SystemUtils.IS_OS_AIX) { + return OSName.AIX; + } else if (SystemUtils.IS_OS_HP_UX) { + return OSName.HP_UX; + } else if (SystemUtils.IS_OS_IRIX) { + return OSName.IRIX; + } else if (SystemUtils.IS_OS_LINUX) { + return OSName.LINUX; + } else if (SystemUtils.IS_OS_MAC) { + return OSName.MAC; + } else if (SystemUtils.IS_OS_MAC_OSX) { + return OSName.MAC_OSX; + } else if (SystemUtils.IS_OS_OS2) { + return OSName.OS2; + } else if (SystemUtils.IS_OS_SOLARIS) { + return OSName.SOLARIS; + } else if (SystemUtils.IS_OS_SUN_OS) { + return OSName.SUN_OS; + } else if (SystemUtils.IS_OS_WINDOWS) { + return OSName.WINDOWS; + } + return OSName.UNKNOWN; + } + + public static final String getOsNameString() { + if (SystemUtils.IS_OS_AIX) { + return "AIX"; + } else if (SystemUtils.IS_OS_HP_UX) { + return "HP_UX"; + } else if (SystemUtils.IS_OS_IRIX) { + return "IRIX"; + } else if (SystemUtils.IS_OS_LINUX) { + return "LINUX"; + } else if (SystemUtils.IS_OS_MAC_OSX) { + return "MAC_OSX"; + } else if (SystemUtils.IS_OS_MAC) { + return "MAC"; + } else if (SystemUtils.IS_OS_OS2) { + return "OS2"; + } else if (SystemUtils.IS_OS_SOLARIS) { + return "SOLARIS"; + } else if (SystemUtils.IS_OS_SUN_OS) { + return "SUN_OS"; + } else if (SystemUtils.IS_OS_WINDOWS) { + return "WINDOWS"; + } + return "UNKNOWN"; + } + +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/KeepOrderHash.java b/src/main/java/info/istlab/Zemi01/imgview/KeepOrderHash.java new file mode 100644 index 0000000..5ac4ee7 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/KeepOrderHash.java @@ -0,0 +1,23 @@ +package info.istlab.Zemi01.imgview; + +import java.util.ArrayList; +import java.util.Hashtable; + +public class KeepOrderHash { + public ArrayList orderarray; + public Hashtable hash; + public KeepOrderHash(){ + orderarray = new ArrayList(); + hash = new Hashtable(); + } + public void put(V v, E e){ + orderarray.add(v); + hash.put(v,e); + } + public ArrayList getIterator(){ + return orderarray; + } + public E get(V v){ + return hash.get(v); + } +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/MouseWheelRotationListener.java b/src/main/java/info/istlab/Zemi01/imgview/MouseWheelRotationListener.java new file mode 100644 index 0000000..6be8a6f --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/MouseWheelRotationListener.java @@ -0,0 +1,5 @@ +package info.istlab.Zemi01.imgview; + +public interface MouseWheelRotationListener { + public void mouseWheelRotated(float f); +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/MyAction.java b/src/main/java/info/istlab/Zemi01/imgview/MyAction.java new file mode 100644 index 0000000..89d82fd --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/MyAction.java @@ -0,0 +1,105 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.ArrayList; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JToggleButton; + +public class MyAction extends AbstractAction { + boolean isToggle; + private boolean isSelected; + private static final long serialVersionUID = -2253928255968178345L; + /** + * isToggleを省略すると,falseになる + * @param text + * @param icon + * @param desc + * @param mnemonic + */ + ArrayList actionListenerAry; + ArrayList itemListenerAry; + + public MyAction(String text, String icon, String desc) { + this(text,icon,desc,false); + } + + public MyAction(String text, String icon, + String desc, boolean isToggle) { + super(text, QuickMenuActionManager.createNavigationIcon(icon+"24")); + putValue(Action.SMALL_ICON, QuickMenuActionManager.createNavigationIcon(icon+"16")); + putValue(Action.LARGE_ICON_KEY, QuickMenuActionManager.createNavigationIcon(icon+"24")); + actionListenerAry = new ArrayList(); + itemListenerAry = new ArrayList(); + + putValue(SHORT_DESCRIPTION, desc); +// putValue(MNEMONIC_KEY, mnemonic); + if (isToggle) { + putValue("toggle","true"); + this.isToggle = isToggle; + } + } + public void addActionListenerToAry(ActionListener al){ + actionListenerAry.add(al); + } + public void addItemListenerToAry(ItemListener il){ + itemListenerAry.add(il); + } + + public void actionPerformed(ActionEvent e) { +// System.out.println("super.action"); + e.setSource(this); + for(ActionListener al: actionListenerAry){ + al.actionPerformed(e); + } + if (isToggle){ + setSelected(!isSelected); +// if (e.getSource() instanceof JCheckBoxMenuItem){ +// JCheckBoxMenuItem jmi = (JCheckBoxMenuItem) e.getSource(); +// setSelected(jmi.isSelected()); +// } +// if (e.getSource() instanceof JToggleButton){ +// JToggleButton jtb = (JToggleButton) e.getSource(); +// setSelected(jtb.isSelected()); +// } + } + } + @SuppressWarnings("unchecked") + public void setSelected(boolean b){ + isSelected = b; + + JToggleButton jtb = (JToggleButton) getValue("togglebutton"); + if (jtb != null) jtb.setSelected(isSelected); + + JCheckBoxMenuItem jmi = (JCheckBoxMenuItem) getValue("togglemenu"); + if (jmi != null) jmi.setSelected(isSelected); + +// 更新対象がリストの場合 + ArrayList jtbal = (ArrayList) getValue("togglebuttonList"); + if (jtbal != null) for(JToggleButton jtb0: jtbal) if (jtb0!=null) jtb0.setSelected(isSelected); + ArrayList jmial = (ArrayList) getValue("togglemenuList"); + if (jmial != null) for(JCheckBoxMenuItem jmi0: jmial) if(jmi0!=null) jmi0.setSelected(isSelected); + } + /** + * 未使用 + * @param e + */ + public void itemStateChanged(ItemEvent e){ + for(ItemListener il: itemListenerAry){ + il.itemStateChanged(e); + } + } + public boolean isSelected() { + return isSelected; + } + + public void doClick() { + actionPerformed(new ActionEvent(this, 1, "doClick")); + } + +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/MyPCanvas.java b/src/main/java/info/istlab/Zemi01/imgview/MyPCanvas.java new file mode 100644 index 0000000..5271b51 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/MyPCanvas.java @@ -0,0 +1,207 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.AWTException; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.geom.Point2D; + +import org.piccolo2d.PCamera; +import org.piccolo2d.PCanvas; +import org.piccolo2d.PInputManager; +import org.piccolo2d.event.PBasicInputEventHandler; +import org.piccolo2d.event.PInputEvent; +import org.piccolo2d.event.PInputEventFilter; +import org.piccolo2d.event.PPanEventHandler; +import org.piccolo2d.extras.event.PSelectionEventHandler; +import org.piccolo2d.extras.event.PZoomToEventHandler; +import org.piccolo2d.util.PBounds; + +@SuppressWarnings("serial") + + + +public class MyPCanvas extends PCanvas { + + static PInputEventFilter b1mask = new PInputEventFilter( + InputEvent.BUTTON1_MASK); + + static PInputEventFilter b2mask = new PInputEventFilter( + InputEvent.BUTTON2_MASK); + + static PInputEventFilter b3mask = new PInputEventFilter( + InputEvent.BUTTON3_MASK); + + static PInputEventFilter disablemask = new PInputEventFilter(0); + + PBasicInputEventHandler flowmenuEventHandler; + + PSelectionEventHandler selectionEventHandler; + + PPanEventHandler panEventHandler; + + PZoomToEventHandler zoomeh; + + Point2D cursorpoint; + + public PCamera cam; + + WheelZoomEventHandler wheelzoom; + + public MouseWheelRotationListener wheelListener; + + /** + * ホイール回転時のズーム方向.1または-1.デフォルトは1 = 手前(下)回転でズームイン + */ +// public int wheelrotationdirection = -1; + + /** + * カーソルを中央にもってくるかどうか + */ + public boolean moveMouseCursorOnZoomIn = true; + Robot robot; + + /** + * ズーム時の幅 + */ + public float wheelZoomRatio = 1.0f; + + public MyPCanvas() { + super(); + initialize(); + try { + robot = new Robot(); + } catch (AWTException e) { + } + } + /** + * 擬似的なクリック + * @param x + * @param y + */ + public void pseudoClick(int x, int y){ + getRoot().getDefaultInputManager().processEventFromCamera(new MouseEvent(this,0,0,MouseEvent.BUTTON1,x,y,1,true), MouseEvent.MOUSE_PRESSED, getCamera()); + getRoot().getDefaultInputManager().processEventFromCamera(new MouseEvent(this,0,0,MouseEvent.BUTTON1,x,y,1,false), MouseEvent.MOUSE_RELEASED, getCamera()); + } + + public void setWheelRotationDirection(int d){ + if (wheelzoom != null) wheelzoom.setDirection(d); + } + public void setMouseWheelRotationListener(MouseWheelRotationListener l){ + wheelListener = l; + } + public void setWheelZoomRatio(float f){ + wheelZoomRatio = f; + } + + public PBasicInputEventHandler getWheelListener() { + return wheelzoom; + } + + class WheelZoomEventHandler extends PBasicInputEventHandler { + public int direction = -1; + public void setDirection(int d){ + direction = d; + } + public void mouseWheelRotated(PInputEvent e) { + if (!e.isControlDown() && !e.isShiftDown() && !e.isAltDown()) { + PCamera pc = getCamera(); + +// System.out.println("wheel rotation: " + pc.getAttribute("hoge")); + PBounds pb = pc.getViewBounds(); +// System.out.println(pb.toString()); + float f = 1.0f + (0.1f * direction * e.getWheelRotation()); + if (e.getWheelRotation() //下に回すと正になるので + * direction < 0) { + pb = zoomBounds_focusbyCursor(pb, f); + } else { + pb = BUtil.zoomBounds(pb, f); + } + if (pb.x == 0 && pb.y == 0) { + System.out.println("ズームイン位置がまだ準備前"); + return; + } + pc.animateViewToCenterBounds(pb, true, 0); + if (MyPCanvas.this.wheelListener != null) MyPCanvas.this.wheelListener.mouseWheelRotated(f); + } + } + } + + public void initialize() { + cam = getCamera(); + + disablemask.rejectAllEventTypes(); + + wheelzoom = new WheelZoomEventHandler(); + wheelzoom.setEventFilter(b2mask); + cam.addInputEventListener(wheelzoom); + + // panEventHandler = new PPanEventHandler(); + // getPanEventHandler().setEventFilter(disablemask); + // panEventHandler.setEventFilter(b2mask); + // addInputEventListener(panEventHandler); + getPanEventHandler().setEventFilter(b2mask); + // check current cursor position + addInputEventListener(new PInputManager() { + public void mouseMoved(PInputEvent e) { + cursorpoint = e.getCanvasPosition(); + try { + e.getPath().getPathTransformTo(getLayer()).inverseTransform(cursorpoint, cursorpoint); + } catch (RuntimeException ex) { + cursorpoint = e.getPosition(); // Camera付きのメニューボタンや,背景部分(PCamera)のとき + } + // TODO: 本来であればRuntimeExceptionを出さずに処理したいのだが.. +// e.getPickedNode().localToParent(cursorpoint); +// System.out.println(e.getPickedNode().getRoot().getClass().getName()); +// if (e.getPickedNode() instanceof PCamera) +// else cursorpoint = e.getPositionRelativeTo(getLayer()); +// catch (NoninvertibleTransformException e1) { +// // TODO Auto-generated catch block +// e1.printStackTrace(); +// } + } + }); + } + + public PBounds zoomBounds_focusbyCursor(PBounds pb, double rate) { + double x = pb.getX(); + double y = pb.getY(); + double w = pb.getWidth(); + double h = pb.getHeight(); + double nw = w * rate; + double nh = h * rate; + Point2D camcp = cam.getViewBounds().getCenter2D(); + double camcx = camcp.getX(); + double camcy = camcp.getY(); +// System.out.println("camcp "+camcx+" "+camcy); + double curx = cursorpoint.getX(); + double cury = cursorpoint.getY(); +// System.out.println("cursor "+curx+" "+cury); + double nx = x - (nw - w) / 2 + curx - camcx; + double ny = y - (nh - h) / 2 + cury - camcy; + PBounds ret = new PBounds(nx, ny, nw, nh); + cursorpoint = ret.getCenter2D(); + if (moveMouseCursorOnZoomIn) { + moveCursorPointCenter(); + } else { + } + return ret; + } + + public void moveCursorPointCenter() { + Point canvasglobalp = getLocationOnScreen(); + int canvasw = getWidth(); + int canvash = getHeight(); + if (robot != null) + robot.mouseMove((int) (canvasglobalp.getX() + canvasw / 2), + (int) (canvasglobalp.getY() + canvash / 2)); + } +} + +//@SuppressWarnings("serial") +//class MyPCanvas_noPointerZoom extends MyPCanvas { +//public PBounds zoomBounds_focusbyCursor(PBounds pb, double rate) { +//return BUtil.zoomBounds(pb, rate); +//} +//} diff --git a/src/main/java/info/istlab/Zemi01/imgview/MyPImage.java b/src/main/java/info/istlab/Zemi01/imgview/MyPImage.java new file mode 100644 index 0000000..818f85c --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/MyPImage.java @@ -0,0 +1,339 @@ +package info.istlab.Zemi01.imgview; + +/* + * Copyright (c) 2002-@year@, University of Maryland + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the University of Maryland nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Piccolo was written at the Human-Computer Interaction Laboratory www.cs.umd.edu/hcil by Jesse Grosjean + * under the supervision of Ben Bederson. The Piccolo website is www.cs.umd.edu/hcil/piccolo. + */ + +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import javax.imageio.ImageIO; +import javax.swing.JFrame; + +import org.piccolo2d.PNode; +import org.piccolo2d.util.PBounds; +import org.piccolo2d.util.PPaintContext; + +/** + * PImage is a wrapper around a java.awt.Image. If this node is copied or + * serialized that image will be converted into a BufferedImage if it is not + * already one. + *

+ * + * 上記のやり方だと,一度シリアライズした画像データは非常にかさばる形式になり, + * 保存にむいていない.また,レンダリングにも時間がかかる. + * そのため,元画像のソース(JPGならJPGファイル,GIFならGIFファイル)のバイナリを + * 保存しておき,デシリアライズ時に回復するクラスをつくり,MyPImageとして用意した. + * + * @version 1.0 + * @author Jesse Grosjean + */ +public class MyPImage extends PNode { + + private static final long serialVersionUID = -2779887448253879707L; + /** + * The property name that identifies a change of this node's image (see + * {@link #getImage getImage}). Both old and new value will be set correctly + * to Image objects in any property change event. + */ + public static final String PROPERTY_IMAGE = "image"; + public static final int PROPERTY_CODE_IMAGE = 1 << 15; + + private transient Image image; + public byte[] sourcebytes; // ここに,イメージの基を溜め込む + + public MyPImage() { + super(); + } + + /** + * Construct a new PImage wrapping the given java.awt.Image. + */ + public MyPImage(Image newImage) { + this(); + sourcebytes = getImageBytesFromImage(newImage); + restoreImage(); +// setImage(newImage); + } + + public MyPImage(Image newImage, String jpgORpng) { + this(); + sourcebytes = getImageBytesFromImage(newImage, jpgORpng); + restoreImage(); + } + public MyPImage(byte[] bytes, boolean copy){ + if (copy) { + sourcebytes = new byte[bytes.length]; + for(int i=0;inull, create an + * empty PImage; this behaviour is useful when fetching resources that may + * be missing. + */ + public MyPImage(java.net.URL url) { + this(); + if (url != null) setImage(Toolkit.getDefaultToolkit().getImage(url)); + } + + /** + * Returns the image that is shown by this node. + * @return the image that is shown by this node + */ + public Image getImage() { + return image; + } + + /** + * Set the image that is wrapped by this PImage node. This method will also + * load the image using a MediaTracker before returning. + */ + public void restoreImage() { + image = Toolkit.getDefaultToolkit().createImage(sourcebytes); + setImage(image); +// setImage(Toolkit.getDefaultToolkit().getImage(fileName)); + } + + public void readImageToBuffer(String s){ + File f = new File(s); + long fsize = f.length(); + + InputStream in = null; + int b; + try { + in = new BufferedInputStream(new FileInputStream(s)); + final int LS = 1024; + byte buf[] = new byte[LS]; + ByteArrayOutputStream varyBuf = new ByteArrayOutputStream((int)fsize) ; + + while((b = in.read(buf, 0, buf.length)) != -1 ) { + varyBuf.write(buf,0,b) ; + } + sourcebytes = varyBuf.toByteArray(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + } + } + + + + /** + * Set the image that is wrapped by this PImage node. This method will also + * load the image using a MediaTracker before returning. + */ + public void setImage(Image newImage) { + Image old = image; + + if (newImage instanceof BufferedImage) { + image = newImage; + } else { // else make sure the image is loaded +// 画像の読込完了を待つ + MediaTracker mt = new MediaTracker(new JFrame()); + mt.addImage(newImage, 0); + try{ + mt.waitForID(0); + }catch(InterruptedException e){} + image = newImage; + } + if (image != null) { + setBounds(0, 0, getImage().getWidth(null), getImage().getHeight(null)); + invalidatePaint(); + } else { + image = null; + } + + firePropertyChange(PROPERTY_CODE_IMAGE, PROPERTY_IMAGE, old, image); + } + + protected void paint(PPaintContext paintContext) { + if (getImage() != null) { + double iw = image.getWidth(null); + double ih = image.getHeight(null); + PBounds b = getBoundsReference(); + Graphics2D g2 = paintContext.getGraphics(); + + if (b.x != 0 || b.y != 0 || b.width != iw || b.height != ih) { + g2.translate(b.x, b.y); + g2.scale(b.width / iw, b.height / ih); + g2.drawImage(image, 0, 0, null); + g2.scale(iw / b.width, ih / b.height); + g2.translate(-b.x, -b.y); + } else { + g2.drawImage(image, 0, 0, null); + } + } + } + + //**************************************************************** + // Serialization + //**************************************************************** + + /** + * The java.awt.Image wrapped by this PImage is converted into a BufferedImage + * when serialized. + */ + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); +// BufferedImage bufferedImage = toBufferedImage(image, false); +// if (bufferedImage != null) ImageIO.write(bufferedImage, "png", out); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + image = Toolkit.getDefaultToolkit().createImage(sourcebytes); + // 画像の読込完了を待つ + MediaTracker mt = new MediaTracker(new JFrame()); + mt.addImage(image, 0); + try{ + mt.waitForID(0); + }catch(InterruptedException e){} +// invalidatePaint(); +// image = ImageIO.read(in); + } + + //**************************************************************** + // Util + //**************************************************************** + + /** + * If alwaysCreateCopy is false then if the image is already a buffered + * image it will not be copied and instead the original image will just be + * returned. + */ + public static BufferedImage toBufferedImage(Image image, boolean alwaysCreateCopy) { + if (image == null) return null; + + if (!alwaysCreateCopy && image instanceof BufferedImage) { + return (BufferedImage) image; + } else { + GraphicsConfiguration graphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); + BufferedImage result = graphicsConfiguration.createCompatibleImage(image.getWidth(null), image.getHeight(null)); + Graphics2D g2 = result.createGraphics(); + g2.drawImage(image, 0, 0, null); + g2.dispose(); + return result; + } + } + public BufferedImage getBufferedImage(){ + return toBufferedImage(image, true); + } + + /** + * イメージを変換し,取り込み + * @param img + * @param format "jpg"or"png"; + */ + public static byte[] getImageBytesFromImage(Image img, String format){ + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + try { + ImageIO.write(toBufferedImage(img, true), format, buf); + } catch (IOException e) { + e.printStackTrace(); + } + return buf.toByteArray(); + } + + public static byte[] getImageBytesFromImage(Image img){ + byte[] png = getImageBytesFromImage(img, "png"); + byte[] jpg = getImageBytesFromImage(img, "jpg"); +// System.out.println("png "+png.length + " jpg "+jpg.length); + if (png.length <= jpg.length) { +// System.out.println("png is better "); + return png; + } else { +// System.out.println("jpg is better "); + return jpg; + } + + } + + //**************************************************************** + // Debugging - methods for debugging + //**************************************************************** + + /** + * Returns a string representing the state of this node. This method is + * intended to be used only for debugging purposes, and the content and + * format of the returned string may vary between implementations. The + * returned string may be empty but may not be null. + * + * @return a string representation of this node's state + */ + protected String paramString() { + StringBuffer result = new StringBuffer(); + + result.append("image=" + (image == null ? "null" : image.toString())); + result.append(','); + // result.append(super.paramString()); //APIが古くてなくなったので、とりあえず削除した。 + + return result.toString(); + } + + public MyPImage localClone(){ + MyPImage clone = (MyPImage) this.clone(); + clone.setImage(this.getImage()); + clone.setBounds(this.getBounds()); + clone.removeAllChildren(); + return clone; + } +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/PPPath.java b/src/main/java/info/istlab/Zemi01/imgview/PPPath.java new file mode 100644 index 0000000..641934a --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/PPPath.java @@ -0,0 +1,64 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Path2D; +import java.awt.geom.Rectangle2D; + +import org.piccolo2d.nodes.PPath; + +/** + * 以前のPiccolo PPathとの互換性をとるためのクラス + */ +public class PPPath extends PPath.Double { + private static final Rectangle2D.Float TEMP_RECTANGLE = new Rectangle2D.Float(); + private static final Ellipse2D.Float TEMP_ELLIPSE = new Ellipse2D.Float(); + private static final BasicStroke DEFAULT_STROKE = new BasicStroke(1.0f); + private static final Color DEFAULT_STROKE_PAINT = Color.black; + private transient Stroke stroke; + public PPPath(){ + super(new Path2D.Float()); + // setStrokePaint(DEFAULT_STROKE_PAINT); + // setStroke(DEFAULT_STROKE); + setPaint(null); + } + public PPPath(Shape aShape) { + this(aShape, DEFAULT_STROKE); + } + public PPPath(Shape aShape, Stroke aStroke) { + this(); + stroke = aStroke; + if (aShape != null) append(aShape, false); + } + public void setPathTo(final Shape aShape) { + this.getPathReference().reset(); + append(aShape, false); + } + public void setPathToRectangle(float x, float y, float width, float height){ + TEMP_RECTANGLE.setFrame(x, y, width, height); + setPathTo(TEMP_RECTANGLE); + } + public void setPathToEllipse(float x, float y, float width, float height) { + TEMP_ELLIPSE.setFrame(x, y, width, height); + setPathTo(TEMP_ELLIPSE); + } + /** + * Return a reference to the list used to manage this node's + * children. This list should not be modified. + * + * @return reference to the children list + */ + // public List getChildrenReference() { + // if (children == null) { + // children = new ArrayList(); + // } + // return children; + // } + // public PInterpolatingActivity animateToStrokeColor(final Color destColor, final long duration) { + // return super.animateToColor(destColor, duration); + + // } +} diff --git a/src/main/java/info/istlab/Zemi01/imgview/QuickMenuActionManager.java b/src/main/java/info/istlab/Zemi01/imgview/QuickMenuActionManager.java new file mode 100644 index 0000000..a452e46 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/QuickMenuActionManager.java @@ -0,0 +1,149 @@ +package info.istlab.Zemi01.imgview; +import java.awt.event.ActionListener; +import java.awt.event.ItemListener; +import java.awt.event.KeyListener; +import java.util.ArrayList; +import java.util.Hashtable; + +import javax.swing.AbstractButton; +import javax.swing.Action; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; + +public class QuickMenuActionManager { + protected KeepOrderHash> menurepos; // "File"=> ArrayList + protected Hashtable name2act; + protected Hashtable name2tbutton; + public QuickMenuActionManager(){ + menurepos = new KeepOrderHash>(); + name2act = new Hashtable(); + name2tbutton = new Hashtable(); + } + protected MyAction lastOne; + public void addAction(String type, MyAction a){ + ArrayList al = menurepos.get(type); + if (al == null){ + al = new ArrayList(); + al.add(a); + menurepos.put(type, al); + } else { + al.add(a); + } + name2act.put((String)a.getValue(Action.NAME), a); + System.out.println((String)a.getValue(Action.NAME)); + lastOne = a; + } + public void addHandler_Action(ActionListener al){ + lastOne.addActionListenerToAry(al); + } + public void addHandler_Item(ItemListener il){ + lastOne.addItemListenerToAry(il); + } + public MyAction getAction(String key){ + return name2act.get(key); + } + public AbstractButton getButton(String key){ + return name2tbutton.get(key); + } + + public JMenuBar getMenuBar(){ + JMenuItem menuItem = null; + JMenuBar menuBar; + + //Create the menu bar. + menuBar = new JMenuBar(); + + for(String type: menurepos.getIterator()){ + JMenu mainMenu = new JMenu(type); + for(Action a: menurepos.get(type)){ + if (a.getValue("toggle") != null){ + menuItem = new JCheckBoxMenuItem(a); + a.putValue("togglemenu", menuItem); + } else { + menuItem = new JMenuItem(a); + } +// menuItem.setIcon(null); //arbitrarily chose not to use icon + mainMenu.add(menuItem); + } + menuBar.add(mainMenu); + } + return menuBar; + } + public JToolBar getToolBar(KeyListener editor) { + AbstractButton button = null; + + //Create the toolbar. + JToolBar toolBar = new JToolBar(); + + for(String type: menurepos.getIterator()){ + for(Action a: menurepos.get(type)){ + if (a.getValue("toggle") != null){ + button = new JToggleButton(a); + a.putValue("togglebutton", button); + } else { + button = new JButton(a); + } + if (button.getIcon() != null) { +// button.setText(""); //an icon-only button + } + toolBar.add(button); + button.addKeyListener(editor); + name2tbutton.put(button.getText(),button);//あとでテキスト隠したりするときに参照が必要なので +// System.out.println("BUTTON:: "+button.getText()); + } + toolBar.addSeparator(); + } + return toolBar; + } + + /** Returns an ImageIcon, or null if the path was invalid. */ + public static ImageIcon createNavigationIcon(String imageName) { + ClassLoader cl = QuickMenuActionManager.class.getClassLoader(); + + if (cl == null) { + System.err.println("Resource not found: "+ imageName); + return null; + } + String imgLocation = "toolbarButtonGraphics/" + + imageName + + ".gif"; + if (imageName.startsWith("_")){ + imgLocation = "myicon/" + imageName.substring(1)+".gif"; + ImageIcon ii; + try{ + ii = new ImageIcon(cl.getResource(imgLocation)); + }catch(NullPointerException ex){ + ii = new ImageIcon("resource/"+imgLocation); + } + return ii; + } else { + +// java.net.URL imageURL = maincls.getResource(imgLocation); + + return new ImageIcon(cl.getResource(imgLocation)); + } + } + public void foldToolbarText(boolean f){ + if (f){ + for(AbstractButton ab: name2tbutton.values()){ + if (ab.getIcon()!= null){ + ab.setText(null); + } + } + } else { + for(String key: name2tbutton.keySet()){ + AbstractButton ab = name2tbutton.get(key); + ab.setText(key); +// ab.validate(); + } + } + } + +} + diff --git a/src/main/java/info/istlab/Zemi01/imgview/ScrCapture.java b/src/main/java/info/istlab/Zemi01/imgview/ScrCapture.java new file mode 100644 index 0000000..8637267 --- /dev/null +++ b/src/main/java/info/istlab/Zemi01/imgview/ScrCapture.java @@ -0,0 +1,469 @@ +package info.istlab.Zemi01.imgview; + +import java.awt.AWTException; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.image.AreaAveragingScaleFilter; +import java.awt.image.BufferedImage; +import java.awt.image.ConvolveOp; +import java.awt.image.FilteredImageSource; +import java.awt.image.ImageFilter; +import java.awt.image.ImageProducer; +import java.awt.image.Kernel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.SimpleDateFormat; +import java.util.Date; + +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JOptionPane; + +//import com.sun.image.codec.jpeg.JPEGCodec; +//import com.sun.image.codec.jpeg.JPEGEncodeParam; +//import com.sun.image.codec.jpeg.JPEGImageEncoder; + + +public class ScrCapture implements Runnable { + public Thread capthread; + + public String format; + public int msec; + public CaptureCallback retobj; + byte[] bb; + int mochatstate = -1; + int limitsize = 0; + JFrame parentFrame; + + public ScrCapture(String format, CaptureCallback call, int wait_msec, JFrame parent){ + retobj = call; + this.format = format; + msec = wait_msec; + parentFrame = parent; + + capthread = new Thread(this); + capthread.start(); + + } + + @Override + public void run() { + if (parentFrame != null) parentFrame.setState(JFrame.ICONIFIED); + try { + Thread.sleep(msec); // プラス2秒は,captureのなかで + } catch (InterruptedException e) { + e.printStackTrace(); + } + capture(); + + } + public void capture(){ + System.out.print("capture - "); + String osname = InfoGetter.getOsNameString(); + if (osname.startsWith("Linux")){ + // bb = getImageFromClipboard("JPG"); + bb = getImageFromGnome(format); //JPG or PNG + } else { + bb = getImage(format); //JPG or PNG + } + // if (bb == null) return;//キャプチャエラーか,60秒以内に操作しなかった. + System.out.println(format+":"+bb.length); + retobj.finished(bb); + + if (parentFrame != null) parentFrame.setState(JFrame.NORMAL); + } + public byte[] getImage(String imgtype){ + // capture the whole screen + BufferedImage screencapture = null; + try { + screencapture = new Robot().createScreenCapture( + new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()) ); + } catch (AWTException e1) { + e1.printStackTrace(); + } + + ByteArrayOutputStream imgbaos = new ByteArrayOutputStream(); + try{ + ImageIO.write(screencapture, imgtype, imgbaos); + } catch(IOException ex){ + System.out.println("can't capture"); + } + if (imgtype == "JPG"){ + // byte[] b = miniImage(imgbaos.toByteArray(), imgbaos.size()*2/3); + byte[] b = miniImage(imgbaos.toByteArray(), 1024*60); + return b; + } + return imgbaos.toByteArray(); + + // Save as JPEG + // File file = new File("screencapture.png"); + // try { + // ImageIO.write(screencapture, "png", file); + // } catch (IOException e) { + // e.printStackTrace(); + // } + } + + Process process = null; + public byte[] getImageFromGnome(String imgtype){ + //この時刻よりも後のファイルだけを対象とする + SimpleDateFormat sdf; +// sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + sdf = new SimpleDateFormat("yyyy-MM-dd hh-mm-ss"); + String compareFileName = "Screenshot from "+sdf.format(new Date())+".png"; + try { Thread.sleep(2000); } catch (InterruptedException e1) { e1.printStackTrace(); } + String command; + command = "/usr/bin/gnome-screenshot"; + // command = "/usr/bin/gsettings set org.gnome.gnome-screenshot auto-save-directory file:///home/t/"+ig.uid; + try { + process = Runtime.getRuntime().exec(command); + } catch (IOException e1) { e1.printStackTrace(); } + command = "/usr/bin/gnome-screenshot"; + try { + process = Runtime.getRuntime().exec(command); + } catch (IOException e1) { e1.printStackTrace(); } + //wait and load + int count=32; + File toberemoved = null; + while(count>0 && toberemoved ==null){ + try { Thread.sleep(2000); } catch (InterruptedException e1) { e1.printStackTrace(); } + File f = new File("capture.png"); + for(File ff: f.listFiles()){ + String target = ff.getName(); + System.out.println("checking "+ff.getAbsoluteFile()); + if (target.startsWith("Screenshot from 20")){ + if (target.compareTo(compareFileName) > 0){ + toberemoved = ff; + break; + } + } + } + count--; + } + if (toberemoved == null) { + JOptionPane.showMessageDialog(null, "画面レポート送信失敗.\n\nキャプチャ後,60秒以内に「保存(S)」をおしてください.\n\n保存をキャンセルして,もう一度Shussekiのメニューから「送信>画面レポート」を実行してください."); + return null; + } + BufferedImage screencapture = null; + try { + screencapture = ImageIO.read(toberemoved); + } catch (IOException e) { + e.printStackTrace(); + } + ByteArrayOutputStream imgbaos = new ByteArrayOutputStream(); + try{ + ImageIO.write(screencapture, imgtype, imgbaos); + } catch(IOException ex){ + System.out.println("can't capture"); + } + try { + imgbaos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + toberemoved.delete(); + if (imgtype == "JPG" && limitsize > 0){ + // byte[] b = miniImage(imgbaos.toByteArray(), imgbaos.size()*2/3); + byte[] b = miniImage(imgbaos.toByteArray(), limitsize); + return b; + } + return imgbaos.toByteArray(); + } + + /** + * サイズの圧縮 + * @param byteData + * @param max_bytesize + * @return + */ + byte[] miniImage(byte[] byteData, double max_bytesize) { + if (byteData == null) + return null; + + ByteArrayInputStream input = new ByteArrayInputStream(byteData); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try { + BufferedImage image = ImageIO.read(input); + ImageIO.write(image,"jpeg",output); +// JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(output); +// +// JPEGEncodeParam encodeParam = encoder +// .getDefaultJPEGEncodeParam(image); + + // boolean widthCheck = false; + // boolean heightCheck = false; + // + // JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(input); + +// float sizeValue = new Float(max_bytesize).floatValue() +// / byteData.length; + +// encodeParam.setQuality(sizeValue, false); +// encoder.encode(image, encodeParam); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + input.close(); + output.flush(); + output.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + byte[] byteDataResult = null; + if (output.size() > 0) + byteDataResult = output.toByteArray(); + + return byteDataResult; + } + public BufferedImage toBufferedImage(Image img){ + if (img instanceof BufferedImage) + { + return (BufferedImage) img; + } + + // Create a buffered image with transparency + BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB); + + // Draw the image on to the buffered image + Graphics2D bGr = bimage.createGraphics(); + bGr.drawImage(img, 0, 0, null); + bGr.dispose(); + + // Return the buffered image + return bimage; + } + + public static void writeBytesToFile(String filepath, byte[] ba){ + OutputStream fos = null; + DataOutputStream dos = null; + try{ + fos = new FileOutputStream(filepath); + dos = new DataOutputStream(fos); + dos.write(ba); + dos.close(); + fos.close(); + }catch(IOException iex){ + iex.printStackTrace(System.out); + } + } + + public static byte[] readBytesFromFile(String filepath){ + InputStream fos = null; + DataInputStream dos = null; + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try{ + fos = new FileInputStream(filepath); + dos = new DataInputStream(fos); + int len; + byte buf[] = new byte[1024]; + while((len=dos.read(buf))!=-1){ + output.write(buf, 0, len); + } + dos.close(); + fos.close(); + }catch(IOException iex){ + iex.printStackTrace(System.out); + } + return output.toByteArray(); + } + + public static ByteArrayOutputStream crop(ByteArrayInputStream input, String format, int[] rect){ + ByteArrayOutputStream imgbaos = new ByteArrayOutputStream(); + try { + BufferedImage image = ImageIO.read(input); + BufferedImage cropped = image.getSubimage(rect[0],rect[1],rect[2],rect[3]); + + ImageIO.write(cropped, format, imgbaos); + + } catch (IOException e2) { + e2.printStackTrace(); + } finally { + try { + input.close(); + imgbaos.flush(); + imgbaos.close(); + } catch (IOException e3) { + e3.printStackTrace(); + } + } + return imgbaos; + } + public static ByteArrayOutputStream pixelize(ByteArrayInputStream input, String format, int[] rect, int PIX_SIZE){ + ByteArrayOutputStream imgbaos = new ByteArrayOutputStream(); + try { + BufferedImage image = ImageIO.read(input); + Raster src = image.getData(); + WritableRaster dest = src.createCompatibleWritableRaster(); + double[] pixel = new double[3]; + for(int y=0;y