title: Printing to a physical form -- need basic understanding
body: <p>I'm not quite sure I understand g.drawString. </p>
  
  <p>I have a program that writes to a preprinted form.  The users claim that the printing is irregular...ie, text on the form is higher/lower than the previous print.  Personally, I think they're misloading the form, but since they pay me to write code, I'm measuring the form and converting dimensions to pixels and rewriting the portion that deals with printing.</p>
  
  <p>To print the form correctly, c.getCostAmount() has to be printed one pixel ABOVE c.getAppraisersAmount() for it to appear one line below it.  Yet, each succeeding line is 4mm (or roughly 15 pixels) below that.  </p>
  
  <p>My problem is that <strong>I don't understand the vertical distances</strong> and why the 3rd line has to be placed a pixel above the previous line for it to be underneath.</p>
  
  <p>Anybody have a quick-n-easy explanation or a link to a tutorial/explanation?</p>
  
  <p>Much thanks!</p>
  
  <p>The code (h/t Alex, <a href="https://stackoverflow.com/questions/8841068/java-printing-program-output-to-a-physical-printer">Java: Printing program output to a physical printer</a>):</p>
  
  <pre><code>public int print(Graphics g, PageFormat pf, int page, Check c){
      final double MILLIMETER_IN_PIXELS = 3.779527559;
      DecimalFormat df = new DecimalFormat("$#.00");
  
      if (page &gt; 0) {
          return NO_SUCH_PAGE;
      }
  
      Graphics2D g2d = (Graphics2D) g;
      int x = (int) pf.getImageableX();
      int y = (int) pf.getImageableY();
      g2d.translate(x, y + .5);
  
      Font font = new Font("Courier New", Font.PLAIN, 10);
      g2d.setFont(font);
      FontMetrics metrics = g.getFontMetrics(font);
      g.drawString("CHECK #" + c.getCheckNumber(), ((int) MILLIMETER_IN_PIXELS* 55),((int) MILLIMETER_IN_PIXELS*15));
  
      int strWidth = SwingUtilities.computeStringWidth(metrics, df.format(c.getAppraisersAmount()));
      g.drawString(df.format(c.getAppraisersAmount()), ((int) ((MILLIMETER_IN_PIXELS*62)-strWidth)), ((int) MILLIMETER_IN_PIXELS*23));
  
      Date d = c.getJavaDate();
      SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
      g.drawString(sdf.format(d), ((int) MILLIMETER_IN_PIXELS*90), ((int) MILLIMETER_IN_PIXELS*24));
  
      strWidth = SwingUtilities.computeStringWidth(metrics, df.format(c.getCostAmount()));
      g.drawString(df.format(c.getCostAmount()), ((int) ((MILLIMETER_IN_PIXELS*62)-strWidth)), ((int) (MILLIMETER_IN_PIXELS*22)));
  
      strWidth = SwingUtilities.computeStringWidth(metrics, df.format(c.getRefundsAmount()));
      g.drawString(df.format(c.getRefundsAmount()), ((int) ((MILLIMETER_IN_PIXELS*62)-strWidth)), ((int) (MILLIMETER_IN_PIXELS*26)));        
  
      strWidth = SwingUtilities.computeStringWidth(metrics, df.format(c.getOfficersAmount()));
      g.drawString(df.format(c.getOfficersAmount()), ((int) ((MILLIMETER_IN_PIXELS*62)-strWidth)), ((int) (MILLIMETER_IN_PIXELS*30)));
  
      Double totalLeft = c.getAppraisersAmount() + c.getCostAmount() + c.getRefundsAmount() + c.getOfficersAmount();
      strWidth = SwingUtilities.computeStringWidth(metrics, df.format(totalLeft));
      g.drawString(df.format(totalLeft), ((int) ((MILLIMETER_IN_PIXELS*62)-strWidth)), ((int) (MILLIMETER_IN_PIXELS*44)));
  
      return PAGE_EXISTS;
  }
  </code></pre>