package com.aelitis.azureus.ui.swt.utils; import org.eclipse.swt.SWT; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.*; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.*; import org.gudy.azureus2.core3.internat.MessageText; import org.gudy.azureus2.core3.util.AEThread; import org.gudy.azureus2.core3.util.SystemTime; import org.gudy.azureus2.ui.swt.Utils; import org.gudy.azureus2.ui.swt.components.shell.ShellFactory; public class ImageResizer { static private final int RESIZE_STEPS = 100000; static private final int MARGIN = 20; private int minWidth, minHeight; private int displayWidth, displayHeight; private Display display; private Shell parent; private Shell shell; private Cursor cursor; private Canvas canvas; private Scale scale; private long lastUpdate = 0l; private Image original; private int originalWidth, originalHeight; private Image currentImage; private Image overlay; private Image overlayDragging; private Image overlayNotDragging; private boolean done; private Image result; private float zoomRatio; private float minZoomRatio; private float maxZoomRatio; private Point offset; private Listener moveImageListener = new Listener() { private boolean mouseDown = false; private Point pointDown; public void handleEvent(Event event) { //System.out.println(event); switch (event.type) { case SWT.MouseDown: mouseDown = true; pointDown = new Point(event.x, event.y); overlay = overlayDragging; drawCurrentImage(); break; case SWT.MouseUp: mouseDown = false; overlay = overlayNotDragging; drawCurrentImage(); break; case SWT.MouseMove: if (!mouseDown) { break; } offset.x = offset.x + event.x - pointDown.x; offset.y = offset.y + event.y - pointDown.y; insureOffsetIsCorrect(); pointDown.x = event.x; pointDown.y = event.y; drawCurrentImage(); break; case SWT.MouseEnter: break; case SWT.MouseExit: break; } } }; private ImageResizerListener imageResizerListener; public ImageResizer(Display display, int width, int height, Shell parent) { this.parent = parent; this.display = display; this.minWidth = width; this.minHeight = height; } public void resize(Image original, ImageResizerListener l) throws ImageResizeException { this.original = original; this.imageResizerListener = l; //If the image is too small, let's just not deal with it if (!checkSize(original)) { dispose(); throw new ImageResizeException(MessageText.getString( "ImageResizer.image.too.small", new String[] { minWidth + "", minHeight + "" })); } originalWidth = original.getBounds().width; originalHeight = original.getBounds().height; currentImage = new Image(display, internalResize(original, (int) (originalWidth * zoomRatio), (int) (originalHeight * zoomRatio))); offset = new Point(0, 0); if (minWidth != original.getBounds().width || minHeight != original.getBounds().height) { displayWidth = minWidth + 2 * (MARGIN + 1); displayHeight = minHeight + 2 * (MARGIN + 1); overlay = overlayNotDragging = createOverlayImage((byte) 255, 0x00FFFFFF, (byte) 255, 0x00000000); overlayDragging = createOverlayImage((byte) 80, 0x00FFFFFF, (byte) 255, 0x00FFFFFF); initUI(); done = false; } else { result = computeResultImage(); l.imageResized(result); } } private void initUI() { cursor = new Cursor(display, SWT.CURSOR_HAND); if (parent != null) { shell = ShellFactory.createShell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL); } else { shell = ShellFactory.createMainShell(SWT.CLOSE | SWT.BORDER); } shell.setText("Thumbnail Assistant"); Utils.setShellIcon(shell); shell.addListener(SWT.Close, new Listener() { public void handleEvent(Event event) { event.doit = false; result = null; done = true; shell = null; dispose(); imageResizerListener.imageResized(result); } }); FormLayout layout = new FormLayout(); layout.marginBottom = 5; layout.marginTop = 5; layout.marginLeft = 5; layout.marginRight = 5; FormData data; shell.setLayout(layout); Label title = new Label(shell, SWT.WRAP); title.setText(MessageText.getString("ImageResizer.title")); data = new FormData(); data.width = displayWidth; title.setLayoutData(data); canvas = new Canvas(shell, SWT.BORDER); canvas.setCursor(cursor); data = new FormData(); data.width = displayWidth; data.height = displayHeight; data.top = new FormAttachment(title, 5); canvas.setLayoutData(data); canvas.addListener(SWT.MouseDown, moveImageListener); canvas.addListener(SWT.MouseUp, moveImageListener); canvas.addListener(SWT.MouseMove, moveImageListener); canvas.addPaintListener(new PaintListener() { public void paintControl(PaintEvent arg0) { drawCurrentImage(); } }); offset.x = (minWidth - currentImage.getBounds().width) / 2; offset.y = (minHeight - currentImage.getBounds().height) / 2; Label label = new Label(shell, SWT.WRAP); //The label text depends on the presence of the scale, //Thefore we delay the size computation as well as //Assiging any FormData (layout) to it see (1) //The Control to witch the Buttons OK and Cancel are going to be attached //Depends on the presence of the scale Control attach = label; if (minZoomRatio < 1) { scale = new Scale(shell, SWT.HORIZONTAL); data = new FormData(); data.width = displayWidth; data.top = new FormAttachment(label, 5); scale.setLayoutData(data); scale.setMaximum((int) (RESIZE_STEPS * maxZoomRatio)); scale.setMinimum((int) (RESIZE_STEPS * minZoomRatio)); scale.setIncrement((int) ((maxZoomRatio - minZoomRatio) * RESIZE_STEPS / 10)); scale.setPageIncrement((int) ((maxZoomRatio - minZoomRatio) * RESIZE_STEPS / 10)); scale.addListener(SWT.Selection, new Listener() { public void handleEvent(Event arg0) { final long timestamp = SystemTime.getCurrentTime(); lastUpdate = timestamp; final int position = scale.getSelection(); AEThread t = new AEThread("") { public void runSupport() { try { Thread.sleep(150); } catch (Exception e) { e.printStackTrace(); } if (timestamp == lastUpdate) { if (display != null && !display.isDisposed()) { display.asyncExec(new Runnable() { public void run() { refreshCurrentImage(position); } }); } } } }; t.setDaemon(true); t.start(); } }); attach = scale; label.setText(MessageText.getString("ImageResizer.move.image.with.slider")); } else { label.setText(MessageText.getString("ImageResizer.move.image")); } // (1) Layout of the label, depending on the text in it int width = label.computeSize(SWT.DEFAULT, SWT.DEFAULT).x; if (width > displayWidth) { width = displayWidth; } data = new FormData(); data.width = width; data.top = new FormAttachment(canvas, 5); data.left = new FormAttachment(canvas, 0, SWT.CENTER); label.setLayoutData(data); Button btnCancel = new Button(shell, SWT.PUSH); btnCancel.setText("Cancel"); data = new FormData(); data.width = 70; data.top = new FormAttachment(attach, 10); data.right = new FormAttachment(100, -10); btnCancel.setLayoutData(data); btnCancel.addListener(SWT.Selection, new Listener() { public void handleEvent(Event arg0) { result = null; done = true; dispose(); imageResizerListener.imageResized(result); } }); Button btnOk = new Button(shell, SWT.PUSH); btnOk.setText("OK"); data = new FormData(); data.width = 70; data.top = new FormAttachment(attach, 10); data.right = new FormAttachment(btnCancel, -10); btnOk.setLayoutData(data); btnOk.addListener(SWT.Selection, new Listener() { public void handleEvent(Event arg0) { result = computeResultImage(); done = true; dispose(); imageResizerListener.imageResized(result); } }); shell.setDefaultButton(btnOk); btnOk.setFocus(); shell.setSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); if (parent != null) { Utils.centerWindowRelativeTo(shell, parent); } shell.open(); drawCurrentImage(); } private boolean checkSize(Image image) { //If the image is smaller than the minimal size, we shouldn't accept it Rectangle size = image.getBounds(); if (size.width < minWidth || size.height < minHeight) { return false; } float minHRatio = (float) (minHeight) / size.height; float minWRatio = (float) (minWidth) / size.width; float maxHRatio = (float) (minHeight * 4) / size.height; float maxWRatio = (float) (minWidth * 4) / size.width; //We must keep the min zoom bigger than the "biggest" ratio (ie, smallest zoom out) minZoomRatio = minHRatio > minWRatio ? minHRatio : minWRatio; maxZoomRatio = maxHRatio > maxWRatio ? maxHRatio : maxWRatio; if (maxZoomRatio > 1) { maxZoomRatio = 1; } zoomRatio = minZoomRatio; return true; } private ImageData internalResize(Image image, int newWidth, int newHeight) { ImageData srcData = image.getImageData(); //int width = srcData.width,height = srcData.height; ImageData data = srcData; //int newWidth = (int)(width*zoomRatio); //int newHeight = (int)(height*zoomRatio); final ImageData copy = new ImageData(newWidth, newHeight, 24, new PaletteData(0x00FF0000, 0x0000FF00, 0x000000FF)); Image src = new Image(display, srcData); Image dst = new Image(display, copy); GC gc = new GC(dst); gc.setAdvanced(true); try { gc.setInterpolation(SWT.HIGH); } catch (Exception e) { // may not be avail } gc.drawImage(src, 0, 0, srcData.width, srcData.height, 0, 0, copy.width, copy.height); //gc.setAlpha(50); //gc.drawImage(src,2,2,srcData.width-2,srcData.height-2,0,0,copy.width,copy.height); gc.dispose(); data = dst.getImageData(); src.dispose(); dst.dispose(); return data; } private void drawCurrentImage() { GC gcCanvas = new GC(canvas); Image temp = new Image(display, displayWidth, displayHeight); GC gc = new GC(temp); gc.drawImage(currentImage, offset.x + MARGIN + 1, offset.y + MARGIN + 1); //gc.setAlpha(128); gc.drawImage(overlay, 0, 0); //gc.setTextAntialias(SWT.ON); //gc.drawText("This is a test", 15, displayHeight-15,true); gc.dispose(); gcCanvas.drawImage(temp, 0, 0); temp.dispose(); gcCanvas.dispose(); } private void insureOffsetIsCorrect() { int minX = minWidth - currentImage.getBounds().width; if (offset.x < minX) { offset.x = minX; } int minY = minHeight - currentImage.getBounds().height; if (offset.y < minY) { offset.y = minY; } if (offset.x > 0) { offset.x = 0; } if (offset.y > 0) { offset.y = 0; } } private void dispose() { if (shell != null && !shell.isDisposed()) { shell.dispose(); } if (currentImage != null && !currentImage.isDisposed()) { currentImage.dispose(); } if (overlayDragging != null && !overlayDragging.isDisposed()) { overlayDragging.dispose(); } if (overlayNotDragging != null && !overlayNotDragging.isDisposed()) { overlayNotDragging.dispose(); } if (cursor != null && !cursor.isDisposed()) { cursor.dispose(); } } private Image computeResultImage() { Image img = new Image(display, minWidth, minHeight); /*ImageData srcData = original.getImageData(); ImageData dstData = new ImageData( currentImage.getBounds().width, currentImage.getBounds().height, 32, new PaletteData(0xFF,0xFF00,0xFF0000)); Resample resample = new Resample(); resample.setFilter(Resample.FILTER_TYPE_LANCZOS3, 7.0f); resample.process(srcData, dstData); Image filtered = new Image(display,dstData); */ GC gc = new GC(img); gc.drawImage(currentImage, offset.x, offset.y); gc.dispose(); //filtered.dispose(); return img; } private Image createOverlayImage(final byte marginAlpha, final int marginColor, final byte borderAlpha, final int borderColor) { int width = displayWidth; int height = displayHeight; ImageData data = new ImageData(width, height, 32, new PaletteData( 0x000000FF, 0x0000FF00, 0x00FF0000)); byte[] transparency = new byte[width * height]; int[] pixels = new int[width * height]; byte rowAlpha[] = new byte[width]; int rowPixels[] = new int[width]; //Top //Pattern for (int i = 0; i < width; i++) { rowAlpha[i] = marginAlpha; rowPixels[i] = marginColor; } //Fill for (int i = 0; i < MARGIN; i++) { System.arraycopy(rowAlpha, 0, transparency, i * width, width); System.arraycopy(rowPixels, 0, pixels, i * width, width); } //Main area //Pattern for (int i = 0; i < MARGIN; i++) { rowAlpha[i] = marginAlpha; rowAlpha[width - i - 1] = marginAlpha; } for (int i = MARGIN; i < width - MARGIN; i++) { rowAlpha[i] = 0; } //Fill for (int i = MARGIN; i < height - MARGIN; i++) { System.arraycopy(rowAlpha, 0, transparency, i * width, width); System.arraycopy(rowPixels, 0, pixels, i * width, width); } //Bottom //Pattern for (int i = 0; i < width; i++) { rowAlpha[i] = marginAlpha; } //Fill for (int i = height - MARGIN - 1; i < height; i++) { System.arraycopy(rowAlpha, 0, transparency, i * width, width); System.arraycopy(rowPixels, 0, pixels, i * width, width); } //Let's do the border part for (int i = MARGIN; i < width - MARGIN; i++) { transparency[width * MARGIN + i] = borderAlpha; pixels[width * MARGIN + i] = borderColor; } for (int j = MARGIN; j < height - MARGIN; j++) { transparency[j * width + MARGIN] = borderAlpha; pixels[j * width + MARGIN] = borderColor; transparency[j * width + width - MARGIN - 1] = borderAlpha; pixels[j * width + width - MARGIN - 1] = borderColor; } for (int i = MARGIN; i < width - MARGIN; i++) { transparency[width * (height - MARGIN - 1) + i] = borderAlpha; pixels[width * (height - MARGIN - 1) + i] = borderColor; } data.alphaData = transparency; data.setPixels(0, 0, width * height, pixels, 0); Image overlay = new Image(display, data); return overlay; } private void refreshCurrentImage(int position) { float previousZoom = zoomRatio; zoomRatio = (float) position / RESIZE_STEPS; if (zoomRatio > 1) { zoomRatio = 1; } if (zoomRatio < minZoomRatio) { zoomRatio = minZoomRatio; } if (previousZoom != zoomRatio) { Image previous = currentImage; currentImage = new Image(display, internalResize(original, (int) (originalWidth * zoomRatio), (int) (originalHeight * zoomRatio))); //float ratio = zoomRatio / previousZoom; offset.x += (previous.getBounds().width - currentImage.getBounds().width) / 2; offset.y += (previous.getBounds().height - currentImage.getBounds().height) / 2; if (previous != null && !previous.isDisposed()) { previous.dispose(); } insureOffsetIsCorrect(); drawCurrentImage(); } } public interface ImageResizerListener { void imageResized(Image image); } public static void main(final String args[]) throws Exception { final Display display = Display.getDefault(); final Shell test = new Shell(display); ImageResizer resizer = new ImageResizer(display, 228, 128, null); String file = new FileDialog(test).open(); Image img = new Image(display, file); resizer.resize(img, new ImageResizerListener() { public void imageResized(Image thumbnail) { System.out.println(thumbnail); thumbnail.dispose(); test.dispose(); if (args.length == 0) { display.dispose(); } } }); } }