Warning: session_start(): open(/var/lib/php/sessions/sess_0p3c19qb9lhvo3b9jfuc0k30rc, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
sclass ImageSurface extends Surface {
BufferedImage image;
double zoomX = 1, zoomY = 1, zoomFactor = 1.5;
private Rectangle selection;
new L tools;
// use overlays now
O overlay; // voidfunc(Graphics2D)
L overlays = syncL();
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
bool autoZoomToDisplay; // only works 100% when not in scrollpane
settable bool repaintInThread; // after setImage, repaint in same thread
BoolVar showingVar;
Pt mousePosition;
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;
onResize(this, r { if (autoZoomToDisplay) zoomToDisplaySize(); });
componentPopupMenu2(this, ImageSurface_popupMenuMaker());
new ImageSurfaceSelector(this);
jHandleFileDrop(this, voidfunc(File f) { setImage(loadBufferedImage(f)) });
imageSurfaceOnHover(this, p -> mousePosition = p);
}
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);*/
menu.add(jCheckBoxMenuItem_dyn(/*"Auto-zoom to window"*/"Zoom to window",
-> autoZoomToDisplay,
b -> { setAutoZoomToDisplay(b); }));
addMenuItem(menu, "Show full screen", r { showFullScreen() });
addMenuItem(menu, "Point: " + point.x + "," + point.y + " (image: " + w() + "*" + h() + ")", 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);
}
}
}
void drawImageItself(int w, int h, Graphics2D g) {
int iw = getZoomedWidth(), ih = getZoomedHeight();
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
}
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 (!hasImage())
g.fillRect(0, 0, w, h);
else {
bool alpha = !noAlpha && hasTransparency(image);
if (alpha) g.fillRect(0, 0, w, h);
drawImageItself(w, h, g);
int iw = getZoomedWidth(), ih = getZoomedHeight();
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);
}
for (var overlay : cloneList(overlays)) pcall {
overlay.drawOn(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) {
autoZoomToDisplay = false;
setZoom_dontChangeAutoZoom(zoomX, zoomY);
}
public void setZoom_dontChangeAutoZoom(double zoomX, double zoomY default zoomX) {
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 scaffolded Dimension getMinimumSize() {
if (noMinimumSize) ret new Dimension(1, 1);
int w = getZoomedWidth();
int h = getZoomedHeight();
Dimension min = super.getMinimumSize();
ret printIfScaffoldingEnabled(this, new Dimension(Math.max(w, min.width), Math.max(h, min.height)));
}
int getZoomedHeight() {
return (int) (h() * zoomY);
}
int getZoomedWidth() {
return (int) (w() * zoomX);
}
bool isShowing_quick() {
if (showingVar == null) swing {
showingVar if null = componentShowingVar(ImageSurface.this);
}
ret showingVar!;
}
public void setImageIfShowing_thisThread(BufferedImage etc image) {
if (isShowing_quick())
setImage_thisThread(image);
}
public void setImage(MakesBufferedImage image) swing {
setImage_thisThread(image);
}
public void setImage(BufferedImage img) swing {
setImage_thisThread(img);
}
public void setImage_thisThread(BufferedImage etc img) {
BufferedImage newImage = img != null ? img : dummyImage();
BufferedImage oldImage = image;
image = newImage;
bool sameSize = !imagesHaveSameSize(oldImage, newImage);
if (!sameSize) {
if (verbose) _print("New image size");
revalidate(); // do we need this?
}
quickRepaint();
pcallF(onNewImage);
if (!sameSize && autoZoomToDisplay) zoomToDisplaySize();
}
void setImageAndZoomToDisplay(BufferedImage img) {
setImage(img);
zoomToDisplaySize();
}
public BufferedImage getImage() {
return image;
}
public double getZoomX() {
return zoomX;
}
public double getZoomY() {
return zoomY;
}
public scaffolded Dimension getPreferredSize() {
ret printIfScaffoldingEnabled(this, 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 (!hasImage()) return;
Dimension display = getDisplaySize();
int w = w(), h = h();
double xRatio = (display.width-5)/(double) w;
double yRatio = (display.height-5)/(double) h;
//if (scaffoldingEnabled(this))
ifdef ImageSurface_debug
printVars(+display, +w, +h, +xRatio, +yRatio);
endifdef
setZoom_dontChangeAutoZoom(min(xRatio, yRatio));
revalidate();
}
/** tricky magic to get parent scroll pane */
private scaffolded 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);
quickRepaint();
}
}
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; }
void setOverlay(IVF1 overlay) {
this.overlay = overlay;
}
bool hasImage() { ret image != null; }
int w() { ret image.getWidth(); }
int h() { ret image.getHeight(); }
void setPixelated(bool b) {
assertTrue(b);
imageSurface_pixelated(this);
}
selfType setAutoZoomToDisplay(bool b) {
if (autoZoomToDisplay = b)
zoomToDisplaySize();
this;
}
void quickRepaint() {
if (repaintInThread)
paintImmediately(0, 0, getWidth(), getHeight());
else
repaint();
}
} // end of ImageSurface
// static function allows garbage collection
static VF2 ImageSurface_popupMenuMaker() {
ret voidfunc(ImageSurface is, JPopupMenu menu) {
Point p = is.pointFromEvent(componentPopupMenu_mouseEvent.get()).getPoint();
is.fillPopupMenu(menu, p);
};
}