Changeset 1102 for trunk/src/org/expeditee/items/Picture.java
- Timestamp:
- 05/10/18 16:04:51 (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/expeditee/items/Picture.java
r1047 r1102 19 19 package org.expeditee.items; 20 20 21 import java.awt.AlphaComposite;22 import java.awt.BasicStroke;23 import java.awt.Color;24 import java.awt.Graphics2D;25 import java.awt.Image;26 import java.awt.Point;27 import java.awt.Polygon;28 import java.awt.Rectangle;29 import java.awt.Shape;30 import java.awt.Stroke;31 import java.awt.Toolkit;32 import java.awt.geom.AffineTransform;33 import java.awt.geom.Point2D;34 import java.awt.image.BufferedImage;35 import java.awt.image.CropImageFilter;36 import java.awt.image.FilteredImageSource;37 import java.awt.image.ImageObserver;38 import java.awt.image.PixelGrabber;39 21 import java.io.File; 40 22 import java.io.IOException; 41 23 import java.text.DecimalFormat; 42 43 import javax.imageio.ImageIO;44 import javax.swing.ImageIcon;45 24 46 25 import org.apache.commons.cli.CommandLine; … … 49 28 import org.apache.commons.cli.Options; 50 29 import org.apache.commons.cli.ParseException; 51 import org.expeditee.gui.DisplayIO; 30 import org.expeditee.core.Clip; 31 import org.expeditee.core.Colour; 32 import org.expeditee.core.Dimension; 33 import org.expeditee.core.EnforcedClipStack.EnforcedClipKey; 34 import org.expeditee.core.Image; 35 import org.expeditee.core.Point; 36 import org.expeditee.core.Stroke; 37 import org.expeditee.core.bounds.AxisAlignedBoxBounds; 38 import org.expeditee.core.bounds.CombinationBoxBounds; 39 import org.expeditee.core.bounds.PolygonBounds; 40 import org.expeditee.gio.EcosystemManager; 41 import org.expeditee.gio.GraphicsManager; 42 import org.expeditee.gui.DisplayController; 52 43 import org.expeditee.gui.FrameGraphics; 53 44 import org.expeditee.gui.FrameIO; 54 import org.expeditee.gui.FrameMouseActions;55 45 import org.expeditee.gui.FrameUtils; 56 import org.expeditee.items.widgets.InteractiveWidget;57 import org.expeditee.stats.Logger;58 46 59 47 /** … … 75 63 */ 76 64 public class Picture extends XRayable { 65 66 private static final float CROPPING_COMPOSITE_ALPHA = 0.5f; 77 67 78 68 private static final int MINIMUM_WIDTH = 10; … … 114 104 private String _fileName = null; 115 105 116 // used to repaint animated GIF images, among other things. 117 protected ImageObserver _imageObserver = null; 118 119 protected Picture(Text source, ImageObserver observer, Image image) { 106 protected Picture(Text source, Image image) { 120 107 super(source); 121 _imageObserver = observer;122 108 _image = image; 123 109 … … 150 136 * screen. 151 137 */ 152 public Picture(Text source, String fileName, String path, String size ,153 ImageObserver observer){138 public Picture(Text source, String fileName, String path, String size) 139 { 154 140 super(source); 155 _imageObserver = observer;156 141 _fileName = fileName; 157 142 _path = path; … … 226 211 227 212 // set the default values for start and end 228 _start.set Location(0, 0);213 _start.set(0, 0); 229 214 if (_image == null) 230 _end.set Location(0, 0);215 _end.set(0, 0); 231 216 else 232 _end.set Location(_image.getWidth(null), _image.getHeight(null));217 _end.set(_image.getWidth(), _image.getHeight()); 233 218 size = size.trim(); 234 219 String sizeLower = size.toLowerCase(); … … 272 257 try { 273 258 if (size.length() == 0) { 274 size = "" + _image.getWidth( null);259 size = "" + _image.getWidth(); 275 260 _source.setText(getTagText() + size); 276 261 return; … … 293 278 } 294 279 280 public void setStartCrop(Point p) 281 { 282 if (p != null) setStartCrop(p.x, p.y); 283 } 284 295 285 public void setStartCrop(int x, int y) { 296 286 invalidateCroppedArea(); 297 287 _cropStart = new Point(x - getX(), y - getY()); 298 288 invalidateCroppedArea(); 289 } 290 291 public void setEndCrop(Point p) 292 { 293 if (p != null) setEndCrop(p.x, p.y); 299 294 } 300 295 … … 312 307 int startY = getY() + topLeft.y - _highlightThickness; 313 308 int border = 2 * _highlightThickness; 314 invalidate(new Rectangle(startX, startY, bottomRight.x - topLeft.x 315 + 2 * border, bottomRight.y - topLeft.y + 2 * border)); 309 // TODO: Why invalidate specific area just before invalidateAll? cts16 310 invalidate(new AxisAlignedBoxBounds(startX, startY, 311 bottomRight.x - topLeft.x + 2 * border, bottomRight.y - topLeft.y + 2 * border)); 316 312 invalidateAll(); 317 313 } else { … … 325 321 } 326 322 327 public Point getBottomRightCrop() {328 return new Point(Math.max(_cropStart.x, _cropEnd.x), Math.max(329 323 public Point getBottomRightCrop() 324 { 325 return new Point(Math.max(_cropStart.x, _cropEnd.x), Math.max(_cropStart.y, _cropEnd.y)); 330 326 } 331 327 … … 335 331 invalidateCroppedArea(); 336 332 } 337 338 public boolean isCropTooSmall() { 339 if (_cropStart == null || _cropEnd == null) 340 return true; 333 334 public boolean isBeingCropped() 335 { 336 return (_cropStart != null && _cropEnd != null); 337 } 338 339 public boolean isCropTooSmall() 340 { 341 if (!isBeingCropped()) return true; 341 342 342 343 int cropWidth = Math.abs(_cropEnd.x - _cropStart.x); … … 353 354 } 354 355 355 public void updatePolygon() { 356 public PolygonBounds updateBounds() 357 { 356 358 if (_image == null) { 357 359 refresh(); … … 360 362 361 363 Point[] ori = new Point[4]; 362 Point2D[] rot = new Point2D[4];363 364 Point centre = new Point(); 364 365 … … 393 394 centre.y = base_y + (bottomRight.y - topLeft.y) / 2; 394 395 395 Rectangle clip = new Rectangle(topLeft.x + base_x,396 AxisAlignedBoxBounds clip = new AxisAlignedBoxBounds(topLeft.x + base_x, 396 397 topLeft.y + base_y, bottomRight.x - topLeft.x, 397 bottomRight.y - topLeft.y) .getBounds();398 bottomRight.y - topLeft.y); 398 399 // _poly.addPoint((int) clip.getMinX() - 1, (int) clip.getMinY() - 1); 399 400 // _poly.addPoint((int) clip.getMinX() - 1, (int) clip.getMaxY()); … … 408 409 } 409 410 410 AffineTransform.getRotateInstance(Math.PI * _rotate / 180, centre.x, centre.y).transform(ori, 0, rot, 0, 4); 411 412 _poly = new Polygon(); 413 for(Point2D p : rot) { 414 _poly.addPoint((int)p.getX(), (int)p.getY()); 415 } 411 PolygonBounds poly = new PolygonBounds(); 412 for (Point p : ori) { 413 poly.addPoint(p); 414 } 415 poly.rotate(Math.PI * _rotate / 180, centre); 416 417 return poly.close(); 416 418 } 417 419 … … 454 456 */ 455 457 @Override 456 protected void paintLink( Graphics2D g) {457 if (FrameGraphics.isAudienceMode())458 459 super.paintLink( g);460 } 461 462 public void paintImageTiling(Graphics2D g) {463 if (_image == null) {464 return;465 }466 467 i nt iw = _image.getWidth(null);468 int ih = _image.getHeight(null);469 i f(iw <= 0 || ih <= 0) {470 return;471 }472 473 int base_x = (_anchorLeft !=null) ? _anchorLeft : _source.getX();474 int base_y = (_anchorTop !=null) ? _anchorTop : _source.getY();458 protected void paintLink() 459 { 460 if (DisplayController.isAudienceMode()) return; 461 super.paintLink(); 462 } 463 464 /** 465 * Paint the image repeatedly tiled over the drawing area. 466 */ 467 public void paintImageTiling() 468 { 469 if (_image == null) return; 470 471 int iw = _image.getWidth(); 472 int ih = _image.getHeight(); 473 if(iw <= 0 || ih <= 0) return; 474 475 int base_x = (_anchorLeft != null) ? _anchorLeft : _source.getX(); 476 int base_y = (_anchorTop != null) ? _anchorTop : _source.getY(); 475 477 476 478 int dX1 = base_x; … … 479 481 int dY2 = base_y + getHeight(); 480 482 481 BufferedImage tmp = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); 482 Graphics2D g2d = tmp.createGraphics(); 483 Image tmp = Image.createImage(getWidth(), getHeight()); 484 EcosystemManager.getGraphicsManager().pushDrawingSurface(tmp); 485 483 486 int offX = (tmp.getWidth() - getWidth()) / 2; 484 487 int offY = (tmp.getHeight() - getHeight()) / 2; 485 486 // g2d.rotate(rotate, tmp.getWidth() / 2, tmp.getHeight() / 2);487 488 488 489 int cropStartX = _start.x; … … 491 492 cropEndX = iw; 492 493 } 494 493 495 for(int x = dX1; x < dX2; ) { 494 496 // end - start = (cropEnd - cropStart) * scale … … 506 508 cropEndY = ih; 507 509 } 510 508 511 for(int y = dY1; y < dY2; ) { 509 512 int h = (int) ((cropEndY - cropStartY) * _scale); … … 518 521 int sy = _flipY ? cropEndY : cropStartY; 519 522 int ey = _flipY ? cropStartY : cropEndY; 520 g2d.drawImage(_image, x - dX1 + offX, y - dY1 + offY, endX - dX1 + offX, endY - dY1 + offY, sx, sy, ex, ey, null); 523 524 Point topLeft = new Point(x - dX1 + offX, y - dY1 + offY); 525 Dimension size = new Dimension(endX - x, endY - y); 526 Point cropTopLeft = new Point(sx, sy); 527 Dimension cropSize = new Dimension(ex - sx, ey - sy); 528 if (cropSize.width > 0 && cropSize.height > 0) { 529 EcosystemManager.getGraphicsManager().drawImage(_image, topLeft, size, 0.0, cropTopLeft, cropSize); 530 } 521 531 522 532 cropStartY = 0; … … 531 541 x = endX; 532 542 } 533 534 AffineTransform at = new AffineTransform();535 at.translate(dX1, dY1);536 at.rotate(Math.PI * _rotate / 180, tmp.getWidth() / 2, tmp.getHeight() / 2);537 g.drawImage(tmp, at, _imageObserver);538 // g.drawImage(tmp, dX1, dY1, dX2, dY2, 0, 0, tmp.getWidth(), tmp.getHeight(), _imageObserver); 539 }540 541 @Override542 public void paint(Graphics2D g) {543 if (_image == null) 544 return;545 546 paintLink(g);547 548 // if we are showing the cropping , then show the original as transparent543 544 EcosystemManager.getGraphicsManager().popDrawingSurface(); 545 EcosystemManager.getGraphicsManager().drawImage(tmp, new Point(dX1, dY1), null, Math.PI * _rotate / 180); 546 tmp.releaseImage(); 547 } 548 549 @Override 550 public void paint() 551 { 552 if (_image == null) return; 553 554 paintLink(); 555 556 GraphicsManager g = EcosystemManager.getGraphicsManager(); 557 558 // if we are showing the cropping 549 559 if (_showCropping && !isCropTooSmall()) { 550 // show the full image as transparent 551 float alpha = .5f; 552 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 553 alpha)); 554 555 paintImageTiling(g); 556 557 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 558 1.0f)); 560 // show the uncropped area as transparent 561 g.setCompositeAlpha(CROPPING_COMPOSITE_ALPHA); 562 paintImageTiling(); 563 g.setCompositeAlpha(1.0f); 564 559 565 // show the cropped area normally 560 566 Point topLeft = getTopLeftCrop(); 561 567 Point bottomRight = getBottomRightCrop(); 562 int base_x = (_anchorLeft!=null) ? _anchorLeft : _source.getX(); 563 int base_y = (_anchorTop!=null) ? _anchorTop : _source.getY(); 564 565 Shape clip = new Rectangle(base_x + topLeft.x, base_y + topLeft.y, 566 bottomRight.x - topLeft.x, bottomRight.y - topLeft.y); 567 g.setColor(getPaintHighlightColor()); 568 g.draw(clip); 569 g.setClip(clip); 570 571 paintImageTiling(g); 572 573 g.draw(clip); 574 // if the image is cropped, but we are not showing the cropping 575 // otherwise, paint normally 568 int base_x = (_anchorLeft != null) ? _anchorLeft : _source.getX(); 569 int base_y = (_anchorTop != null) ? _anchorTop : _source.getY(); 570 571 Clip clip = new Clip(new AxisAlignedBoxBounds( base_x + topLeft.x, 572 base_y + topLeft.y, 573 bottomRight.x - topLeft.x, 574 bottomRight.y - topLeft.y)); 575 EnforcedClipKey key = g.pushClip(clip); 576 paintImageTiling(); 577 g.popClip(key); 578 579 // Draw an outline for the crop selection box 580 g.drawRectangle(clip.getBounds(), 0.0, null, getPaintHighlightColor(), HIGHLIGHT_STROKE, null); 581 582 // otherwise, paint normally 576 583 } else { 577 paintImageTiling(g); 578 } 579 584 paintImageTiling(); 585 } 586 587 PolygonBounds poly = (PolygonBounds) getBounds(); 588 580 589 if (hasVisibleBorder()) { 581 g.setColor(getPaintBorderColor()); 582 Stroke borderStroke = new BasicStroke(getThickness(), CAP, JOIN); 583 g.setStroke(borderStroke); 584 g.drawPolygon(getPolygon()); 590 Stroke borderStroke = new Stroke(getThickness(), DEFAULT_CAP, DEFAULT_JOIN); 591 g.drawPolygon(poly, null, null, 0.0, null, getPaintBorderColor(), borderStroke); 585 592 } 586 593 587 594 if (isHighlighted()) { 588 Stroke borderStroke = new BasicStroke(1, CAP, JOIN); 589 g.setStroke(borderStroke); 590 g.setColor(getHighlightColor()); 591 g.drawPolygon(getPolygon()); 592 } 593 594 //System.out.print("p_"); 595 } 596 597 @Override 598 public Color getHighlightColor() { 599 if (_highlightColor.equals(getBorderColor())) 600 return ALTERNATE_HIGHLIGHT; 601 return _highlightColor; 602 } 603 604 @Override 605 public int setHighlightColor() { 606 super.setHighlightColor(); 607 608 return Item.DEFAULT_CURSOR; 609 } 610 611 protected Picture createPicture() { 612 return ItemUtils.CreatePicture((Text) _source.copy(), _imageObserver); 595 Stroke borderStroke = new Stroke(1, DEFAULT_CAP, DEFAULT_JOIN); 596 g.drawPolygon(poly, null, null, 0.0, null, getHighlightColor(), borderStroke); 597 } 598 } 599 600 @Override 601 public Colour getHighlightColor() 602 { 603 if (_highlightColour.equals(getBorderColor())) return ALTERNATE_HIGHLIGHT; 604 return _highlightColour; 605 } 606 607 protected Picture createPicture() 608 { 609 return ItemUtils.CreatePicture((Text) _source.copy()); 613 610 } 614 611 … … 617 614 Picture p = createPicture(); 618 615 p._image = _image; 619 p._ mode = _mode;616 p._highlightMode = _highlightMode; 620 617 // Doing Duplicate item duplicates link mark which we dont want to do 621 618 // when in audience mode because the linkMark will be copied incorrectly … … 632 629 int endX = Math.round(bottomRight.x / _scale + _start.x); 633 630 int endY = Math.round(bottomRight.y / _scale + _start.y); 634 int width = _image.getWidth( null);635 int height = _image.getHeight( null);631 int width = _image.getWidth(); 632 int height = _image.getHeight(); 636 633 // adjust our start and end if the user has dragged outside of the 637 634 // shape … … 663 660 664 661 p.updateSource(); 665 p. updatePolygon();662 p.invalidateBounds(); 666 663 667 664 return p; … … 678 675 public void scaleCrop() { 679 676 // scale crop values to within image bounds 680 int iw = _image.getWidth( null);681 int ih = _image.getHeight( null);677 int iw = _image.getWidth(); 678 int ih = _image.getHeight(); 682 679 if(iw > 0 || ih > 0) { 683 680 while(_start.x >= iw) { … … 723 720 _scale = oldScale; 724 721 } else { 725 _source.translate(new Point2D.Float(FrameMouseActions.MouseX, 726 FrameMouseActions.MouseY), multiplier); 722 _source.translate(EcosystemManager.getInputManager().getCursorPosition(), multiplier); 727 723 } 728 724 updateSource(); 729 updatePolygon();725 invalidateBounds(); 730 726 // Make sure items that are resized display the border 731 727 invalidateAll(); … … 753 749 } 754 750 755 return Toolkit.getDefaultToolkit().createImage( 756 new FilteredImageSource(_image.getSource(), 757 new CropImageFilter(_start.x, _start.y, 758 getUnscaledWidth(), getUnscaledHeight()))); 751 return Image.createImageAsCroppedCopy(_image, _start.x, _start.y, getUnscaledWidth(), getUnscaledHeight()); 759 752 } 760 753 … … 771 764 */ 772 765 public boolean isCropped() { 773 return (_end.x != 0 && _end.x != _image.getWidth( null)) || (_end.y != 0 && _end.y != _image.getHeight(null)) || _start.y != 0 || _start.x != 0;766 return (_end.x != 0 && _end.x != _image.getWidth()) || (_end.y != 0 && _end.y != _image.getHeight()) || _start.y != 0 || _start.x != 0; 774 767 } 775 768 … … 779 772 // (notably.bmp) hence, we try this first, then if it fails we try 780 773 // ImageIO 774 /* 781 775 try { 782 776 _image = new ImageIcon(_path).getImage(); … … 785 779 786 780 // if ImageIcon failed to read the image 787 if (_image == null || _image.getWidth( null) <= 0) {781 if (_image == null || _image.getWidth() <= 0) { 788 782 try { 789 783 _image = ImageIO.read(new File(_path)); … … 795 789 } 796 790 } 791 */ 792 _image = Image.getImage(_path); 797 793 return true; 798 794 } … … 827 823 @Override 828 824 public boolean getLinkMark() { 829 return ! FrameGraphics.isAudienceMode() && _source.getLinkMark();825 return !DisplayController.isAudienceMode() && _source.getLinkMark(); 830 826 } 831 827 … … 892 888 // If the image is cropped add the position for the start and finish of 893 889 // the crop to the soure text 894 if (_start.x > 0 || _start.y > 0 || _end.x != _image.getWidth( null)895 || _end.y != _image.getHeight( null)) {890 if (_start.x > 0 || _start.y > 0 || _end.x != _image.getWidth() 891 || _end.y != _image.getHeight()) { 896 892 newText.append(" ").append(_start.x).append(" ").append(_start.y); 897 893 newText.append(" ").append(_end.x).append(" ").append(_end.y); … … 912 908 913 909 @Override 914 public void translate(Point 2Dorigin, double ratio) {910 public void translate(Point origin, double ratio) { 915 911 _scale *= ratio; 916 912 updateSource(); … … 919 915 920 916 @Override 921 public Rectangle[]getDrawingArea() {922 923 Rectangle[]da = super.getDrawingArea();917 public AxisAlignedBoxBounds getDrawingArea() { 918 919 AxisAlignedBoxBounds da = super.getDrawingArea(); 924 920 925 921 if (getLink() != null || hasAction()) { 926 Rectangle[] da2 = new Rectangle[da.length + 1]; 927 System.arraycopy(da, 0, da2, 0, da.length); 928 da2[da.length] = getLinkPoly().getBounds(); 929 da2[da.length].translate(getX() - LEFT_MARGIN, getY() 930 + getLinkYOffset()); 931 da2[da.length].width += 2; 932 da2[da.length].height += 2; 933 da = da2; 922 AxisAlignedBoxBounds linkBounds = AxisAlignedBoxBounds.getEnclosing(getLinkBounds()); 923 linkBounds.getTopLeft().add(getX() - LEFT_MARGIN, getY() + getLinkYOffset()); 924 linkBounds.getSize().width += 2; 925 linkBounds.getSize().height += 2; 926 da.combineWith(linkBounds); 934 927 } 935 928 … … 963 956 _rotate = rotate; 964 957 updateSource(); 965 updatePolygon();958 invalidateBounds(); 966 959 } 967 960 … … 970 963 } 971 964 972 public boolean MouseOverBackgroundPixel(int mouseX, int mouseY, Color bg_col) 973 { 974 int[] pixels = new int[1]; 975 965 public boolean MouseOverBackgroundPixel(int mouseX, int mouseY, Colour bg_col) 966 { 976 967 int base_x = (_anchorLeft!=null) ? _anchorLeft : _source.getX(); 977 968 int base_y = (_anchorTop!=null) ? _anchorTop : _source.getY(); … … 979 970 int y = mouseY - base_y; 980 971 981 // Consider making this a slightly larger area to check, say 3 x 3? 982 // Back op if all are the same sought after color? 983 PixelGrabber grabber = new PixelGrabber(_image, x,y, 1, 1, pixels, 0, 1); 984 985 // The following might be a better approach, as it sets the color model 986 // when getPixels() is called, however, it might return an int[] or byte[] 987 // array (handled as Object), as so some extra complexity would exist in 988 // handling the returned result 989 990 //PixelGrabber pg = new PixelGrabber(_image, mouseX, mouseY, 1, 1, true); 991 992 try { 993 grabber.grabPixels(0); 994 } 995 catch (Exception e) { 996 e.printStackTrace(); 997 } 998 999 1000 int c = pixels[0]; 1001 int c_red = (c & 0x00ff0000) >> 16; 1002 int c_green = (c & 0x0000ff00) >> 8; 1003 int c_blue = c & 0x000000ff; 1004 1005 int bg_red = (bg_col!=null) ? bg_col.getRed() : 0xff; 1006 int bg_green = (bg_col!=null) ? bg_col.getGreen() : 0xff; 1007 int bg_blue = (bg_col!=null) ? bg_col.getBlue() : 0xff; 972 Colour c = _image.getPixel(x, y); 973 974 int c_red = c.getRed255(); 975 int c_green = c.getGreen255(); 976 int c_blue = c.getBlue255(); 977 978 int bg_red = (bg_col!=null) ? bg_col.getRed255() : 0xff; 979 int bg_green = (bg_col!=null) ? bg_col.getGreen255() : 0xff; 980 int bg_blue = (bg_col!=null) ? bg_col.getBlue255() : 0xff; 1008 981 1009 982 int red_diff = Math.abs(c_red - bg_red);
Note:
See TracChangeset
for help on using the changeset viewer.