<commit_before>/*******************************************************************************
 * Copyright (c) 2004 Actuate Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.report.engine.emitter.pdf;

import java.awt.Color;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.birt.report.engine.api.EngineConstants;
import org.eclipse.birt.report.engine.api.IReportRunnable;
import org.eclipse.birt.report.engine.api.PDFRenderContext;
import org.eclipse.birt.report.engine.api.RenderOptionBase;
import org.eclipse.birt.report.engine.api.TOCNode;
import org.eclipse.birt.report.engine.content.IContent;
import org.eclipse.birt.report.engine.content.IHyperlinkAction;
import org.eclipse.birt.report.engine.content.IImageContent;
import org.eclipse.birt.report.engine.content.IReportContent;
import org.eclipse.birt.report.engine.content.IStyle;
import org.eclipse.birt.report.engine.css.engine.StyleConstants;
import org.eclipse.birt.report.engine.emitter.IEmitterServices;
import org.eclipse.birt.report.engine.layout.area.IArea;
import org.eclipse.birt.report.engine.layout.area.IAreaVisitor;
import org.eclipse.birt.report.engine.layout.area.IContainerArea;
import org.eclipse.birt.report.engine.layout.area.IImageArea;
import org.eclipse.birt.report.engine.layout.area.ITemplateArea;
import org.eclipse.birt.report.engine.layout.area.ITextArea;
import org.eclipse.birt.report.engine.layout.area.impl.PageArea;
import org.eclipse.birt.report.engine.layout.font.FontInfo;
import org.eclipse.birt.report.engine.layout.util.PropertyUtil;
import org.eclipse.birt.report.model.api.IResourceLocator;
import org.eclipse.birt.report.model.api.ReportDesignHandle;

import com.lowagie.text.BadElementException;
import com.lowagie.text.Chunk;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Font;
import com.lowagie.text.Image;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfAction;
import com.lowagie.text.pdf.PdfAnnotation;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfDestination;
import com.lowagie.text.pdf.PdfOutline;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;

/**
 * used to output the area tree in PDF file.
 * 
 * the objects passed in must be formated. Any unformated object
 * will be discarded.
 * 
 * @version $Revision$ $Date$
 */
public class PDFEmitter implements IAreaVisitor
{
	/**
	 * the default output pdf file name
	 */
	public static final String REPORT_FILE = "Report.pdf"; //$NON-NLS-1$
	
	/**
	 * the default image folder
	 */
	public static final String IMAGE_FOLDER = "image"; //$NON-NLS-1$
	
	/**
	 * the output stream
	 */
	private OutputStream output = null;
	
	/**
	 * the emitter configturation
	 */
	//private PDFEmitterConfig ec = null;
	
	/**
	 * The ratio of layout measure to iText measure
	 */
	public static final float LAYOUT_TO_PDF_RATIO = 1000f;
	
	/**
	 * the pdf Document object created by iText
	 */
	private Document doc = null;

	/**
	 * the Pdf Writer
	 */
	private PdfWriter writer = null;
	
	/**
	 * template for totalpage
	 * */
	private PdfTemplate tpl = null;
	private int tplWidth =0;
	private int tplHeight =0;

	/**
	 * contentByte layer for pdf;
	 * cb covers cbUnder.
	 */
	private PdfContentByte cb, cbUnder = null;

	/**
	 * the height and width of the current pdf page.
	 */
	private float pageHeight, pageWidth = 0f;
	
	/**
	 * the logger logging the error, debug, warning messages.
	 */
	protected static Logger logger = Logger.getLogger( PDFEmitter.class.getName( ) );
	
	protected IReportContent report;
	
	protected IReportRunnable reportRunnable;
	
	protected ReportDesignHandle reportDesign;
	
	protected PDFRenderContext context;
	
	private Stack containerStack = new Stack();
	
	private class ContainerPosition
	{
		private int x;
		private int y;
		public ContainerPosition(int x, int y)
		{
			this.x = x;
			this.y = y;
		}
	}
	
	/**
	 * get the output format. here it returns "pdf".
	 */
	public String getOutputFormat()
	{
		return RenderOptionBase.OUTPUT_FORMAT_PDF;
	}

	/**
	 * initialize the pdfEmitter
	 */
	public void initialize(IEmitterServices services)
	{
		//get the output file name from RenderOptionBase.OUTPUT_FILE_NAME.
		//It has the top preference.
		this.reportRunnable = services.getReportRunnable();
		if (reportRunnable != null)
		{
			reportDesign = (ReportDesignHandle)reportRunnable.getDesignHandle();
		}
		Object renderContext = services.getRenderContext();
		if(renderContext!=null && renderContext instanceof Map)
		{
			Object con = ((Map)renderContext).get(EngineConstants.APPCONTEXT_PDF_RENDER_CONTEXT);
			if(con instanceof PDFRenderContext)
			{
				this.context = (PDFRenderContext)con;
			}
		}
		Object fd = services.getOption( RenderOptionBase.OUTPUT_FILE_NAME );
		File file = null;
		try
		{
			if( fd != null )
			{
				file = new File(fd.toString());
				output = new FileOutputStream( file );
			}
		}
		catch( FileNotFoundException fnfe )
		{
			logger.log( Level.WARNING, fnfe.getMessage( ), fnfe );
		}
		
		//while failed to get the outputStream from the output file name specified
		//from RenderOptionBase.OUTPUT_FILE_NAME, use RenderOptionBase.OUTPUT_STREAM
		//to build the outputStream
		if( output == null )
		{
			Object value = services.getOption( RenderOptionBase.OUTPUT_STREAM );
			if( value != null && value instanceof OutputStream )
			{
				output = ( OutputStream ) value;
			}
			
			//if the RenderOptionBase.OUTPUT_STREAM is NOT set, build the outputStream from the
			//REPORT_FILE param defined in this file.
			else
			{
				try
				{<commit_msg>Fix Bugzilla Bug 137817--NPE while generating PDF report<commit_after>/*******************************************************************************
 * Copyright (c) 2004 Actuate Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.report.engine.emitter.pdf;

import java.awt.Color;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.birt.report.engine.api.EngineConstants;
import org.eclipse.birt.report.engine.api.IReportRunnable;
import org.eclipse.birt.report.engine.api.PDFRenderContext;
import org.eclipse.birt.report.engine.api.RenderOptionBase;
import org.eclipse.birt.report.engine.api.TOCNode;
import org.eclipse.birt.report.engine.content.IContent;
import org.eclipse.birt.report.engine.content.IHyperlinkAction;
import org.eclipse.birt.report.engine.content.IImageContent;
import org.eclipse.birt.report.engine.content.IReportContent;
import org.eclipse.birt.report.engine.content.IStyle;
import org.eclipse.birt.report.engine.css.engine.StyleConstants;
import org.eclipse.birt.report.engine.emitter.IEmitterServices;
import org.eclipse.birt.report.engine.layout.area.IArea;
import org.eclipse.birt.report.engine.layout.area.IAreaVisitor;
import org.eclipse.birt.report.engine.layout.area.IContainerArea;
import org.eclipse.birt.report.engine.layout.area.IImageArea;
import org.eclipse.birt.report.engine.layout.area.ITemplateArea;
import org.eclipse.birt.report.engine.layout.area.ITextArea;
import org.eclipse.birt.report.engine.layout.area.impl.PageArea;
import org.eclipse.birt.report.engine.layout.font.FontInfo;
import org.eclipse.birt.report.engine.layout.util.PropertyUtil;
import org.eclipse.birt.report.model.api.IResourceLocator;
import org.eclipse.birt.report.model.api.ReportDesignHandle;

import com.lowagie.text.BadElementException;
import com.lowagie.text.Chunk;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Font;
import com.lowagie.text.Image;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfAction;
import com.lowagie.text.pdf.PdfAnnotation;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfDestination;
import com.lowagie.text.pdf.PdfOutline;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;

/**
 * used to output the area tree in PDF file.
 * 
 * the objects passed in must be formated. Any unformated object
 * will be discarded.
 * 
 * @version $Revision$ $Date$
 */
public class PDFEmitter implements IAreaVisitor
{
	/**
	 * the default output pdf file name
	 */
	public static final String REPORT_FILE = "Report.pdf"; //$NON-NLS-1$
	
	/**
	 * the default image folder
	 */
	public static final String IMAGE_FOLDER = "image"; //$NON-NLS-1$
	
	/**
	 * the output stream
	 */
	private OutputStream output = null;
	
	/**
	 * the emitter configturation
	 */
	//private PDFEmitterConfig ec = null;
	
	/**
	 * The ratio of layout measure to iText measure
	 */
	public static final float LAYOUT_TO_PDF_RATIO = 1000f;
	
	/**
	 * the pdf Document object created by iText
	 */
	private Document doc = null;

	/**
	 * the Pdf Writer
	 */
	private PdfWriter writer = null;
	
	/**
	 * template for totalpage
	 * */
	private PdfTemplate tpl = null;
	private int tplWidth =0;
	private int tplHeight =0;

	/**
	 * contentByte layer for pdf;
	 * cb covers cbUnder.
	 */
	private PdfContentByte cb, cbUnder = null;

	/**
	 * the height and width of the current pdf page.
	 */
	private float pageHeight, pageWidth = 0f;
	
	/**
	 * the logger logging the error, debug, warning messages.
	 */
	protected static Logger logger = Logger.getLogger( PDFEmitter.class.getName( ) );
	
	protected IReportContent report;
	
	protected IReportRunnable reportRunnable;
	
	protected ReportDesignHandle reportDesign;
	
	protected PDFRenderContext context;
	
	private Stack containerStack = new Stack();
	
	private class ContainerPosition
	{
		private int x;
		private int y;
		public ContainerPosition(int x, int y)
		{
			this.x = x;
			this.y = y;
		}
	}
	
	/**
	 * get the output format. here it returns "pdf".
	 */
	public String getOutputFormat()
	{
		return RenderOptionBase.OUTPUT_FORMAT_PDF;
	}

	/**
	 * initialize the pdfEmitter
	 */
	public void initialize(IEmitterServices services)
	{
		//get the output file name from RenderOptionBase.OUTPUT_FILE_NAME.
		//It has the top preference.
		this.reportRunnable = services.getReportRunnable();
		if (reportRunnable != null)
		{
			reportDesign = (ReportDesignHandle)reportRunnable.getDesignHandle();
		}
		Object renderContext = services.getRenderContext();
		if(renderContext!=null && renderContext instanceof Map)
		{
			Object con = ((Map)renderContext).get(EngineConstants.APPCONTEXT_PDF_RENDER_CONTEXT);
			if(con instanceof PDFRenderContext)
			{
				this.context = (PDFRenderContext)con;
			}
		}
		Object fd = services.getOption( RenderOptionBase.OUTPUT_FILE_NAME );
		File file = null;
		try
		{
			if( fd != null )
			{
				file = new File(fd.toString());
				File parent = file.getParentFile( );
				if ( parent != null && !parent.exists( ) )
				{
					parent.mkdirs( );
				}
				output = new FileOutputStream( file );
			}
		}
		catch( FileNotFoundException fnfe )
		{
			logger.log( Level.WARNING, fnfe.getMessage( ), fnfe );
		}
		
		//while failed to get the outputStream from the output file name specified
		//from RenderOptionBase.OUTPUT_FILE_NAME, use RenderOptionBase.OUTPUT_STREAM
		//to build the outputStream
		if( output == null )
		{
			Object value = services.getOption( RenderOptionBase.OUTPUT_STREAM );
			if( value != null && value instanceof OutputStream )
			{
				output = ( OutputStream ) value;
			}
			
			//if the RenderOptionBase.OUTPUT_STREAM is NOT set, build the outputStream from the
			//REPORT_FILE param defined in this file.
			else
			{
				try
				{
{'fraction_non_alphanumeric': 0.12703408044212466, 'fraction_numerical': 0.003070310101320233, 'mean_word_length': 4.149802371541502, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5665808', 'n_tokens_mistral': 4317, 'n_tokens_neox': 3957, 'n_words': 965}