/*
* Copyright (c) 2012 Diamond Light Source Ltd.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.dawnsci.remotedataset.test.mock;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.filechooser.FileSystemView;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.dawnsci.analysis.api.downsample.DownsampleMode;
import org.eclipse.dawnsci.analysis.dataset.function.Downsample;
import org.eclipse.dawnsci.plotting.api.IPlottingSystem;
import org.eclipse.dawnsci.plotting.api.PlotType;
import org.eclipse.dawnsci.plotting.api.PlottingFactory;
import org.eclipse.dawnsci.plotting.api.histogram.IImageService;
import org.eclipse.dawnsci.plotting.api.histogram.ImageServiceBean;
import org.eclipse.dawnsci.plotting.api.histogram.ImageServiceBean.ImageOrigin;
import org.eclipse.dawnsci.plotting.api.image.IFileIconService;
import org.eclipse.dawnsci.plotting.api.image.IPlotImageService;
import org.eclipse.dawnsci.plotting.api.image.PlotImageData;
import org.eclipse.dawnsci.plotting.api.image.PlotImageData.PlotImageType;
import org.eclipse.dawnsci.plotting.api.preferences.PlottingConstants;
import org.eclipse.dawnsci.plotting.api.trace.ISurfaceTrace;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.DatasetFactory;
import org.eclipse.january.dataset.DatasetUtils;
import org.eclipse.january.dataset.DoubleDataset;
import org.eclipse.january.dataset.IDataset;
import org.eclipse.january.dataset.RGBDataset;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
import org.eclipse.ui.services.AbstractServiceFactory;
import org.eclipse.ui.services.IDisposable;
import org.eclipse.ui.services.IServiceLocator;
/**
* A service to provide SWT Image objects for 2D data.
* @author Matthew Gerring
*
*/
public class PlotImageServiceMock extends AbstractServiceFactory implements IPlotImageService {
static {
System.out.println("Starting PlotImageService");
}
public PlotImageServiceMock() {
}
private static float minimumThreshold = 0.98f;
private static int colourMapChoice = 1;
private static ImageRegistry imageRegistry;
@Override
public Image createImage(final File f, final int width, int height) {
if (f.isDirectory()) {
final Image blank = new Image(Display.getDefault(), width, height);
return blank;
}
try {
final Dataset thumb = getThumbnail(f, width, height);
return createImageSWT(thumb, null);
} catch (Throwable ne) {
if (imageRegistry == null) imageRegistry = new ImageRegistry(Display.getDefault());
final String extension = FileUtils.getFileExtension(f);
Image image = imageRegistry.get(extension);
if (image != null) return image;
Program program = Program.findProgram(extension);
ImageData imageData = (program == null ? null : program.getImageData());
if (imageData != null) {
image = new Image(Display.getDefault(), imageData);
imageRegistry.put(extension, image);
return image;
}
}
final Image image = PlatformUI.getWorkbench().getEditorRegistry().getImageDescriptor(f.getAbsolutePath()).createImage();
final Image blank = new Image(Display.getDefault(), width, height);
GC gc = new GC(blank);
gc.drawImage(image, (width/2)-image.getImageData().width/2, height/2-image.getImageData().height/2);
gc.dispose();
return blank;
}
private Dataset getThumbnail(final File f, final int width, final int height) throws Throwable {
return DatasetFactory.zeros(DoubleDataset.class, height, width);
}
public Dataset getThumbnail(final IDataset ds, final int w, final int h) {
if (ds!=null && ds.getRank() == 2) { // 2D datasets only!!!
int width = ds.getShape()[1];
int height = ds.getShape()[0];
int[] stepping = new int[2];
stepping[1] = Math.max(1, width / w);
stepping[0] = Math.max(1, height / h);
Downsample down = new Downsample(DownsampleMode.POINT, stepping);
Dataset ds_downsampled = DatasetUtils.convertToDataset(down.value(ds).get(0));
ds_downsampled.setName(ds.getName());
return ds_downsampled;
}
return null;
}
/**
* Modified from fable
* @param thumbnail
* @return
* @throws Exception
*/
public Image createImageSWT(final IDataset thumbnail, ImageServiceBean bean) throws Exception {
final ScopedPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, "org.dawnsci.plotting");
if (bean==null) {
bean = new ImageServiceBean();
bean.setPalette(ImageServiceMock.makeJetPalette());
bean.setOrigin(ImageOrigin.forLabel(store.getString(PlottingConstants.ORIGIN_PREF)));
}
bean.setImage(thumbnail);
final IImageService service = new ImageServiceMock();
return service.getImage(bean);
}
@Override
public Object create(Class serviceInterface, IServiceLocator parentLocator,
IServiceLocator locator) {
if (serviceInterface==IPlotImageService.class) {
return new PlotImageServiceMock();
} else if (serviceInterface==IFileIconService.class) {
return new PlotImageServiceMock();
}
return null;
}
private Image createImage(IDataset thumb, ImageServiceBean bean) throws Exception {
return createImageSWT(thumb, bean);
}
@Override
public Image getImage(final PlotImageData data) throws Exception {
final IDataset set = data.getData();
final int width = data.getWidth();
final int height = data.getHeight();
if (set.getShape().length==2 && data.getType()==PlotImageType.IMAGE_ONLY) {
final Dataset thumb = getThumbnail(set, width, height);
if (thumb==null) return null;
return createImage(thumb, (ImageServiceBean)data.getImageServiceBean());
} else {
PlotDisposable pd = (PlotDisposable)data.getDisposable();
if (pd == null) pd = (PlotDisposable)createPlotDisposable(null);
final PlotDisposable plotDisposable = pd;
final IPlottingSystem<?> system = pd.getSystem();
final Image[] scaled = new Image[1];
final Shell shell = plotDisposable.getShell();
final Display display = shell!=null ? shell.getDisplay() : Display.getDefault();
display.syncExec(new Runnable() {
public void run() {
if (shell!=null) shell.setSize(width+20, height+20);
if (set.getShape().length==1) {
system.updatePlot1D(null, Arrays.asList(set), new NullProgressMonitor());
} else if (data.getType()==PlotImageType.IMAGE_PLOT) {
system.setPlotType(PlotType.IMAGE);
system.updatePlot2D(set, null, new NullProgressMonitor());
} else if (data.getType()==PlotImageType.SURFACE_PLOT) {
final ISurfaceTrace trace = (ISurfaceTrace)system.getTraces(ISurfaceTrace.class).iterator().next();
// Keep z constant
List<? extends IDataset> oaxes = trace.getAxes();
List<IDataset> axes = new ArrayList<IDataset>(3);
if (oaxes==null) {
axes.add(DatasetFactory.createRange(set.getShape()[1], Dataset.INT));
axes.add(DatasetFactory.createRange(set.getShape()[0], Dataset.INT));
} else {
axes.add(oaxes.get(0));
axes.add(oaxes.get(1));
}
// z only gets larger
double zLow = Math.min(data.getzLower(), set.min().doubleValue());
double zUp = Math.max(data.getzUpper(), set.max().doubleValue());
IDataset z = DatasetFactory.createRange(zLow, zUp, (zUp-zLow)/1000, Dataset.FLOAT);
axes.add(z);
trace.setData(data.getData(), axes);
}
if (data.getPlotTitle()!=null) system.setTitle(data.getPlotTitle());
system.repaint(true);
// We try to make the axes only grow if they are caching plotting because
// it stops the video being shakey.
if (data.getDisposable()!=null && data.isConstantRange() && data.getType()!=PlotImageType.SURFACE_PLOT){
double yLow = Math.min(data.getyLower(), system.getSelectedYAxis().getLower());
double yUp = Math.max(data.getyUpper(), system.getSelectedYAxis().getUpper());
data.setyLower(yLow);
data.setyUpper(yUp);
double xLow = Math.min(data.getxLower(), system.getSelectedXAxis().getLower());
double xUp = Math.max(data.getxUpper(), system.getSelectedXAxis().getUpper());
data.setxLower(xLow);
data.setxUpper(xUp);
system.getSelectedYAxis().setRange(yLow, yUp);
system.getSelectedXAxis().setRange(xLow, xUp);
}
if (width>=300) {
scaled[0] = new Image(null, width, height);
} else { // They wanted an icon
final Image unscaled = new Image(null, 300, 300);
scaled[0] = new Image(display, unscaled.getImageData().scaledTo(width, height));
}
// They are inefficiently make a new plot part each time.
if (data.getDisposable()==null) plotDisposable.dispose();
}
});
return scaled[0];
}
}
@Override
public IDisposable createPlotDisposable(String plotName) throws Exception {
// We plot to an offscreen plotting system, then take a screen shot of this.
final PlotDisposable ret = new PlotDisposable();
IPlottingSystem<?> system = plotName!=null
? PlottingFactory.getPlottingSystem(plotName)
: PlottingFactory.getLightWeightPlottingSystem();
if (system==null) system = PlottingFactory.getLightWeightPlottingSystem();
ret.setSystem(system);
if (system.getPlotComposite()==null) {
Display.getDefault().syncExec(new Runnable() {
public void run() {
final Shell shell = new Shell(Display.getDefault(), SWT.RESIZE|SWT.NO_TRIM);
ret.setShell(shell);
shell.setSize(600, 600);
shell.setLayout(new FillLayout());
final Composite main = new Composite(shell, SWT.NONE);
main.setLayout(new GridLayout(1, false));
final Composite plotter = new Composite(main, SWT.NONE);
plotter.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
ret.getSystem().createPlotPart(plotter, "Thumbnail", null, PlotType.XY, null);
}
});
}
return ret;
}
protected static class PlotDisposable implements IDisposable {
private IPlottingSystem<?> system;
private Shell shell;
@Override
public void dispose() {
Display.getDefault().syncExec(new Runnable() {
public void run() {
if (system!=null) system.dispose();
if (shell!=null) shell.dispose();
}
});
}
public <T> IPlottingSystem<T> getSystem() {
return (IPlottingSystem<T>)system;
}
public <T> void setSystem(IPlottingSystem<T> system) {
this.system = system;
}
public Shell getShell() {
return shell;
}
public void setShell(Shell shell) {
this.shell = shell;
}
}
public Image getIconForFile(final File file) {
if (file.isDirectory()) {
return getFolderImage(file);
}
final String ext = FileUtils.getFileExtension(file);
if (imageRegistry == null)
imageRegistry = new ImageRegistry();
Image returnImage = imageRegistry.get(ext);
if (returnImage != null)
return returnImage;
// Eclipse icon
ECLISPE_BLOCK: if (returnImage == null) {
final IEditorDescriptor desc = PlatformUI.getWorkbench()
.getEditorRegistry()
.getDefaultEditor(file.getAbsolutePath());
if (desc == null)
break ECLISPE_BLOCK;
final ImageDescriptor imageDescriptor = desc.getImageDescriptor();
if (imageDescriptor == null)
break ECLISPE_BLOCK;
returnImage = imageDescriptor.createImage();
}
// Program icon from system
if (returnImage == null) {
final Program program = Program.findProgram(ext);
if (program != null) {
final ImageData iconData = Program.findProgram(ext).getImageData();
if (iconData != null) //Might happen it does not exist
returnImage = new Image(Display.getCurrent(), iconData);
}
}
if (returnImage == null)
returnImage = getImageSWT(file);
/* Not storing null image for ext, because the reason of null is the
* broken file. Even if a broken file icon would be gotten in the
* future, the image still should not be attached to ext.
*/
if (returnImage != null)
imageRegistry.put(ext, returnImage);
return returnImage;
}
/**
* Create a square image from a specified file, f of given side size, size in pixels.
* @param f
* @param size
* @return
*/
public Image createImage(final BufferedImage image) {
return new Image(null,convertToSWT(image) );
}
public IDataset createDataset(final BufferedImage bufferedImage) {
return convertToRGBDataset(bufferedImage);
}
static ImageData convertToSWT(BufferedImage bufferedImage) {
if (bufferedImage.getColorModel() instanceof DirectColorModel) {
DirectColorModel colorModel = (DirectColorModel)bufferedImage.getColorModel();
PaletteData palette = new PaletteData(colorModel.getRedMask(), colorModel.getGreenMask(), colorModel.getBlueMask());
ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette);
for (int y = 0; y < data.height; y++) {
for (int x = 0; x < data.width; x++) {
int rgb = bufferedImage.getRGB(x, y);
int pixel = palette.getPixel(new RGB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF));
data.setPixel(x, y, pixel);
if (colorModel.hasAlpha()) {
data.setAlpha(x, y, (rgb >> 24) & 0xFF);
}
}
}
return data;
} else if (bufferedImage.getColorModel() instanceof IndexColorModel) {
IndexColorModel colorModel = (IndexColorModel)bufferedImage.getColorModel();
int size = colorModel.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
colorModel.getReds(reds);
colorModel.getGreens(greens);
colorModel.getBlues(blues);
RGB[] rgbs = new RGB[size];
for (int i = 0; i < rgbs.length; i++) {
rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, blues[i] & 0xFF);
}
PaletteData palette = new PaletteData(rgbs);
ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette);
data.transparentPixel = colorModel.getTransparentPixel();
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[1];
for (int y = 0; y < data.height; y++) {
for (int x = 0; x < data.width; x++) {
raster.getPixel(x, y, pixelArray);
data.setPixel(x, y, pixelArray[0]);
}
}
return data;
}
return null;
}
static RGBDataset convertToRGBDataset(BufferedImage bufferedImage) {
RGBDataset data = DatasetFactory.zeros(RGBDataset.class, bufferedImage.getHeight(), bufferedImage.getWidth());
if (bufferedImage.getColorModel() instanceof DirectColorModel) {
DirectColorModel colorModel = (DirectColorModel)bufferedImage.getColorModel();
for (int y = 0; y < bufferedImage.getHeight(); y++) {
for (int x = 0; x < bufferedImage.getWidth(); x++) {
int value = bufferedImage.getRGB(x, y);
RGB rgb = new RGB((value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF);
data.set(new short[]{(short)rgb.red, (short)rgb.green, (short)rgb.blue}, y, x);
if (colorModel.hasAlpha()) {
// TODO
//data.set(x, y, (rgb >> 24) & 0xFF);
}
}
}
return data;
} else if (bufferedImage.getColorModel() instanceof IndexColorModel) {
IndexColorModel colorModel = (IndexColorModel)bufferedImage.getColorModel();
int size = colorModel.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
colorModel.getReds(reds);
colorModel.getGreens(greens);
colorModel.getBlues(blues);
RGB[] rgbs = new RGB[size];
for (int i = 0; i < rgbs.length; i++) {
rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, blues[i] & 0xFF);
}
PaletteData palette = new PaletteData(rgbs);
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[1];
for (int y = 0; y < bufferedImage.getHeight(); y++) {
for (int x = 0; x < bufferedImage.getWidth(); x++) {
raster.getPixel(x, y, pixelArray);
RGB rgb = palette.getRGB(pixelArray[0]);
data.set(new short[]{(short)rgb.red, (short)rgb.green, (short)rgb.blue}, y, x);
}
}
} else {
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[3];
for (int y = 0; y < bufferedImage.getHeight(); y++) {
for (int x = 0; x < bufferedImage.getWidth(); x++) {
raster.getPixel(x, y, pixelArray);
data.set(new short[]{
(short)pixelArray[0],
(short)pixelArray[1],
(short)pixelArray[2]},
y, x);
}
}
}
return data;
}
static Image getImageSWT(File file) {
ImageIcon systemIcon = (ImageIcon) FileSystemView.getFileSystemView().getSystemIcon(file);
if (systemIcon == null) // Happens when file does not exist
return null;
java.awt.Image image = systemIcon.getImage();
if (image instanceof BufferedImage) {
return new Image(Display.getDefault(), convertToSWT((BufferedImage)image));
}
int width = image.getWidth(null);
int height = image.getHeight(null);
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return new Image(Display.getDefault(), convertToSWT(bufferedImage));
}
private static Image folderImage;
private static Image rootFolderImage;
private Image getFolderImage(File file) {
//file should not be null, but if it is, then try a folder name (next line should be deleted)
// if (file==null) file = isWindowsOS() ? new File("C:/Windows/") : new File("/etc");
//if next line causes NPE, then uncommenting previous line is quick fix, but not optimal
if( file.getName().isEmpty() ) { //It is a root folder
if (rootFolderImage==null) {
/**
* On windows, use windows icon for folder,
* on unix folder icon can be not very nice looking, use folder.png
*/
if (isWindowsOS()) {
rootFolderImage = getImageSWT(file);
} else {
rootFolderImage = new Image(null, 16, 16);
}
}
return rootFolderImage;
} else {
if (folderImage==null) {
/**
* On windows, use windows icon for folder,
* on unix folder icon can be not very nice looking, use folder.png
*/
if (isWindowsOS()) {
folderImage = getImageSWT(file);
} else {
folderImage = new Image(null, 16, 16);
}
}
return folderImage;
}
}
/**
* @return true if windows
*/
static public boolean isWindowsOS() {
return (System.getProperty("os.name").indexOf("Windows") == 0);
}
@Override
public Image getIconForFile(String path) {
return getIconForFile(new File(path));
}
public final static List<String> EXT;
static {
List<String> tmp = new ArrayList<String>(7);
tmp.add("h5");
tmp.add("nxs");
tmp.add("hd5");
tmp.add("hdf5");
tmp.add("hdf");
tmp.add("nexus");
EXT = Collections.unmodifiableList(tmp);
}
public static boolean isH5(final String filePath) {
if (filePath == null) { return false; }
final String ext = FileUtils.getFileExtension(filePath);
if (ext == null) { return false; }
return EXT.contains(ext.toLowerCase());
}
}