3

When generating a report with JasperReports, I am seeing weird borders drawn by the reporting engine. Sometimes the borders are drawn so that the lines jut out at 100% zoom level, as seen in this image. This means that when I attempt to draw a square textbox, it will not look like a square unless I zoom in to 150% for more. Here is an image showing the issue.

Bad Table

Am I doing something wrong when setting the border settings in iReport? How can I fix this problem?

4

1 回答 1

3

我有同样的问题。将表格导出为 PDF 并使用细表格边框时,单元格边框线似乎比表格边框高出一个像素。视觉伪影仅在某些 PDF 查看器中可见(它们在 Adob​​e Reader 中可见)并且仅在某些缩放级别下可见。在 PDF 查看器中打开或关闭线条艺术平滑时,伪影的外观会发生变化。如果您在最大级别上放大 overstrike,您会看到线条绘制正确 - 工件是由 PDF 查看器在缩放文档时制作的。

检查 JasperReports 代码时,我发现 PDF 导出将表格边框绘制为四个单行。它们的绘制没有大写(线在最后立即被切断)。以这种方式绘制方形边框时,角落不会完全连接,因此每条线都画得比边框稍长一些,以弥补缺少的帽子。这个算法对我来说似乎是正确的,但是在 Adob​​e Reader 中发生了一些事情,一些舍入和图像“改进”会导致出现图像伪影。

我能够想出一个解决方案来解决我的问题。我对 JRPdfExporter 进行了子类化并修改了绘制边框的代码。用法很简单,只需使用我的类而不是 JRPdfExporter。我使用 JasperReports 5.0.0。

package cz.jwa.jasper;

import java.awt.Color;

import net.sf.jasperreports.engine.JRLineBox;
import net.sf.jasperreports.engine.JRPen;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.legacy.BorderOffset;
import net.sf.jasperreports.engine.type.LineStyleEnum;

import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfContentByte;

public class JWAPdfExporter extends JRPdfExporter
{
  protected void exportBox(JRLineBox box, JRPrintElement element)
  {
    if(!isBoxVisible(box)) return;

    pdfContentByte.setLineCap(PdfContentByte.LINE_CAP_PROJECTING_SQUARE);    

    float x1 = element.getX() + getOffsetX();
    float y1 = jasperPrint.getPageHeight() - element.getY() - getOffsetY();
    float x2 = element.getX() + getOffsetX() + element.getWidth();
    float y2 = jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight(); 

    Rectangle r = new Rectangle(x1, y2, x2, y1);

    int borderFlag = 0;

    boolean same = true;

    float lineWidth = 0;
    Color lineColor = null;

    if(box.getLeftPen().getLineWidth().floatValue() > 0f)
    {
      borderFlag |= Rectangle.LEFT;
      lineWidth = box.getLeftPen().getLineWidth().floatValue();
      lineColor = box.getLeftPen().getLineColor(); 
    }

    if(box.getTopPen().getLineWidth().floatValue() > 0f)
    {
      borderFlag |= Rectangle.TOP;
      if(lineWidth == 0)
      {
        lineWidth = box.getTopPen().getLineWidth().floatValue();
        lineColor = box.getTopPen().getLineColor(); 
      }
      else if(lineWidth != box.getTopPen().getLineWidth().floatValue()
          || !lineColor.equals(box.getTopPen().getLineColor()))
      {
        same = false;
      }
    }

    if(box.getRightPen().getLineWidth().floatValue() > 0f)
    {
      borderFlag |= Rectangle.RIGHT;
      if(lineWidth == 0)
      {
        lineWidth = box.getRightPen().getLineWidth().floatValue();
        lineColor = box.getRightPen().getLineColor(); 
      }
      else if(lineWidth != box.getRightPen().getLineWidth().floatValue()
          || !lineColor.equals(box.getRightPen().getLineColor()))
      {
        same = false;
      }
    }

    if(box.getBottomPen().getLineWidth().floatValue() > 0f)
    {
      borderFlag |= Rectangle.BOTTOM;
      if(lineWidth == 0)
      {
        lineWidth = box.getBottomPen().getLineWidth().floatValue();
        lineColor = box.getBottomPen().getLineColor(); 
      }
      else if(lineWidth != box.getBottomPen().getLineWidth().floatValue()
          || !lineColor.equals(box.getBottomPen().getLineColor()))
      {
        same = false;
      }
    }

    if(same)
    {
      r.setBorder(borderFlag);
      r.setBorderColor(lineColor);
      r.setBorderWidth(lineWidth);

      pdfContentByte.rectangle(r);
      pdfContentByte.stroke();

      pdfContentByte.setLineDash(0.0F);
      pdfContentByte.setLineCap(PdfContentByte.LINE_CAP_PROJECTING_SQUARE);   
    }
    else
    {
      super.exportBox(box, element);
    }    
  }

  private boolean isBoxVisible(JRLineBox box)
  {
    return box.getLeftPen().getLineWidth().floatValue() > 0f 
        || box.getTopPen().getLineWidth().floatValue() > 0f
        || box.getRightPen().getLineWidth().floatValue() > 0f
        || box.getBottomPen().getLineWidth().floatValue() > 0f
        ;
  }

  protected void exportTopPen(
      JRPen topPen, 
      JRPen leftPen, 
      JRPen rightPen, 
      JRPrintElement element)
    {
      if (topPen.getLineWidth().floatValue() > 0f)
      {
        float leftOffset = 0; //leftPen.getLineWidth().floatValue() / 2 - BorderOffset.getOffset(leftPen);
        float rightOffset = 0; //rightPen.getLineWidth().floatValue() / 2 - BorderOffset.getOffset(rightPen);

        preparePen(pdfContentByte, topPen, PdfContentByte.LINE_CAP_BUTT);

        if (topPen.getLineStyleValue() == LineStyleEnum.DOUBLE)
        {
          float topOffset = topPen.getLineWidth().floatValue();

          pdfContentByte.moveTo(
            element.getX() + getOffsetX() - leftOffset,
            jasperPrint.getPageHeight() - element.getY() - getOffsetY() + topOffset / 3
            );
          pdfContentByte.lineTo(
            element.getX() + getOffsetX() + element.getWidth() + rightOffset,
            jasperPrint.getPageHeight() - element.getY() - getOffsetY() + topOffset / 3
            );
          pdfContentByte.stroke();

          pdfContentByte.moveTo(
            element.getX() + getOffsetX() + leftOffset / 3,
            jasperPrint.getPageHeight() - element.getY() - getOffsetY() - topOffset / 3
            );
          pdfContentByte.lineTo(
            element.getX() + getOffsetX() + element.getWidth() - rightOffset / 3,
            jasperPrint.getPageHeight() - element.getY() - getOffsetY() - topOffset / 3
            );
          pdfContentByte.stroke();
        }
        else
        {
          float topOffset =  BorderOffset.getOffset(topPen);
          pdfContentByte.moveTo(
            element.getX() + getOffsetX() - leftOffset,
            jasperPrint.getPageHeight() - element.getY() - getOffsetY() - topOffset
            );
          pdfContentByte.lineTo(
            element.getX() + getOffsetX() + element.getWidth() + rightOffset,
            jasperPrint.getPageHeight() - element.getY() - getOffsetY() - topOffset
            );
          pdfContentByte.stroke();
        }
      }
    }

  protected void exportLeftPen(JRPen topPen, JRPen leftPen, JRPen bottomPen, JRPrintElement element)
  {
    if (leftPen.getLineWidth().floatValue() > 0f)
    {
      float topOffset = 0; //topPen.getLineWidth().floatValue() / 2 - BorderOffset.getOffset(topPen);
      float bottomOffset = 0; //bottomPen.getLineWidth().floatValue() / 2 - BorderOffset.getOffset(bottomPen);

      preparePen(pdfContentByte, leftPen, PdfContentByte.LINE_CAP_BUTT);

      if (leftPen.getLineStyleValue() == LineStyleEnum.DOUBLE)
      {
        float leftOffset = leftPen.getLineWidth().floatValue();

        pdfContentByte.moveTo(
          element.getX() + getOffsetX() - leftOffset / 3,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() + topOffset
          );
        pdfContentByte.lineTo(
          element.getX() + getOffsetX() - leftOffset / 3,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() - bottomOffset
          );
        pdfContentByte.stroke();

        pdfContentByte.moveTo(
          element.getX() + getOffsetX() + leftOffset / 3,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - topOffset / 3
          );
        pdfContentByte.lineTo(
          element.getX() + getOffsetX() + leftOffset / 3,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() + bottomOffset / 3
          );
        pdfContentByte.stroke();
      }
      else
      {
        float leftOffset =  BorderOffset.getOffset(leftPen);
        pdfContentByte.moveTo(
          element.getX() + getOffsetX() + leftOffset,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() + topOffset
          );
        pdfContentByte.lineTo(
          element.getX() + getOffsetX() + leftOffset,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() - bottomOffset
          );
        pdfContentByte.stroke();
      }
    }
  }


  /**
   *
   */
  protected void exportBottomPen(JRPen leftPen, JRPen bottomPen, JRPen rightPen, JRPrintElement element)
  {
    if (bottomPen.getLineWidth().floatValue() > 0f)
    {
      float leftOffset = 0; //leftPen.getLineWidth().floatValue() / 2 - BorderOffset.getOffset(leftPen);
      float rightOffset = 0; //rightPen.getLineWidth().floatValue() / 2 - BorderOffset.getOffset(rightPen);

      preparePen(pdfContentByte, bottomPen, PdfContentByte.LINE_CAP_BUTT);

      if (bottomPen.getLineStyleValue() == LineStyleEnum.DOUBLE)
      {
        float bottomOffset = bottomPen.getLineWidth().floatValue();

        pdfContentByte.moveTo(
          element.getX() + getOffsetX() - leftOffset,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() - bottomOffset / 3
          );
        pdfContentByte.lineTo(
          element.getX() + getOffsetX() + element.getWidth() + rightOffset,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() - bottomOffset / 3
          );
        pdfContentByte.stroke();

        pdfContentByte.moveTo(
          element.getX() + getOffsetX() + leftOffset / 3,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() + bottomOffset / 3
          );
        pdfContentByte.lineTo(
          element.getX() + getOffsetX() + element.getWidth() - rightOffset / 3,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() + bottomOffset / 3
          );
        pdfContentByte.stroke();
      }
      else
      {
        float bottomOffset =  BorderOffset.getOffset(bottomPen);
        pdfContentByte.moveTo(
          element.getX() + getOffsetX() - leftOffset,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() + bottomOffset
          );
        pdfContentByte.lineTo(
          element.getX() + getOffsetX() + element.getWidth() + rightOffset,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() + bottomOffset
          );
        pdfContentByte.stroke();
      }
    }
  }


  /**
   *
   */
  protected void exportRightPen(JRPen topPen, JRPen bottomPen, JRPen rightPen, JRPrintElement element)
  {
    if (rightPen.getLineWidth().floatValue() > 0f)
    {
      float topOffset = 0; //topPen.getLineWidth().floatValue() / 2 - BorderOffset.getOffset(topPen);
      float bottomOffset = 0; //bottomPen.getLineWidth().floatValue() / 2 - BorderOffset.getOffset(bottomPen);

      preparePen(pdfContentByte, rightPen, PdfContentByte.LINE_CAP_BUTT);

      if (rightPen.getLineStyleValue() == LineStyleEnum.DOUBLE)
      {
        float rightOffset = rightPen.getLineWidth().floatValue();

        pdfContentByte.moveTo(
          element.getX() + getOffsetX() + element.getWidth() + rightOffset / 3,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() + topOffset
          );
        pdfContentByte.lineTo(
          element.getX() + getOffsetX() + element.getWidth() + rightOffset / 3,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() - bottomOffset
          );
        pdfContentByte.stroke();

        pdfContentByte.moveTo(
          element.getX() + getOffsetX() + element.getWidth() - rightOffset / 3,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - topOffset / 3
          );
        pdfContentByte.lineTo(
          element.getX() + getOffsetX() + element.getWidth() - rightOffset / 3,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() + bottomOffset / 3
          );
        pdfContentByte.stroke();
      }
      else
      {
        float rightOffset =  BorderOffset.getOffset(rightPen);
        pdfContentByte.moveTo(
          element.getX() + getOffsetX() + element.getWidth() - rightOffset,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() + topOffset
          );
        pdfContentByte.lineTo(
          element.getX() + getOffsetX() + element.getWidth() - rightOffset,
          jasperPrint.getPageHeight() - element.getY() - getOffsetY() - element.getHeight() - bottomOffset
          );
        pdfContentByte.stroke();
      }
    }
  }

  private static void preparePen(PdfContentByte pdfContentByte, JRPen pen, int lineCap)
  {
    float lineWidth = pen.getLineWidth().floatValue();

    if (lineWidth <= 0)
    {
      return;
    }

    pdfContentByte.setLineWidth(lineWidth);
    pdfContentByte.setLineCap(lineCap);

    Color color = pen.getLineColor();
    pdfContentByte.setRGBColorStroke(color.getRed(), color.getGreen(), color.getBlue());

    switch (pen.getLineStyleValue())
    {
      case DOUBLE:
      {
        pdfContentByte.setLineWidth(lineWidth / 3);
        pdfContentByte.setLineDash(0f);
        break;
      }
      case DOTTED:
      {
        switch (lineCap)
        {
          case PdfContentByte.LINE_CAP_BUTT:
          {
            pdfContentByte.setLineDash(lineWidth, lineWidth, 0f);
            break;
          }
          case PdfContentByte.LINE_CAP_PROJECTING_SQUARE:
          {
            pdfContentByte.setLineDash(0, 2 * lineWidth, 0f);
            break;
          }
        }
        break;
      }
      case DASHED:
      {
        switch (lineCap)
        {
          case PdfContentByte.LINE_CAP_BUTT:
          {
            pdfContentByte.setLineDash(5 * lineWidth, 3 * lineWidth, 0f);
            break;
          }
          case PdfContentByte.LINE_CAP_PROJECTING_SQUARE:
          {
            pdfContentByte.setLineDash(4 * lineWidth, 4 * lineWidth, 0f);
            break;
          }
        }
        break;
      }
      case SOLID:
      default:
      {
        pdfContentByte.setLineDash(0f);
        break;
      }
    }
  }
}
于 2014-01-02T16:37:46.170 回答