/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: LayoutImage.java * * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.user.dialogs; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.prototype.NodeProto; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.technology.PrimitiveNode; import com.sun.electric.technology.Technology; import com.sun.electric.tool.Job; import com.sun.electric.tool.JobException; import com.sun.electric.tool.io.FileType; import com.sun.electric.tool.user.User; import com.sun.electric.tool.user.ui.WindowFrame; import com.sun.electric.util.TextUtils; import javax.imageio.stream.ImageInputStream; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.swing.*; import java.awt.Canvas; import java.awt.Frame; import java.awt.Image; import java.awt.MediaTracker; import java.awt.Toolkit; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.awt.image.Raster; import java.util.Iterator; import java.io.File; /** * Class to handle the "Layout Image" dialog. There is still a ton of * overlap left in here from LayoutText.java; at some point I will * either merge the two or else remove that overlap. In particular, * LayoutText could benefit from "backporting" the new support for * grayscale images (which would give us antialiased layout text!) * * @author Adam Megacz <adam.megacz@sun.com>, derived from LayoutText.java */ public class LayoutImage extends EDialog { /** Creates new form LayoutImage */ public LayoutImage(Frame parent) { super(parent, true); initComponents(); // make all text fields select-all when entered EDialog.makeTextFieldSelectAllOnTab(largestDotWidth); EDialog.makeTextFieldSelectAllOnTab(smallestDotWidth); EDialog.makeTextFieldSelectAllOnTab(minimumGutter); EDialog.makeTextFieldSelectAllOnTab(fileName); largestDotWidth.setText("32"); smallestDotWidth.setText("22"); minimumGutter.setText("16"); // fileName.setText("/Users/megacz/proj/fleet/marina/logo/marina-logo.png"); monochrome.setSelected(false); reverseVideo.setSelected(false); Technology tech = Technology.getCurrent(); for(Iterator<PrimitiveNode> it = tech.getNodes(); it.hasNext(); ) { PrimitiveNode np = it.next(); if (np.getFunction() == PrimitiveNode.Function.NODE) textLayer.addItem(np.getName()); } finishInitialization(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; cancel = new javax.swing.JButton(); ok = new javax.swing.JButton(); jLabel1 = new javax.swing.JLabel(); smallestDotWidth = new javax.swing.JTextField(); jLabel2 = new javax.swing.JLabel(); largestDotWidth = new javax.swing.JTextField(); jLabel3 = new javax.swing.JLabel(); minimumGutter = new javax.swing.JTextField(); jLabel5 = new javax.swing.JLabel(); textLayer = new javax.swing.JComboBox(); reverseVideo = new javax.swing.JCheckBox(); monochrome = new javax.swing.JCheckBox(); fileName = new javax.swing.JTextField(); jLabel4 = new javax.swing.JLabel(); openFileButton = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setTitle("Layout Image"); getContentPane().setLayout(new java.awt.GridBagLayout()); cancel.setText("Cancel"); cancel.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cancel(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 9; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(cancel, gridBagConstraints); ok.setText("OK"); ok.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { ok(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 9; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(ok, gridBagConstraints); jLabel1.setText("Width of smallest dot:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(jLabel1, gridBagConstraints); smallestDotWidth.setColumns(8); smallestDotWidth.setText(" "); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(smallestDotWidth, gridBagConstraints); jLabel2.setText("Width of largest dot:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(jLabel2, gridBagConstraints); largestDotWidth.setColumns(8); largestDotWidth.setText(" "); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(largestDotWidth, gridBagConstraints); jLabel3.setText("Minimum gutter between dots:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(jLabel3, gridBagConstraints); minimumGutter.setColumns(8); minimumGutter.setText(" "); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(minimumGutter, gridBagConstraints); jLabel5.setText("Layer:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 6; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(jLabel5, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 6; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(textLayer, gridBagConstraints); reverseVideo.setText("Reverse-video"); reverseVideo.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); reverseVideo.setMargin(new java.awt.Insets(0, 0, 0, 0)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 7; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(reverseVideo, gridBagConstraints); monochrome.setText("Monochrome"); monochrome.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); monochrome.setMargin(new java.awt.Insets(0, 0, 0, 0)); monochrome.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { monochromeActionPerford(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 8; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(monochrome, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 4, 1, 4); getContentPane().add(fileName, gridBagConstraints); jLabel4.setText("Image file name:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(jLabel4, gridBagConstraints); openFileButton.setText("Load"); openFileButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { openFileButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new java.awt.Insets(1, 4, 12, 4); getContentPane().add(openFileButton, gridBagConstraints); pack(); }// </editor-fold>//GEN-END:initComponents private void cancel(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancel setVisible(false); dispose(); }//GEN-LAST:event_cancel private void ok(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ok final Cell curCell = WindowFrame.needCurCell(); if (curCell == null) return; final Technology tech = Technology.getCurrent(); final int minimumGutter = (int)TextUtils.atofDistance(this.minimumGutter.getText(), tech); final int largestDotWidth = (int)TextUtils.atofDistance(this.largestDotWidth.getText(), tech); final int smallestDotWidth = (int)TextUtils.atofDistance(this.smallestDotWidth.getText(), tech); // final boolean reverseVideo = this.reverseVideo.isSelected(); final String layer = (String)textLayer.getSelectedItem(); // determine the primitive to use for the layout final NodeProto primNode = Technology.getCurrent().findNodeProto(layer); if (primNode == null) { System.out.println("Cannot find " + layer + " primitive"); return; } try { // Checking if the file is actually a JPEG file File fileURL = new File(fileName.getText()); ImageInputStream iis = ImageIO.createImageInputStream(fileURL); Iterator<ImageReader> readers = ImageIO.getImageReaders(iis); boolean validFormat = false; while (readers.hasNext()) { ImageReader read = readers.next(); // Another way to detect this could be "read instanceof JPEGImageReader String format = read.getFormatName().toLowerCase(); // so far jpeg and png are the only valid formats tested. validFormat = format.equals("jpeg") || format.equals("png"); if (validFormat) break; } if (!validFormat) { String msg = "'" + fileName.getText() + "' is not a JPEG file"; JOptionPane.showMessageDialog(null, msg, "Erorr in LoadImage", JOptionPane.ERROR_MESSAGE); return; } Image img = Toolkit.getDefaultToolkit().createImage(fileName.getText()); // dumb hack to force AWT to load the image MediaTracker mediatracker = new MediaTracker(new Canvas()); mediatracker.addImage(img, 1); try { mediatracker.waitForAll(); } catch (InterruptedException e) { } mediatracker.removeImage(img); BufferedImage textImage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_BYTE_GRAY); textImage.getGraphics().drawImage(img, 0, 0, null); Raster ras = textImage.getData(); DataBufferByte dbb = (DataBufferByte)ras.getDataBuffer(); setVisible(false); dispose(); new LayoutImageJob(ras.getWidth(), ras.getHeight(), ras.getWidth()/2, -ras.getHeight()/2, dbb.getData(), largestDotWidth+minimumGutter, largestDotWidth, smallestDotWidth, primNode, curCell); } catch (Exception e) { throw new RuntimeException(e); } }//GEN-LAST:event_ok private static class LayoutImageJob extends Job { int width; int height; int xOffset; int yOffset; byte[] samples; int scale; int largestDotWidth; int smallestDotWidth; NodeProto primNode; Cell curCell; public LayoutImageJob(int width, int height, int xOffset, int yOffset, byte[] samples, int scale, int largestDotWidth, int smallestDotWidth, NodeProto primNode, Cell curCell) { super("Create Layout Image", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER); this.xOffset = xOffset; this.yOffset = yOffset; this.width = width; this.height = height; this.samples = samples; this.scale = scale; this.largestDotWidth = largestDotWidth; this.smallestDotWidth = smallestDotWidth; this.primNode = primNode; this.curCell = curCell; startJob(); } public boolean doIt() throws JobException { int samp = 0; for(int y=0; y<height; y++) { for(int x=0; x<width; x++) { int w = ((int)(((255-(samples[samp++] & 0xff)) / 255f) * ((largestDotWidth-smallestDotWidth))))+smallestDotWidth; Point2D center = new Point2D.Double((x-xOffset)*scale, -(y+yOffset)*scale); NodeInst.newInstance(primNode, center, w, w, curCell); } } return true; } } private void monochromeActionPerford(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_monochromeActionPerford // TODO add your handling code here: }//GEN-LAST:event_monochromeActionPerford private void openFileButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openFileButtonActionPerformed String fn = OpenFile.chooseInputFile(FileType.ANY, null); if (fn == null) return; fileName.setText(fn); }//GEN-LAST:event_openFileButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton cancel; private javax.swing.JTextField fileName; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; private javax.swing.JLabel jLabel5; private javax.swing.JTextField largestDotWidth; private javax.swing.JTextField minimumGutter; private javax.swing.JCheckBox monochrome; private javax.swing.JButton ok; private javax.swing.JButton openFileButton; private javax.swing.JCheckBox reverseVideo; private javax.swing.JTextField smallestDotWidth; private javax.swing.JComboBox textLayer; // End of variables declaration//GEN-END:variables }