add dpi option for image output

This commit is contained in:
wyq 2019-04-18 11:40:37 +08:00
parent 3947dafd75
commit 5437734e79
9 changed files with 365 additions and 41 deletions

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<MeteoInfo File="milconfig.xml" Type="configurefile">
<Path OpenPath="D:\Working\MIScript\Jython\mis\io">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map"/>
<Path OpenPath="D:\Working\MIScript\Jython\mis\plot_types">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\micaps"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\onedim"/>
@ -16,25 +15,22 @@
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map\projection"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\image"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\wind"/>
</Path>
<File>
<OpenedFiles>
<OpenedFile File="D:\Working\MIScript\cuace_dust\py\ensemble\daily_input.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\toolbox\miml\xor.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\array\dataframe_2.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\common_math\random\normal_1.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\io\savefig_dpi_1.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\io\savefig_dpi_2.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\heart.py"/>
</OpenedFiles>
<RecentFiles>
<RecentFile File="D:\Working\MIScript\cuace_dust\py\ensemble\daily_input.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\toolbox\miml\xor.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\array\dataframe_2.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\common_math\random\normal_1.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\io\savefig_dpi_1.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\io\savefig_dpi_2.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\heart.py"/>
</RecentFiles>
</File>
<Font>
<TextFont FontName="宋体" FontSize="15"/>
</Font>
<Startup MainFormLocation="-4,3" MainFormSize="1370,763"/>
<Startup MainFormLocation="-7,-7" MainFormSize="1293,693"/>
</MeteoInfo>

View File

@ -245,6 +245,7 @@ def addfile_mm5(fname, getfn=True, reffile=None):
:param fname: (*string*) The MM5 file name.
:param getfn: (*string*) If run ``__getfilename`` function or not. Default is ``True``.
:param reffile: (*string*) Reference file, for the mm5 file lacking header part.
:returns: (*DimDataFile*) Opened file object.
'''

View File

@ -56,7 +56,6 @@ import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream;
@ -93,6 +92,7 @@ import org.meteoinfo.data.mapdata.Field;
import org.meteoinfo.global.Extent;
import org.meteoinfo.global.GenericFileFilter;
import org.meteoinfo.global.PointF;
import org.meteoinfo.image.ImageUtil;
import org.meteoinfo.layer.LayerTypes;
import org.meteoinfo.layer.MapLayer;
import org.meteoinfo.layer.RasterLayer;
@ -123,8 +123,7 @@ public class ChartPanel extends JPanel {
private boolean dragMode = false;
private JPopupMenu popupMenu;
private MouseMode mouseMode;
private List<int[]> selectedPoints;
private final double INCH_2_CM = 2.54;
private List<int[]> selectedPoints;
private int xShift = 0;
private int yShift = 0;
private double paintScale = 1.0;
@ -1498,7 +1497,7 @@ public class ChartPanel extends JPanel {
continue;
}
setDPI(metadata, dpi);
ImageUtil.setDPI(metadata, dpi);
if (sleep != null) {
Thread.sleep(sleep * 1000);
@ -1514,28 +1513,7 @@ public class ChartPanel extends JPanel {
}
g.dispose();
}
private void setDPI(IIOMetadata metadata, float dpi) throws IIOInvalidTreeException {
// for PMG, it's dots per millimeter
double dotsPerMilli = 1.0 * dpi / 10 / INCH_2_CM;
IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
horiz.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
vert.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode dim = new IIOMetadataNode("Dimension");
dim.appendChild(horiz);
dim.appendChild(vert);
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
root.appendChild(dim);
metadata.mergeTree("javax_imageio_1.0", root);
}
/**
* Get view image
*

View File

@ -11,6 +11,9 @@ import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import org.apache.sanselan.ImageFormat;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.ImageWriteException;
@ -24,6 +27,9 @@ import org.apache.sanselan.Sanselan;
* @author Yaqiang Wang
*/
public class ImageUtil {
private final static double INCH_2_CM = 2.54;
/**
* Read RGB array data from image file
* @param fileName Image file name
@ -377,4 +383,32 @@ public class ImageUtil {
e.printStackTrace();
}
}
/**
* Set DPI
* @param metadata IIOMetadata
* @param dpi DPI
* @throws IIOInvalidTreeException
*/
public static void setDPI(IIOMetadata metadata, float dpi) throws IIOInvalidTreeException {
// for PMG, it's dots per millimeter
double dotsPerMilli = 1.0 * dpi / 10 / INCH_2_CM;
IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
horiz.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
vert.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode dim = new IIOMetadataNode("Dimension");
dim.appendChild(horiz);
dim.appendChild(vert);
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
root.appendChild(dim);
metadata.mergeTree("javax_imageio_1.0", root);
}
}

View File

@ -101,11 +101,19 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
@ -137,6 +145,7 @@ import org.meteoinfo.data.mapdata.webmap.TileLoadListener;
import org.meteoinfo.global.event.IUndoEditListener;
import org.meteoinfo.global.event.UndoEditEvent;
import org.meteoinfo.global.util.GlobalUtil;
import org.meteoinfo.image.ImageUtil;
import org.meteoinfo.layer.RasterLayer;
import org.meteoinfo.layer.WebMapLayer;
import org.meteoinfo.legend.VectorBreak;
@ -2904,6 +2913,103 @@ public class MapLayout extends JPanel implements IWebMapPanel {
}
}
}
/**
* Export to a picture file
*
* @param fileName File path
* @param dpi DPI
* @throws java.io.FileNotFoundException
* @throws javax.print.PrintException
*/
public void exportToPicture(String fileName, Integer dpi) throws FileNotFoundException, PrintException, IOException {
if (dpi == null) {
exportToPicture(fileName);
} else {
File output = new File(fileName);
output.delete();
int width = _pageBounds.width;
int height = _pageBounds.height;
String formatName = fileName.substring(fileName.lastIndexOf('.') + 1);
if (formatName.equals("jpg")) {
formatName = "jpeg";
saveImage_Jpeg(fileName, width, height, dpi);
return;
}
double scaleFactor = dpi / 72.0;
BufferedImage image = new BufferedImage((int)(width * scaleFactor), (int)(height * scaleFactor), BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
AffineTransform at = g.getTransform();
at.scale(scaleFactor, scaleFactor);
g.setTransform(at);
paintGraphics(g);
for (Iterator<ImageWriter> iw = ImageIO.getImageWritersByFormatName(formatName); iw.hasNext();) {
ImageWriter writer = iw.next();
ImageWriteParam writeParam = writer.getDefaultWriteParam();
ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
if (metadata.isReadOnly() || !metadata.isStandardMetadataFormatSupported()) {
continue;
}
ImageUtil.setDPI(metadata, dpi);
final ImageOutputStream stream = ImageIO.createImageOutputStream(output);
try {
writer.setOutput(stream);
writer.write(metadata, new IIOImage(image, null, metadata), writeParam);
} finally {
stream.close();
}
break;
}
g.dispose();
}
}
private boolean saveImage_Jpeg(String file, int width, int height, int dpi) {
double scaleFactor = dpi / 72.0;
BufferedImage bufferedImage = new BufferedImage((int)(width * scaleFactor), (int)(height * scaleFactor), BufferedImage.TYPE_INT_RGB);
Graphics2D g = bufferedImage.createGraphics();
AffineTransform at = g.getTransform();
at.scale(scaleFactor, scaleFactor);
g.setTransform(at);
paintGraphics(g);
try {
// Image writer
ImageWriter imageWriter = ImageIO.getImageWritersBySuffix("jpeg").next();
ImageOutputStream ios = ImageIO.createImageOutputStream(new File(file));
imageWriter.setOutput(ios);
// Compression
JPEGImageWriteParam jpegParams = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
jpegParams.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(0.85f);
// Metadata (dpi)
IIOMetadata data = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(bufferedImage), jpegParams);
Element tree = (Element) data.getAsTree("javax_imageio_jpeg_image_1.0");
Element jfif = (Element) tree.getElementsByTagName("app0JFIF").item(0);
jfif.setAttribute("Xdensity", Integer.toString(dpi));
jfif.setAttribute("Ydensity", Integer.toString(dpi));
jfif.setAttribute("resUnits", "1"); // density is dots per inch
data.setFromTree("javax_imageio_jpeg_image_1.0", tree);
// Write and clean up
imageWriter.write(null, new IIOImage(bufferedImage, null, data), jpegParams);
ios.close();
imageWriter.dispose();
} catch (Exception e) {
return false;
}
g.dispose();
return true;
}
// </editor-fold>
// <editor-fold desc="Coordinate transfer">

View File

@ -130,11 +130,19 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
@ -172,6 +180,7 @@ import org.meteoinfo.global.event.ShapeSelectedEvent;
import org.meteoinfo.global.event.UndoEditEvent;
import org.meteoinfo.global.util.BigDecimalUtil;
import org.meteoinfo.global.util.GeoUtil;
import org.meteoinfo.image.ImageUtil;
import static org.meteoinfo.layer.LayerDrawType.Barb;
import static org.meteoinfo.layer.LayerDrawType.StationModel;
import static org.meteoinfo.layer.LayerDrawType.Streamline;
@ -4104,6 +4113,11 @@ public class MapView extends JPanel implements IWebMapPanel {
if (this._lockViewUpdate) {
return;
}
//Draw background
g.setColor(this.getBackground());
//g.clearRect(0, 0, this.getWidth(), this.getHeight());
g.fillRect(0, 0, this.getWidth(), this.getHeight());
getMaskOutGraphicsPath(g);
@ -6559,6 +6573,102 @@ public class MapView extends JPanel implements IWebMapPanel {
}
}
}
/**
* Export to a picture file
*
* @param fileName File path
* @param dpi DPI
* @throws java.io.FileNotFoundException
* @throws javax.print.PrintException
*/
public void exportToPicture(String fileName, Integer dpi) throws FileNotFoundException, PrintException, IOException {
if (dpi == null) {
exportToPicture(fileName);
} else {
File output = new File(fileName);
output.delete();
int width = this.getWidth();
int height = this.getHeight();
String formatName = fileName.substring(fileName.lastIndexOf('.') + 1);
if (formatName.equals("jpg")) {
formatName = "jpeg";
saveImage_Jpeg(fileName, width, height, dpi);
return;
}
double scaleFactor = dpi / 72.0;
BufferedImage image = new BufferedImage((int)(width * scaleFactor), (int)(height * scaleFactor), BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
AffineTransform at = g.getTransform();
at.scale(scaleFactor, scaleFactor);
g.setTransform(at);
paintGraphics(g);
for (Iterator<ImageWriter> iw = ImageIO.getImageWritersByFormatName(formatName); iw.hasNext();) {
ImageWriter writer = iw.next();
ImageWriteParam writeParam = writer.getDefaultWriteParam();
ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
if (metadata.isReadOnly() || !metadata.isStandardMetadataFormatSupported()) {
continue;
}
ImageUtil.setDPI(metadata, dpi);
final ImageOutputStream stream = ImageIO.createImageOutputStream(output);
try {
writer.setOutput(stream);
writer.write(metadata, new IIOImage(image, null, metadata), writeParam);
} finally {
stream.close();
}
break;
}
g.dispose();
}
}
private boolean saveImage_Jpeg(String file, int width, int height, int dpi) {
double scaleFactor = dpi / 72.0;
BufferedImage bufferedImage = new BufferedImage((int)(width * scaleFactor), (int)(height * scaleFactor), BufferedImage.TYPE_INT_RGB);
Graphics2D g = bufferedImage.createGraphics();
AffineTransform at = g.getTransform();
at.scale(scaleFactor, scaleFactor);
g.setTransform(at);
paintGraphics(g);
try {
// Image writer
ImageWriter imageWriter = ImageIO.getImageWritersBySuffix("jpeg").next();
ImageOutputStream ios = ImageIO.createImageOutputStream(new File(file));
imageWriter.setOutput(ios);
// Compression
JPEGImageWriteParam jpegParams = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
jpegParams.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(0.85f);
// Metadata (dpi)
IIOMetadata data = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(bufferedImage), jpegParams);
Element tree = (Element) data.getAsTree("javax_imageio_jpeg_image_1.0");
Element jfif = (Element) tree.getElementsByTagName("app0JFIF").item(0);
jfif.setAttribute("Xdensity", Integer.toString(dpi));
jfif.setAttribute("Ydensity", Integer.toString(dpi));
jfif.setAttribute("resUnits", "1"); // density is dots per inch
data.setFromTree("javax_imageio_jpeg_image_1.0", tree);
// Write and clean up
imageWriter.write(null, new IIOImage(bufferedImage, null, data), jpegParams);
ios.close();
imageWriter.dispose();
} catch (Exception e) {
return false;
}
g.dispose();
return true;
}
// </editor-fold>
// <editor-fold desc="Lon/Lat Layer">

View File

@ -3125,7 +3125,7 @@ public class FrmMain extends JFrame implements IApplication {
// TODO add your handling code here:
String path = System.getProperty("user.dir");
File pathDir = new File(path);
JFileChooser aDlg = new JFileChooser();
ImageFileChooser aDlg = new ImageFileChooser();
aDlg.setCurrentDirectory(pathDir);
String[] fileExts = new String[]{"png"};
GenericFileFilter pngFileFilter = new GenericFileFilter(fileExts, "Png Image (*.png)");
@ -3164,10 +3164,11 @@ public class FrmMain extends JFrame implements IApplication {
if (!fileName.substring(fileName.length() - extent.length()).equals(extent)) {
fileName = fileName + "." + extent;
}
Integer dpi = aDlg.getDPI();
if (this.jTabbedPane_Main.getSelectedIndex() == 0) {
try {
_mapDocument.getActiveMapFrame().getMapView().exportToPicture(fileName);
_mapDocument.getActiveMapFrame().getMapView().exportToPicture(fileName, dpi);
} catch (FileNotFoundException ex) {
Logger.getLogger(FrmMain.class.getName()).log(Level.SEVERE, null, ex);
} catch (PrintException ex) {
@ -3177,7 +3178,7 @@ public class FrmMain extends JFrame implements IApplication {
}
} else if (this.jTabbedPane_Main.getSelectedIndex() == 1) {
try {
_mapDocument.getMapLayout().exportToPicture(fileName);
_mapDocument.getMapLayout().exportToPicture(fileName, dpi);
} catch (FileNotFoundException ex) {
Logger.getLogger(FrmMain.class.getName()).log(Level.SEVERE, null, ex);
} catch (PrintException ex) {

View File

@ -0,0 +1,99 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.meteoinfo.desktop.forms;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.meteoinfo.desktop.config.GenericFileFilter;
/**
*
* @author Yaqiang Wang
*/
public class ImageFileChooser extends JFileChooser {
JComboBox dpiCB;
JPanel panel;
/**
* Constructor
*/
public ImageFileChooser() {
super();
dpiCB = new JComboBox();
DefaultComboBoxModel cbm = new DefaultComboBoxModel();
cbm.addElement("Default");
cbm.addElement("150");
cbm.addElement("300");
cbm.addElement("600");
cbm.addElement("900");
cbm.addElement("1200");
dpiCB.setModel(cbm);
dpiCB.setEditable(true);
panel = new JPanel(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = GridBagConstraints.WEST;
constraints.insets = new Insets(5, 10, 0, 0);
constraints.gridx = 0;
constraints.gridy = 0;
panel.add(new JLabel("DPI:"), constraints);
constraints.gridy = 1;
panel.add(dpiCB, constraints);
setAccessory(panel);
//panel.setVisible(false);
this.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pce) {
String prop = pce.getPropertyName();
//If a file became selected, find out which one.
if (JFileChooser.FILE_FILTER_CHANGED_PROPERTY.equals(prop)) {
GenericFileFilter filter = (GenericFileFilter) pce.getNewValue();
if (filter != null){
switch (filter.getFileExtent().toLowerCase()) {
case "png":
case "jpg":
case "bmp":
case "gif":
panel.setVisible(true);
break;
default:
panel.setVisible(false);
break;
}
repaint();
}
}
}
});
}
/**
* Get DPI
*
* @return DPI
*/
public Integer getDPI() {
if (!this.dpiCB.isVisible())
return null;
String dpiStr = this.dpiCB.getSelectedItem().toString();
if (dpiStr.equals("Default")) {
return null;
} else {
return Integer.parseInt(dpiStr);
}
}
}

View File

@ -5,7 +5,6 @@
*/
package org.meteoinfo.desktop.forms;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;