Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

365
LINES

< > BotCompany Repo | #1004553 - ImageSurface

JavaX fragment (include) [tags: use-pretranspiled]

Uses 108K of libraries. Click here for Pure Java version (9362L/68K).

lib 1400179 // thumbnailator
import net.coobird.thumbnailator.Thumbnailator;

static class ImageSurface extends Surface {
  BufferedImage image;
  double zoomX = 1, zoomY = 1, zoomFactor = 1.5;
  private Rectangle selection;
  new L tools;
  O overlay; // voidfunc(Graphics2D)
  Runnable onSelectionChange;
  static bool verbose;
  bool noMinimumSize = true;
  S titleForUpload;
  O onZoom;
  bool specialPurposed; // true = don't show image changing commands in popup menu
  bool zoomable = true;
  bool noAlpha; // set to true to speed up drawing if you don't use alpha
  O interpolationMode = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
  O onNewImage;
  BufferedImage imageToDraw; // if you want to draw a different image
  File file; // where image was loaded from
 
  public ImageSurface() {
    this(dummyImage());
  }
  
  static BufferedImage dummyImage() {
    ret new RGBImage(1, 1, new int[] { 0xFFFFFF }).getBufferedImage();
  }

  *(MakesBufferedImage image) {
    this(image != null ? image.getBufferedImage() : dummyImage());
  }
  
  *(BufferedImage image) {
    setImage(image);
    clearSurface = false;

    componentPopupMenu2(this, ImageSurface_popupMenuMaker());
    new ImageSurfaceSelector(this);
    
    jHandleFileDrop(this, voidfunc(File f) { setImage(loadBufferedImage(f)) });
  }

  public ImageSurface(RGBImage image, double zoom) {
    this(image);
    setZoom(zoom);
  }

  // point is already in image coordinates
  protected void fillPopupMenu(JPopupMenu menu, final Point point) {
    if (zoomable) {
      JMenuItem miZoomReset = new JMenuItem("Zoom 100%");
      miZoomReset.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
          setZoom(1.0);
          centerPoint(point);
        }
      });
      menu.add(miZoomReset);
  
      JMenuItem miZoomIn = new JMenuItem("Zoom in");
      miZoomIn.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
          zoomIn(zoomFactor);
          centerPoint(point);
        }
      });
      menu.add(miZoomIn);
  
      JMenuItem miZoomOut = new JMenuItem("Zoom out");
      miZoomOut.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
          zoomOut(zoomFactor);
          centerPoint(point);
        }
      });
      menu.add(miZoomOut);
  
      JMenuItem miZoomToWindow = new JMenuItem("Zoom to window");
      miZoomToWindow.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
          zoomToDisplaySize();
        }
      });
      menu.add(miZoomToWindow);
      addMenuItem(menu, "Show full screen", r { showFullScreen() });
      
      addMenuItem(menu, "Point: " + point.x + "," + point.y + " (image: " + image.getWidth() + "*" + image.getHeight() + ")", null);
  
      menu.addSeparator();
    }

    addMenuItem(menu, "Load image...", r { selectFile("Load image",
      voidfunc(File f) { setImage(loadImage2(f)) }) });
    addMenuItem(menu, "Save image...", r { saveImage() });
    addMenuItem(menu, "Upload image...", r { uploadTheImage() });
    addMenuItem(menu, "Copy image to clipboard", r { copyImageToClipboard(getImage()) });
    if (!specialPurposed) {
      addMenuItem(menu, "Paste image from clipboard", r { loadFromClipboard() });
      addMenuItem(menu, "Load image snippet...", r {
        selectImageSnippet(voidfunc(S imageID) {
          setImage(loadImage2(imageID))
        });
      });
    }
    if (selection != null)
      addMenuItem(menu, "Crop", r { crop() });
    if (!specialPurposed)
      addMenuItem(menu, "No image", r { noImage() });
  }
  
  void noImage() { setImage((BufferedImage) null); }
  
  void crop() {
    if (selection == null) ret;
    BufferedImage img = cloneClipBufferedImage(getImage(), selection);
    selection = null;
    setImage(img);
  }
  
  void loadFromClipboard() {
    BufferedImage img = getImageFromClipboard();
    if (img != null)
      setImage(img);
  }

  void saveImage() {
    RGBImage image = new RGBImage(getImage(), null);
    JFileChooser fileChooser = new JFileChooser(getProgramDir());
    if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
      try {
        image.save(file = fileChooser.getSelectedFile());
      } catch (IOException e) {
        popup(e);
      }
    }
  }

  public void render(int w, int h, Graphics2D g) {
    if (verbose) _print("render");
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolationMode);
    g.setColor(Color.white);
    BufferedImage image = or(imageToDraw, this.image);
    if (image == null)
      g.fillRect(0, 0, w, h);
    else {
      int iw = getZoomedWidth(), ih = getZoomedHeight();
      bool alpha = !noAlpha && hasTransparency(image);
      if (alpha) g.fillRect(0, 0, w, h);
      if (eq(interpolationMode, 'thumbnailator))
        g.drawImage(Thumbnailator.createThumbnail(image, iw, ih), 0, 0, null);
      else if (interpolationMode == RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR || zoomX >= 1 || zoomY >= 1)
        g.drawImage(image, 0, 0, iw, ih, null);
      else
        g.drawImage(resizeImage(image, iw, ih), 0, 0, null); // smoother
      
      if (!alpha) {
        g.fillRect(iw, 0, w-iw, h);
        g.fillRect(0, ih, iw, h-ih);
      }
    }

    if (overlay != null) {
      if (verbose) _print("render overlay");
      pcallF(overlay, g);
    }

    if (selection != null) {
      if (verbose) _print("render selection");
      // drawRect is inclusive, selection is exclusive, so... whatever, tests show it's cool.
      drawSelectionRect(g, selection, Color.green, Color.white);
    }
  }

  public void drawSelectionRect(Graphics2D g, Rectangle selection, Color green, Color white) {
    drawSelectionRect(g, selection, green, white, zoomX, zoomY);
  }
  
  public void drawSelectionRect(Graphics2D g, Rectangle selection, Color green, Color white, double zoomX, double zoomY) {
    g.setColor(green);
    int top = (int) (selection.y * zoomY);
    int bottom = (int) ((selection.y+selection.height) * zoomY);
    int left = (int) (selection.x * zoomX);
    int right = (int) ((selection.x+selection.width) * zoomX);
    g.drawRect(left-1, top-1, right-left+1, bottom-top+1);
    g.setColor(white);
    g.drawRect(left - 2, top - 2, right - left + 3, bottom - top + 3);
  }

  public ImageSurface setZoom(double zoom) {
    setZoom(zoom, zoom);
    this;
  }

  public void setZoom(double zoomX, double zoomY) {
    if (this.zoomX == zoomX && this.zoomY == zoomY) ret;
    if (verbose) _print("Setting zoom");
    this.zoomX = zoomX;
    this.zoomY = zoomY;
    revalidate();
    repaint();
    centerPoint(new Point(getImage().getWidth()/2, getImage().getHeight()/2));

    pcallF(onZoom);
  }

  public Dimension getMinimumSize() {
    if (noMinimumSize) ret new Dimension(1, 1);
    int w = getZoomedWidth();
    int h = getZoomedHeight();
    Dimension min = super.getMinimumSize();
    return new Dimension(Math.max(w, min.width), Math.max(h, min.height));
  }

  private int getZoomedHeight() {
    return (int) (image.getHeight() * zoomY);
  }

  private int getZoomedWidth() {
    return (int) (image.getWidth() * zoomX);
  }

  public void setImage(MakesBufferedImage image) {
    setImage(image == null ? null : image.getBufferedImage());
  }
  
  public void setImage(final BufferedImage img) {
    swing {
      BufferedImage newImage = img != null ? img : dummyImage();
      BufferedImage oldImage = image;
      image = newImage;
      if (!imagesHaveSameSize(oldImage, newImage)) {
        if (verbose) _print("New image size");
        revalidate(); // do we need this?
      }
      repaint();
      pcallF(onNewImage);
    }
  }
  
  void setImageAndZoomToDisplay(BufferedImage img) {
    setImage(img);
    zoomToDisplaySize();
  }

  public BufferedImage getImage() {
    return image;
  }

  public double getZoomX() {
    return zoomX;
  }

  public double getZoomY() {
    return zoomY;
  }

  public Dimension getPreferredSize() {
    return new Dimension(getZoomedWidth(), getZoomedHeight());
  }

  /** returns a scrollpane with the scroll-mode prevent-garbage-drawing fix applied */
  public JScrollPane makeScrollPane() {
    JScrollPane scrollPane = new JScrollPane(this);
    scrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
    return scrollPane;
  }

  public void zoomToWindow() { zoomToDisplaySize(); }
  public void zoomToDisplaySize() swing {
    if (image == null) return;
    Dimension display = getDisplaySize();
    double xRatio = (display.width-5)/(double) image.getWidth();
    double yRatio = (display.height-5)/(double) image.getHeight();
    setZoom(min(xRatio, yRatio));
    revalidate();
  }

  /** tricky magic to get parent scroll pane */
  private Dimension getDisplaySize() {
    Container c = getParent();
    while (c != null) {
      if (c instanceof JScrollPane)
        return c.getSize();
      c = c.getParent();
    }
    return getSize();
  }
  
  public void setSelection(Rect r) {
    setSelection(toRectangle(r));
  }

  public void setSelection(Rectangle r) {
    if (neq(selection, r)) {
      selection = r;
      pcallF(onSelectionChange);
      repaint();
    }
  }

  public Rectangle getSelection() {
    return selection;
  }

  public RGBImage getRGBImage() {
    return new RGBImage(getImage());
  }
  
  // p is in image coordinates
  void centerPoint(Point p) {
    JScrollPane sp = enclosingScrollPane(this);
    if (sp == null) ret;
      
    p = new Point((int) (p.x*getZoomX()), (int) (p.y*getZoomY()));
    final JViewport viewport = sp.getViewport();
    Dimension viewSize = viewport.getExtentSize();
    
    //_print("centerPoint " + p);
    int x = max(0, p.x-viewSize.width/2);
    int y = max(0, p.y-viewSize.height/2);
    
    //_print("centerPoint " + p + " => " + x + "/" + y);
    p = new Point(x,y);
    //_print("centerPoint " + p);
    final Point _p = p;
    awtLater(r {
      viewport.setViewPosition(_p);
    });
  }
  
  Pt pointFromEvent(MouseEvent e) {
    ret pointFromComponentCoordinates(new Pt(e.getX(), e.getY()));
  }
  
  Pt pointFromComponentCoordinates(Pt p) {
    ret new Pt((int) (p.x/zoomX), (int) (p.y/zoomY));
  }
  
  Pt pointToComponentCoordinates(double x, double y) {
    ret new Pt((int) (x*zoomX), (int) (y*zoomY));
  }
  
  void uploadTheImage {
    call(hotwire(/*#1007313*/#1016427), "go", getImage(), titleForUpload);
  }
  
  void showFullScreen() {
    showFullScreenImageSurface(getImage());
  }
  
  void zoomIn(double f) { setZoom(getZoomX()*f, getZoomY()*f); }
  void zoomOut(double f) { setZoom(getZoomX()/f, getZoomY()/f); }
  
  selfType setFile(File f) { file = f; this; }
}

// static function allows garbage collection 
static VF2<ImageSurface, JPopupMenu> ImageSurface_popupMenuMaker() {
  ret voidfunc(ImageSurface is, JPopupMenu menu) {
    Point p = is.pointFromEvent(componentPopupMenu_mouseEvent.get()).getPoint();
    is.fillPopupMenu(menu, p);
  };
}

download  show line numbers  debug dex   

Travelled to 18 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, ddnzoavkxhuk, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, jtubtzbbkimh, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, ppjhyzlbdabe, pzhvpgtvlbxg, sawdedvomwva, tslmcundralx, tvejysmllsmz, xrpafgyirdlv

No comments. add comment

Snippet ID: #1004553
Snippet name: ImageSurface
Eternal ID of this version: #1004553/77
Text MD5: 2cfc036adbf67d9ca0da4c7f6fb49378
Transpilation MD5: 37fed7cb17ba0622ba250e1eddca51c0
Author: stefan
Category: javax / gui
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2020-02-29 13:58:20
Source code size: 11370 bytes / 365 lines
Pitched / IR pitched: No / No
Views / Downloads: 775 / 6126
Version history: 76 change(s)
Referenced in: [show references]

Formerly at http://tinybrain.de/1004553 & http://1004553.tinybrain.de