SheetRenderer.java

00001 package edu.stanford.hci.r3.render;
00002 
00003 import java.awt.Color;
00004 import java.awt.Graphics2D;
00005 import java.awt.geom.AffineTransform;
00006 import java.io.File;
00007 import java.io.FileNotFoundException;
00008 import java.io.FileOutputStream;
00009 import java.util.List;
00010 
00011 import javax.media.jai.TiledImage;
00012 
00013 import com.lowagie.text.Document;
00014 import com.lowagie.text.DocumentException;
00015 import com.lowagie.text.Rectangle;
00016 import com.lowagie.text.pdf.PdfContentByte;
00017 import com.lowagie.text.pdf.PdfWriter;
00018 
00019 import edu.stanford.hci.r3.paper.Region;
00020 import edu.stanford.hci.r3.paper.Sheet;
00021 import edu.stanford.hci.r3.pattern.TiledPattern;
00022 import edu.stanford.hci.r3.pattern.TiledPatternGenerator;
00023 import edu.stanford.hci.r3.pattern.coordinates.PatternLocationToSheetLocationMapping;
00024 import edu.stanford.hci.r3.pattern.coordinates.conversion.TiledPatternCoordinateConverter;
00025 import edu.stanford.hci.r3.pattern.output.PDFPatternGenerator;
00026 import edu.stanford.hci.r3.units.Pixels;
00027 import edu.stanford.hci.r3.units.Points;
00028 import edu.stanford.hci.r3.units.Units;
00029 import edu.stanford.hci.r3.units.coordinates.Coordinates;
00030 import edu.stanford.hci.r3.util.DebugUtils;
00031 import edu.stanford.hci.r3.util.MathUtils;
00032 import edu.stanford.hci.r3.util.graphics.GraphicsUtils;
00033 import edu.stanford.hci.r3.util.graphics.ImageUtils;
00034 import edu.stanford.hci.r3.util.graphics.JAIUtils;
00035 
00051 public class SheetRenderer {
00052 
00056         private TiledPatternGenerator generator;
00057 
00061         private File mostRecentlyRenderedPDFFile;
00062 
00066         private Color patternColor = Color.BLACK;
00067 
00072         private int patternDotSizeAdjustment = 0;
00073 
00079         private PatternLocationToSheetLocationMapping patternInformation;
00080 
00085         protected boolean renderActiveRegionsWithPattern = true;
00086 
00090         protected Sheet sheet;
00091 
00097         public SheetRenderer(Sheet s) {
00098                 this(s, new TiledPatternGenerator());
00099         }
00100 
00108         public SheetRenderer(Sheet s, TiledPatternGenerator patternGenerator) {
00109                 sheet = s;
00110                 patternInformation = sheet.getPatternLocationToSheetLocationMapping();
00111                 generator = patternGenerator;
00112         }
00113 
00117         public PatternLocationToSheetLocationMapping getPatternInformation() {
00118                 return patternInformation;
00119         }
00120 
00132         private void renderPattern(PdfContentByte cb) {
00133                 // for each region, overlay pattern if it is an active region
00134                 final List<Region> regions = sheet.getRegions();
00135 
00136                 // this object will generate the right PDF (itext) calls to create pattern
00137                 final PDFPatternGenerator pgen = new PDFPatternGenerator(cb, sheet.getWidth(), sheet.getHeight());
00138                 pgen.setPatternColor(patternColor);
00139 
00140                 // adjust the font size of the pattern...
00141                 pgen.adjustPatternSize(patternDotSizeAdjustment);
00142 
00143                 // render each region that is active
00144                 for (Region r : regions) {
00145                         if (!r.isActive()) {
00146                                 continue;
00147                         }
00148 
00149                         DebugUtils.println("-------------");
00150 
00151                         // add the region's offset from the top left corner of the sheet
00152                         Coordinates regionOffset = sheet.getRegionOffset(r);
00153 
00154                         // System.out.println("SheetRenderer: Rendering Pattern:" + r.getShape());
00155                         // DebugUtils.println(r.getOriginX() + " " + r.getOriginY());
00156 
00157                         // Figure out the real width and height....
00158                         final Units scaledWidth = r.getWidth();
00159                         final Units scaledHeight = r.getHeight();
00160 
00161                         // get pattern of the given width and height
00162                         // by default, the pattern returned will be unique if possible (and a warning thrown
00163                         // otherwise). If you want to use the same pattern in different places, you will
00164                         // need to keep the returned pattern object around
00165                         final TiledPattern pattern = generator.getPattern(scaledWidth, scaledHeight);
00166 
00167                         DebugUtils.println("Rendering Pattern for " + r.getName());
00168                         // render the pattern starting at the region's origin
00169                         pgen.renderPattern(pattern, // the tiled pattern
00170                                         Units.add(r.getOriginX(), regionOffset.getX()), // origin + offset
00171                                         Units.add(r.getOriginY(), regionOffset.getY()));// same, for y
00172 
00173                         // also, at this point, we know what pattern we have assigned to each region
00174                         // we should be able to assign a tile configuration to each region
00175                         // We retrieve it from the HashMap so we can SET the values in the line below
00176                         final TiledPatternCoordinateConverter tiledPatternInRegion = (TiledPatternCoordinateConverter) patternInformation
00177                                         .getPatternBoundsOfRegion(r);
00178                         tiledPatternInRegion.setPatternInformationByReadingItFrom(pattern);
00179                         // the name should already be correct, barring the UnitializedMapping business...
00180                         // tiledPatternInRegion.setRegionName(r.getName());
00181                         // now, this object is modified
00182                         // since it is already mapped to the correct region r, we do not need
00183                         // to do anything else!
00184                 }
00185 
00186                 // /////////////////////////////////////////////////////
00187                 // /////////////////////////////////////////////////////
00188                 // FOR NOW, SPECIAL CASE THE COMPOUND REGIONS
00189                 // IN THE FUTURE, FIGURE OUT HOW TO INTEGRATE IT NICELY
00190                 // /////////////////////////////////////////////////////
00191                 // /////////////////////////////////////////////////////
00192                 // for (Region r : regions) {
00193                 // if (r instanceof CompoundRegion) {
00194                 // DebugUtils.println("Rendering Pattern for Compound Region!");
00195                 // }
00196                 // }
00197                 // 
00198                 // MUST REARCHITECT Pattern Rendering & Event Handling if we are to allow Compound Regions
00199                 // This is for R3 version 0.2 =\ AFTER September 29th...
00200         }
00201 
00211         public void renderToG2D(Graphics2D g2d) {
00212                 // anti-aliased, high quality rendering
00213                 g2d.setRenderingHints(GraphicsUtils.getBestRenderingHints());
00214 
00215                 final List<Region> regions = sheet.getRegions();
00216 
00217                 // render each region
00218                 for (Region r : regions) {
00219                         // Weird. g2d.getTransform SHOULD give us a copy....
00220                         // a real copy
00221                         final AffineTransform currTransform = new AffineTransform(g2d.getTransform());
00222                         DebugUtils.println("Rendering " + r.getName());
00223                         final Coordinates regionOffset = sheet.getRegionOffset(r);
00224                         final double xOffsetPts = regionOffset.getX().getValueInPoints();
00225                         final double yOffsetPts = regionOffset.getY().getValueInPoints();
00226                         // System.out.println(xOffsetPts);
00227                         // g2d.transform(AffineTransform.getTranslateInstance(xOffsetPts, yOffsetPts));
00228                         g2d.translate((int) xOffsetPts, (int) yOffsetPts);
00229                         r.getRenderer().renderToG2D(g2d);
00230                         g2d.setTransform(currTransform);
00231                 }
00232         }
00233 
00239         public void renderToJPEG(File file) {
00240                 renderToJPEG(file, Pixels.ONE);
00241         }
00242 
00250         public void renderToJPEG(File destJPEGFile, Pixels destUnits) {
00251                 final Units width = sheet.getWidth();
00252                 final Units height = sheet.getHeight();
00253 
00254                 final double scale = Points.ONE.getConversionTo(destUnits);
00255 
00256                 final int w = MathUtils.rint(width.getValueIn(destUnits));
00257                 final int h = MathUtils.rint(height.getValueIn(destUnits));
00258                 final TiledImage image = JAIUtils.createWritableBufferWithoutAlpha(w, h);
00259                 final Graphics2D graphics2D = image.createGraphics();
00260                 graphics2D.setRenderingHints(GraphicsUtils.getBestRenderingHints());
00261 
00262                 // transform the graphics such that we are in destUnits' pixels per inch, so that when we
00263                 // draw 72 Graphics2D pixels from now on, it will equal the correct number of output pixels
00264                 // in the JPEG.
00265                 graphics2D.setTransform(AffineTransform.getScaleInstance(scale, scale));
00266 
00267                 // render a white canvas
00268                 graphics2D.setColor(Color.WHITE);
00269                 graphics2D.fillRect(0, 0, w, h);
00270 
00271                 renderToG2D(graphics2D);
00272                 graphics2D.dispose();
00273                 ImageUtils.writeImageToJPEG(image.getAsBufferedImage(), destJPEGFile);
00274         }
00275 
00282         public void renderToPDF(File destPDFFile) {
00283                 try {
00284                         final FileOutputStream fileOutputStream = new FileOutputStream(destPDFFile);
00285 
00286                         final Rectangle pageSize = new Rectangle(0, 0, (int) Math.round(sheet.getWidth()
00287                                         .getValueInPoints()), (int) Math.round(sheet.getHeight().getValueInPoints()));
00288 
00289                         // create a document with these margins (worry about margins later)
00290                         final Document doc = new Document(pageSize, 0, 0, 0, 0);
00291                         final PdfWriter writer = PdfWriter.getInstance(doc, fileOutputStream);
00292                         doc.open();
00293 
00294                         final PdfContentByte topLayer = writer.getDirectContent();
00295                         final PdfContentByte bottomLayer = writer.getDirectContentUnder();
00296                         renderToPDFContentLayers(destPDFFile, topLayer, bottomLayer);
00297 
00298                         doc.close();
00299 
00300                         // save the pattern info to the same directory automatically
00301                         savePatternInformation(); // do this automatically
00302                 } catch (FileNotFoundException e) {
00303                         e.printStackTrace();
00304                 } catch (DocumentException e) {
00305                         e.printStackTrace();
00306                 }
00307         }
00308 
00314         protected void renderToPDFContentLayers(File destPDFFile, PdfContentByte topLayer,
00315                         PdfContentByte bottomLayer) {
00316                 mostRecentlyRenderedPDFFile = destPDFFile;
00317 
00318                 final Units width = sheet.getWidth();
00319                 final Units height = sheet.getHeight();
00320                 final float wPoints = (float) width.getValueInPoints();
00321                 final float hPoints = (float) height.getValueInPoints();
00322 
00323                 // top layer for regions (changed from bottom layer)
00324                 final Graphics2D g2dOver = topLayer.createGraphicsShapes(wPoints, hPoints);
00325                 // now that we have a G2D, we can just use our other G2D rendering method
00326                 renderToG2D(g2dOver);
00327 
00328                 // an efficient dispose, because we are not within a Java paint() method
00329                 g2dOver.dispose();
00330 
00331                 // should this be moved to regions???
00332                 if (renderActiveRegionsWithPattern) {
00333                         DebugUtils.println("Rendering Pattern");
00334                         // after rendering everything, we still need to overlay the pattern on top of active
00335                         // regions; This is only for PDF rendering.
00336 
00337                         // top layer for pattern
00338                         renderPattern(topLayer);
00339                 }
00340         }
00341 
00346         public void savePatternInformation() {
00347                 if (mostRecentlyRenderedPDFFile == null) {
00348                         System.err.println("SheetRenderer: We cannot save the pattern information "
00349                                         + "without a destination file. Please render a PDF first "
00350                                         + "so we know where to put the pattern configuration file!");
00351                 } else {
00352                         File parentDir = mostRecentlyRenderedPDFFile.getParentFile();
00353                         String fileName = mostRecentlyRenderedPDFFile.getName();
00354                         if (fileName.contains(".pdf")) {
00355                                 fileName = fileName.replace(".pdf", ".patternInfo.xml");
00356                         } else {
00357                                 fileName = fileName + ".patternInfo.xml";
00358                         }
00359                         File destFile = new File(parentDir, fileName);
00360                         savePatternInformation(destFile);
00361                 }
00362         }
00363 
00370         public void savePatternInformation(File patternInfoFile) {
00371                 // save the pattern info to disk as a nice XML File! =)
00372                 patternInformation.saveConfigurationToXML(patternInfoFile);
00373                 DebugUtils.println("Pattern Information saved to " + patternInfoFile.getAbsolutePath());
00374         }
00375 
00379         public void setPatternColor(Color pColor) {
00380                 patternColor = pColor;
00381         }
00382 
00390         public void setPatternGenerator(TiledPatternGenerator tiledPatternGenerator) {
00391                 generator = tiledPatternGenerator;
00392         }
00393 
00397         public void setRenderActiveRegionsWithPattern(boolean activeWithPattern) {
00398                 renderActiveRegionsWithPattern = activeWithPattern;
00399         }
00400 
00404         public void useLargerPatternDots() {
00405                 patternDotSizeAdjustment++;
00406         }
00407 
00411         public void useSmallerPatternDots() {
00412                 patternDotSizeAdjustment--;
00413         }
00414 }

Generated on Sat Apr 14 18:21:38 2007 for R3 Paper Toolkit by  doxygen 1.4.7