import eyedev._01.CharacterLearner; import eyedev._21.ImageInfo; import eyedev._09.Subrecognition; import eyedev._01.ImageWithMarkLines; import prophecy.common.gui.SingleComponentPanel; import drjava.util.Trigger; import eyedev._17.MarkLine; import eyedev._21.Correction; import eyedev._21.Corrections; import drjava.util.ObjectUtil; import drjava.util.StringUtil; import eyedev._01.DebugItem; import prophecy.common.image.ImageSurface; import prophecy.common.image.RGBImage; sclass XRecognizableImage extends SingleComponentPanel { ImageInfo imageInfo; private BufferedImage image; private double zoom = 1.0; protected Subrecognition markedSubrecognition, lastMarkedSubrecognition; protected java.util.List debugInfo; private ImageSurface imageSurface; private boolean selectableBoxes; private Subrecognition selectedSubrecognition; public final Trigger markChangeTrigger = new Trigger(); public final Trigger selectionChangeTrigger = new Trigger(); private boolean doubleBuffering; private boolean drawMarkLines; private boolean drawConfidenceBoxes = false; private float minConfidence = 0.5f; // anything below this confidence is shown in dark red private Corrections corrections = new Corrections(); *() { setImage((BufferedImage) null); } *(RGBImage image) { setImage(image); } /* replace image, but keep scroll location if possible */ public void updateImage(RGBImage image) { updateImage(image.getBufferedImage()); } /* replace image, but keep scroll location if possible */ public void updateImage(BufferedImage image) { if (this.image != null && image != null && this.image.getWidth() == image.getWidth() && this.image.getHeight() == image.getHeight()) { this.image = image; imageSurface.setImage(image); } else setImage(image); } public void setImage(RGBImage image) { setImage(image.getBufferedImage()); } public void setImage(BufferedImage image) { this.image = image; clearOverlays(); if (image == null) { setComponent(new JScrollPane()); imageSurface = null; } else { imageSurface = new ImageSurface(image) { @Override protected void fillPopupMenu(JPopupMenu menu, Point point) { super.fillPopupMenu(menu, point); XRecognizableImage.this.fillPopupMenu(menu, point); } public void render(int w, int h, Graphics2D g) { super.render(w, h, g); g.scale(imageSurface.getZoomX(), imageSurface.getZoomY()); renderOverlays(g); } }; imageSurface.addMouseMotionListener(new MouseMotionListener() { public void mouseDragged(MouseEvent e) { } public void mouseMoved(MouseEvent e) { surfaceMouseMove(e); } }); imageSurface.addMouseListener(new MouseAdapter() { public void mouseEntered(MouseEvent e) { surfaceMouseMove(e); } public void mouseExited(MouseEvent e) { setMarkedSubrecognition(null, false); } @Override public void mousePressed(MouseEvent e) { surfaceMouseClick(e); } }); imageSurface.setZoom(zoom); if (doubleBuffering) // This makes Surface create a buffer image imageSurface.setImageType(2); JScrollPane scrollPane = imageSurface.makeScrollPane(); scrollPane.getVerticalScrollBar().setUnitIncrement(10); setComponent(scrollPane); } } private void clearOverlays() { markedSubrecognition = null; selectedSubrecognition = null; debugInfo = null; } private Subrecognition findSubrecognition(MouseEvent e) { Point p = new Point((int) (e.getX()/imageSurface.getZoomX()), (int) (e.getY()/imageSurface.getZoomY())); if (debugInfo != null) for (DebugItem item : debugInfo) if (item.data instanceof Subrecognition) { Subrecognition s = (Subrecognition) item.data; Rectangle r = new Rectangle(s.clip); r.grow(1, 1); if (r.contains(p)) return s; } return null; } private void surfaceMouseMove(MouseEvent e) { setMarkedSubrecognition(findSubrecognition(e), false); } private void surfaceMouseClick(MouseEvent e) { Subrecognition s = findSubrecognition(e); if (selectableBoxes) setSelectedSubrecognition(s); else if (s != null) subrecognitionClicked(s, e); } // override this public void subrecognitionClicked(Subrecognition s, MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) correctCharacter(s); } public void setZoom(double zoom) { if (zoom == this.zoom) return; this.zoom = zoom; if (image != null) setImage(image); } protected void renderOverlays(Graphics2D g) { if (drawConfidenceBoxes) drawConfidenceBoxes(g); if (markedSubrecognition != null) drawBox(g, markedSubrecognition, Color.yellow, 2); if (selectedSubrecognition != null) drawBox(g, selectedSubrecognition, Color.blue, 2); if (drawMarkLines && debugInfo != null) for (DebugItem debugItem : debugInfo) { if (debugItem.data instanceof MarkLine) { MarkLine markLine = (MarkLine) debugItem.data; g.setColor(Color.blue); g.setStroke(new BasicStroke(1)); int y = markLine.type == MarkLine.Type.base ? markLine.y+1 : markLine.y; g.drawLine(markLine.x, y, markLine.x+markLine.width-1, y); } } drawCorrections(g); } private void drawCorrections(Graphics2D g) { for (Correction correction : corrections) { g.setColor(Color.green); g.setStroke(new BasicStroke(1)); Rectangle r = correction.getRectangle(); g.drawRect(r.x, r.y, r.width, r.height); } } private void drawConfidenceBoxes(Graphics2D g) { if (debugInfo != null) for (DebugItem debugItem : debugInfo) if (debugItem.data instanceof Subrecognition) { Subrecognition s = (Subrecognition) debugItem.data; //main.print("Drawing confidence box"); float adjustedConfidence = Math.max(0, s.confidence-minConfidence)/(1.0f-minConfidence); float redness = 1f-adjustedConfidence; Color boxColor = new Color(1f, 0f, 0f, redness); drawBox(g, s, boxColor, 2); } } public void drawBox(Graphics2D g, Subrecognition subrecognition, Color color, int strokeWidth) { g.setColor(color); g.setStroke(new BasicStroke((float) strokeWidth)); Rectangle r = subrecognition.clip; g.drawRect(r.x-1, r.y-1, r.width+2, r.height+2); } public void setMarkedSubrecognition(Subrecognition subrecognition, boolean scroll) { if (!ObjectUtil.equal(subrecognition, markedSubrecognition)) { if (subrecognition != null) lastMarkedSubrecognition = subrecognition; //System.out.println("subrecognition: " + subrecognition + ", lastMarkedSubrecognition: " + lastMarkedSubrecognition); markedSubrecognition = subrecognition; S tooltip = null; if (subrecognition != null) { Correction correction = findCorrection(subrecognition.clip); S ct = correction != null ? correction.getText() : null; S ch = "(unknown character)"; if (subrecognition.text == null) { if (ct != null) ch = "corrected as " + ct; } else { ch = subrecognition.text; if (ct != null && neq(subrecognition.text, ct)) ch += " / corrected as " + ct; } tooltip = ""; tooltip += StringUtil.escapeHtml(ch); tooltip += "
confidence: " + (int) (subrecognition.confidence*100) + "%"; //System.out.println("line: " + subrecognition.line); if (subrecognition.line != null) tooltip += "
" + StringUtil.escapeHtml(subrecognition.line.text); tooltip += ""; } imageSurface.setToolTipText(tooltip); repaintImageSurface(); if (scroll && subrecognition != null) imageSurface.scrollRectToVisible(new Rectangle(subrecognition.clip)); markChangeTrigger.trigger(); } } public void repaintImageSurface() { if (imageSurface != null) imageSurface.repaint(); } public void setSelectedSubrecognition(Subrecognition subrecognition) { if (!ObjectUtil.equal(subrecognition, selectedSubrecognition)) { selectedSubrecognition = subrecognition; repaintImageSurface(); selectionChangeTrigger.trigger(); } } public void setDebugInfo(List debugInfo) { this.debugInfo = debugInfo; selectedSubrecognition = null; repaintImageSurface(); } public void setSelectableBoxes(boolean selectableBoxes) { this.selectableBoxes = selectableBoxes; } public Subrecognition getSelectedSubrecognition() { return selectedSubrecognition; } public Subrecognition getMarkedSubrecognition() { return markedSubrecognition; } public void setDoubleBuffering(boolean b) { doubleBuffering = b; setImage(image); } public void setDrawMarkLines(boolean b) { if (drawMarkLines != b) { drawMarkLines = b; repaintImageSurface(); } } public boolean getDrawConfidenceBoxes() { return drawConfidenceBoxes; } public void setDrawConfidenceBoxes(boolean drawConfidenceBoxes) { if (this.drawConfidenceBoxes != drawConfidenceBoxes) { this.drawConfidenceBoxes = drawConfidenceBoxes; repaintImageSurface(); } } public void setCorrections(Corrections corrections) { this.corrections = corrections; } Correction findCorrection(Point point) { if (imageInfo != null && imageInfo.getCorrections() != null) for (final Correction correction : imageInfo.getCorrections()) if (correction.getRectangle().contains(point)) ret correction; null; } // exact match Correction findCorrection(Rectangle r) { if (imageInfo != null && imageInfo.getCorrections() != null) for (final Correction correction : imageInfo.getCorrections()) if (correction.getRectangle().equals(r)) ret correction; null; } public void fillPopupMenu(JPopupMenu menu, Point point) { prependMenuItem_correctCharacter(menu); prependMenuItem_removeCorrection(menu, point); } void prependMenuItem_removeCorrection(JPopupMenu menu, Point point) { final Correction correction = findCorrection(point); if (correction != null) { JMenuItem mi = new JMenuItem("Remove correction"); mi.addActionListener(actionListener { imageInfo.getCorrections().remove(correction); callOpt(mc(), "saveImageInfo"); }); menu.insert(mi, 0); } } private void prependMenuItem_correctCharacter(JPopupMenu menu) { final Subrecognition subrecognition = lastMarkedSubrecognition; if (subrecognition != null) { String text; if (subrecognition.text != null) text = "Correct character (" + subrecognition.text + ")..."; else text = "Enter character..."; JMenuItem mi = new JMenuItem(text); //JMenuItem mi = new JMenuItem("Correct character..."); mi.addActionListener(actionListener { correctCharacter(subrecognition); }); if (menu.getComponentCount() != 0) menu.insert(new JPopupMenu.Separator(), 0); menu.insert(mi, 0); } } void correctCharacter(Subrecognition subrecognition) { S text = "Correct character"; //text += " (type x_ if it's the left half of an x)"; String newText = JOptionPane.showInputDialog(text, subrecognition.text == null ? "" : subrecognition.text); if (newText != null) correctCharacter(subrecognition, newText); } void correctCharacter(Subrecognition subrecognition, String newText) { //subrecognition.text = newText; ImageWithMarkLines imageWithMarkLines = new ImageWithMarkLines(subrecognition.image, subrecognition.topLine, subrecognition.baseLine); CharacterLearner characterLearner = recognizer.getCharacterLearner(); if (characterLearner != null) { characterLearner.learnCharacter(imageWithMarkLines, newText); callOpt(mc(), "recognizerModified"); } if (imageInfo != null) { imageInfo.getCorrections().add(new Correction(subrecognition.clip, newText)); callOpt(mc(), "saveImageInfo"); } } /*public void subrecognitionClicked(Subrecognition s) { if (!quickCaretMove) { ++blockImageAndTextUpdates; textArea.jumpToLocation(s); --blockImageAndTextUpdates; } }*/ }