Java tutorial
/** * Copyright (c) 2001-2002. Department of Family Medicine, McMaster University. All Rights Reserved. * This software is published under the GPL GNU General Public License. * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * This software was written for the * Department of Family Medicine * McMaster University * Hamilton * Ontario, Canada */ // javac -classpath .;..\lib\itext-1.01.jar -d . FrmPDFServlet.java // form/createpdf?__title=British+Columbia+Antenatal+Record+Part+1&__cfgfile=bcar1PrintCfgPg1&__cfgfile=bcar1PrintCfgPg2&__template=bcar1 package oscar.eform.util; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.List; import java.util.Properties; import javax.servlet.ServletContext; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JasperRunManager; import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource; import org.apache.log4j.Logger; import org.oscarehr.util.LoggedInInfo; import org.oscarehr.util.MiscUtils; import oscar.OscarProperties; import oscar.form.graphic.FrmGraphicFactory; import oscar.form.graphic.FrmPdfGraphic; import oscar.form.pdfservlet.FrmPDFPostValueProcessor; import oscar.form.pdfservlet.HsfoRxDataHolder; import oscar.util.ConcatPDF; import com.lowagie.text.Document; import com.lowagie.text.Element; import com.lowagie.text.Font; import com.lowagie.text.PageSize; import com.lowagie.text.Phrase; import com.lowagie.text.Rectangle; import com.lowagie.text.pdf.BaseFont; import com.lowagie.text.pdf.ColumnText; import com.lowagie.text.pdf.PdfContentByte; import com.lowagie.text.pdf.PdfImportedPage; import com.lowagie.text.pdf.PdfReader; import com.lowagie.text.pdf.PdfWriter; /** * * */ public class EFormPDFServlet extends HttpServlet { public static final String HSFO_RX_DATA_KEY = "hsfo.rx.data"; Logger log = Logger.getLogger(EFormPDFServlet.class); /** * * */ public EFormPDFServlet() { super(); } public void doGet(HttpServletRequest req, HttpServletResponse res) throws javax.servlet.ServletException, java.io.IOException { doPost(req, res); } /** * @param req HTTP request object * @param res HTTP response object */ public void doPost(HttpServletRequest req, HttpServletResponse res) throws javax.servlet.ServletException, java.io.IOException { ByteArrayOutputStream baosPDF = null; FileInputStream fis = null; File tmpFile = null; try { if (req.getParameter("multiple") != null) { ArrayList<Object> files = new ArrayList<Object>(); for (int x = 0; x < Integer.parseInt(req.getParameter("multiple")); x++) { baosPDF = generatePDFDocumentBytes(req, this.getServletContext(), x); tmpFile = File.createTempFile("formpdf", String.valueOf((int) Math.random() * 10000)); baosPDF.writeTo(new FileOutputStream(tmpFile)); files.add(tmpFile.getAbsolutePath()); tmpFile.deleteOnExit(); } tmpFile = File.createTempFile("formpdf", String.valueOf((int) Math.random() * 10000)); ConcatPDF.concat(files, tmpFile.getAbsolutePath()); } else { baosPDF = generatePDFDocumentBytes(req, this.getServletContext(), 0); tmpFile = File.createTempFile("formpdf", String.valueOf((int) Math.random() * 10000)); baosPDF.writeTo(new FileOutputStream(tmpFile)); } StringBuilder sbFilename = new StringBuilder(); sbFilename.append("filename_"); sbFilename.append(".pdf"); // set the Cache-Control header res.setHeader("Cache-Control", "max-age=0"); res.setDateHeader("Expires", 0); res.setContentType("application/pdf"); // The Content-disposition value will be inline StringBuilder sbContentDispValue = new StringBuilder(); sbContentDispValue.append("inline; filename="); //inline - display sbContentDispValue.append(sbFilename); res.setHeader("Content-disposition", sbContentDispValue.toString()); res.setContentLength((int) tmpFile.length()); ServletOutputStream sout = res.getOutputStream(); fis = new FileInputStream(tmpFile); byte[] buffer = new byte[64000]; int bytesRead = 0; while (true) { bytesRead = fis.read(buffer); if (bytesRead == -1) break; sout.write(buffer, 0, bytesRead); } } catch (Exception e) { res.setContentType("text/html"); PrintWriter writer = res.getWriter(); writer.println("Exception from: " + this.getClass().getName() + " " + e.getClass().getName() + "<br>"); writer.println("<pre>"); writer.println(e.getMessage()); writer.println("</pre>"); writer.close(); } finally { if (baosPDF != null) baosPDF.close(); if (fis != null) fis.close(); if (tmpFile != null) tmpFile.deleteOnExit(); } } // added by vic, hsfo private ByteArrayOutputStream generateHsfoRxPDF(HttpServletRequest req) { HsfoRxDataHolder rx = (HsfoRxDataHolder) req.getSession().getAttribute(HSFO_RX_DATA_KEY); JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(rx.getOutlines()); InputStream is = Thread.currentThread().getContextClassLoader() .getResourceAsStream("/oscar/form/prop/Hsfo_Rx.jasper"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { JasperRunManager.runReportToPdfStream(is, baos, rx.getParams(), ds); } catch (JRException e) { throw new RuntimeException(e); } return baos; } /** * the form txt file has lines in the form: * * For Checkboxes: * ie. ohip : left, 76, 193, 0, BaseFont.ZAPFDINGBATS, 8, \u2713 * requestParamName : alignment, Xcoord, Ycoord, 0, font, fontSize, textToPrint[if empty, prints the value of the request param] * NOTE: the Xcoord and Ycoord refer to the bottom-left corner of the element * * For single-line text: * ie. patientCity : left, 242, 261, 0, BaseFont.HELVETICA, 12 * See checkbox explanation * * For multi-line text (textarea) * ie. aci : left, 20, 308, 0, BaseFont.HELVETICA, 8, _, 238, 222, 10 * requestParamName : alignment, bottomLeftXcoord, bottomLeftYcoord, 0, font, fontSize, _, topRightXcoord, topRightYcoord, spacingBtwnLines * *NOTE: When working on these forms in linux, it helps to load the PDF file into gimp, switch to pt. coordinate system and use the mouse to find the coordinates. *Prepare to be bored! * * * @throws Exception */ protected ByteArrayOutputStream generatePDFDocumentBytes(final HttpServletRequest req, final ServletContext ctx, int multiple) throws Exception { // added by vic, hsfo if (HSFO_RX_DATA_KEY.equals(req.getParameter("__title"))) return generateHsfoRxPDF(req); String suffix = (multiple > 0) ? String.valueOf(multiple) : ""; ByteArrayOutputStream baosPDF = new ByteArrayOutputStream(); Document document = new Document(); PdfWriter writer = null; try { writer = PdfWriter.getInstance(document, baosPDF); String title = req.getParameter("__title" + suffix) != null ? req.getParameter("__title" + suffix) : "Unknown"; String template = req.getParameter("__template" + suffix) != null ? req.getParameter("__template" + suffix) + ".pdf" : ""; int numPages = 1; String pages = req.getParameter("__numPages" + suffix); if (pages != null) { numPages = Integer.parseInt(pages); } //load config files Properties[] printCfg = loadPrintCfg(req, suffix); Properties[][] graphicCfg = loadGraphicCfg(req, suffix, numPages); int cfgFileNo = printCfg == null ? 0 : printCfg.length; Properties props = new Properties(); getPrintPropValues(props, req, suffix); Properties measurements = new Properties(); //initialise measurement collections = a list of pages sections measurements List<List<List<String>>> xMeasurementValues = new ArrayList<List<List<String>>>(); List<List<List<String>>> yMeasurementValues = new ArrayList<List<List<String>>>(); for (int idx = 0; idx < numPages; ++idx) { MiscUtils.getLogger().debug("Adding page " + idx); xMeasurementValues.add(new ArrayList<List<String>>()); yMeasurementValues.add(new ArrayList<List<String>>()); } saveMeasurementValues(measurements, props, req, numPages, xMeasurementValues, yMeasurementValues); addDocumentProps(document, title, props); // create a reader for a certain document String propFilename = OscarProperties.getInstance().getProperty("eform_image", "") + "/" + template; PdfReader reader = null; try { reader = new PdfReader(propFilename); log.debug("Found template at " + propFilename); } catch (Exception dex) { log.warn("Cannot find template at : " + propFilename); } // retrieve the total number of pages int n = reader.getNumberOfPages(); // retrieve the size of the first page Rectangle pSize = reader.getPageSize(1); float height = pSize.getHeight(); PdfContentByte cb = writer.getDirectContent(); int i = 0; while (i < n) { document.newPage(); i++; PdfImportedPage page1 = writer.getImportedPage(reader, i); cb.addTemplate(page1, 1, 0, 0, 1, 0, 0); cb.setRGBColorStroke(0, 0, 255); // LEFT/CENTER/RIGHT, X, Y, if (i <= cfgFileNo) { writeContent(printCfg[i - 1], props, measurements, height, cb); } //end if there are print properties //graphic Properties[] tempPropertiesArray; if (i <= graphicCfg.length) { tempPropertiesArray = graphicCfg[i - 1]; MiscUtils.getLogger().debug("Plotting page " + i); } else { tempPropertiesArray = null; MiscUtils.getLogger().debug("Skipped Plotting page " + i); } //if there are properties to plot if (tempPropertiesArray != null) { MiscUtils.getLogger().debug("TEMP PROP LENGTH " + tempPropertiesArray.length); for (int k = 0; k < tempPropertiesArray.length; k++) { //initialise with measurement values which are mapped to config file by form get graphic function List<String> xDate, yHeight; if (xMeasurementValues.get(i - 1).size() > k && yMeasurementValues.get(i - 1).size() > k) { xDate = new ArrayList<String>(xMeasurementValues.get(i - 1).get(k)); yHeight = new ArrayList<String>(yMeasurementValues.get(i - 1).get(k)); } else { xDate = new ArrayList<String>(); yHeight = new ArrayList<String>(); } plotProperties(tempPropertiesArray[k], props, xDate, yHeight, height, cb, (k % 2 == 0)); } } //end: if there are properties to plot } } finally { if (document.isOpen()) document.close(); if (writer != null) writer.close(); } return baosPDF; } protected Properties getCfgProp(String cfgFilename) { Properties ret = new Properties(); String propFilename = OscarProperties.getInstance().getProperty("eform_image", "") + "/" + cfgFilename; InputStream is = null; try { log.debug("1Looking for the prop file! " + propFilename); is = new FileInputStream(propFilename); //getServletContext().getResourceAsStream(propFilename); if (is != null) { log.debug("2Found the prop file! " + cfgFilename); ret.load(is); is.close(); } } catch (Exception e) { log.warn("Can't find the prop file: " + cfgFilename); } finally { if (is != null) try { is.close(); } catch (IOException e) { log.warn("Cannot close FileInputStream"); } } return ret; } private Properties[] loadPrintCfg(HttpServletRequest req, String suffix) { Properties[] printCfg = null; int cfgFileNo; String[] cfgFile = req.getParameterValues("__cfgfile" + suffix); cfgFileNo = cfgFile == null ? 0 : cfgFile.length; if (cfgFileNo > 0) { printCfg = new Properties[cfgFileNo]; for (int idx2 = 0; idx2 < cfgFileNo; ++idx2) { cfgFile[idx2] += ".txt"; if (cfgFile[idx2].indexOf("/") > 0) { cfgFile[idx2] = ""; } printCfg[idx2] = getCfgProp(cfgFile[idx2]); } } return printCfg; } private Properties[][] loadGraphicCfg(HttpServletRequest req, String suffix, int numPages) { Properties[][] graphicCfg = new Properties[numPages][]; String[] cfgGraphicFile; String paramName; int cfgGraphicFileNo; for (int idx = 0; idx < numPages; ++idx) { if (idx == 0) { cfgGraphicFile = req.getParameterValues("__cfgGraphicFile" + suffix); } else { paramName = "__cfgGraphicFile" + String.valueOf(idx) + suffix; cfgGraphicFile = req.getParameterValues(paramName); } cfgGraphicFileNo = cfgGraphicFile == null ? 0 : cfgGraphicFile.length; if (cfgGraphicFileNo == 0) { graphicCfg[idx] = null; } else { graphicCfg[idx] = new Properties[cfgGraphicFileNo]; for (int idx2 = 0; idx2 < cfgGraphicFileNo; ++idx2) { cfgGraphicFile[idx2] += ".txt"; graphicCfg[idx][idx2] = getCfgProp(cfgGraphicFile[idx2]); } } } return graphicCfg; } private void getPrintPropValues(Properties props, HttpServletRequest req, String suffix) { StringBuilder temp = new StringBuilder(""); for (Enumeration<String> e = req.getParameterNames(); e.hasMoreElements();) { temp = new StringBuilder(e.nextElement().toString()); props.setProperty(temp.toString(), req.getParameter(temp.toString())); } if (req.getParameter("postProcessor" + suffix) != null) { String className = "oscar.form.pdfservlet." + req.getParameter("postProcessor" + suffix); try { FrmPDFPostValueProcessor pp = (FrmPDFPostValueProcessor) Class.forName(className).newInstance(); props = pp.process(props); } catch (Exception e) { //ignore } } String currentDate = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date()); int totalPages = 1; if (req.getParameter("multiple") != null) totalPages = Integer.parseInt(req.getParameter("multiple")); String currentUser = LoggedInInfo.loggedInInfo.get().loggedInProvider.getFormattedName(); String pg = suffix.length() == 0 || suffix.equals("0") ? "0" : suffix; String currentPage = String.valueOf(Integer.parseInt(pg) + 1); props.setProperty("total_pages", String.valueOf(totalPages)); props.setProperty("current_page", currentPage); props.setProperty("current_user", currentUser); props.setProperty("current_date", currentDate); props.setProperty("printer_info", "Printed on " + currentDate + " by " + currentUser + ": Page " + currentPage + " of " + totalPages); } private void saveMeasurementValues(Properties measurements, Properties props, HttpServletRequest req, int numPages, List<List<List<String>>> xMeasurementValues, List<List<List<String>>> yMeasurementValues) { StringBuilder temp = null; String tempValue = null; String elementNum = null; int page, section; int index, index2, index3; for (Enumeration<String> e = req.getAttributeNames(); e.hasMoreElements();) { temp = new StringBuilder(e.nextElement().toString()); measurements.setProperty(temp.toString(), req.getAttribute(temp.toString()).toString()); //for graphing measurements of height and weight //since we don't know how many there could be they cannot be defined in a config file //save them here so they can be added to the graph vectors below //naming convention of measurements is xVal_num_section_page, yVal_num_section_page //num uniquely identifies value so x num should = y num //section allows graphing of more than one measurement axis e.g. if top of page is different graph than bottom of page see rourke //page is the pdf page it should be plotted on if (temp.toString().startsWith("xVal_")) { MiscUtils.getLogger().debug("Processing " + temp.toString()); index = temp.indexOf("_"); index2 = temp.indexOf("_", index + 1); elementNum = temp.substring(index + 1, index2); index3 = temp.lastIndexOf("_"); section = Integer.parseInt(temp.substring(index2 + 1, index3)); page = Integer.parseInt(temp.substring(index3 + 1)); //page is zero based, numPages is not if (page >= numPages) { continue; } //if this is the first measurement of the section init array while (xMeasurementValues.get(page).size() <= section) { MiscUtils.getLogger().debug("Adding section " + section); List<List<String>> list = xMeasurementValues.get(page); list.add(new ArrayList<String>()); } while (yMeasurementValues.get(page).size() <= section) { List<List<String>> list = yMeasurementValues.get(page); list.add(new ArrayList<String>()); } xMeasurementValues.get(page).get(section).add((String) req.getAttribute(temp.toString())); MiscUtils.getLogger() .debug("Setting xMeasurementDate to " + (String) req.getAttribute(temp.toString())); temp = new StringBuilder("yVal_"); temp = temp.append(elementNum); temp = temp.append("_" + section); temp = temp.append("_" + page); MiscUtils.getLogger().debug("Key " + temp); tempValue = (String) req.getAttribute(temp.toString()); yMeasurementValues.get(page).get(section).add(tempValue); MiscUtils.getLogger().debug("Setting yMeasurementValue to " + tempValue); } else { props.setProperty(temp.toString(), req.getAttribute(temp.toString()).toString()); } } } private void addDocumentProps(Document document, String title, Properties props) { document.addTitle(title); document.addSubject(""); document.addKeywords("pdf, itext"); document.addCreator("OSCAR"); document.addAuthor(""); document.addHeader("Expires", "0"); // A0-A10, LEGAL, LETTER, HALFLETTER, _11x17, LEDGER, NOTE, B0-B5, ARCH_A-ARCH_E, FLSA // and FLSE // the following shows a temp way to get a print page size final String PAGESIZE = "printPageSize"; Rectangle pageSize = PageSize.LETTER; if ("PageSize.HALFLETTER".equals(props.getProperty(PAGESIZE))) pageSize = PageSize.HALFLETTER; if ("PageSize.A6".equals(props.getProperty(PAGESIZE))) pageSize = PageSize.A6; document.setPageSize(pageSize); document.open(); } private void writeContent(Properties printCfg, Properties props, Properties measurements, float height, PdfContentByte cb) throws Exception { for (Enumeration e = printCfg.propertyNames(); e.hasMoreElements();) { StringBuilder temp = new StringBuilder(e.nextElement().toString()); String[] cfgVal = printCfg.getProperty(temp.toString()).split(" *, *"); String[] fontType = null; int fontFlags = 0; if (cfgVal[4].indexOf(";") > -1) { fontType = cfgVal[4].split(";"); if (fontType[1].trim().equals("italic")) fontFlags = Font.ITALIC; else if (fontType[1].trim().equals("bold")) fontFlags = Font.BOLD; else if (fontType[1].trim().equals("bolditalic")) fontFlags = Font.BOLDITALIC; else fontFlags = Font.NORMAL; } else { fontFlags = Font.NORMAL; fontType = new String[] { cfgVal[4].trim() }; } String encoding = null; if (fontType[0].trim().equals("BaseFont.HELVETICA")) { fontType[0] = BaseFont.HELVETICA; encoding = BaseFont.CP1252; //latin1 encoding } else if (fontType[0].trim().equals("BaseFont.HELVETICA_OBLIQUE")) { fontType[0] = BaseFont.HELVETICA_OBLIQUE; encoding = BaseFont.CP1252; } else if (fontType[0].trim().equals("BaseFont.ZAPFDINGBATS")) { fontType[0] = BaseFont.ZAPFDINGBATS; encoding = BaseFont.ZAPFDINGBATS; } else { fontType[0] = BaseFont.COURIER; encoding = BaseFont.CP1252; } BaseFont bf = BaseFont.createFont(fontType[0], encoding, BaseFont.NOT_EMBEDDED); String propValue = props.getProperty(temp.toString()); //if not in regular config then check measurements if (propValue == null) { propValue = measurements.getProperty(temp.toString(), ""); } ColumnText ct = new ColumnText(cb); // write in a rectangle area if (cfgVal.length >= 9) { Font font = new Font(bf, Integer.parseInt(cfgVal[5].trim()), fontFlags); ct.setSimpleColumn(Integer.parseInt(cfgVal[1].trim()), (height - Integer.parseInt(cfgVal[2].trim())), Integer.parseInt(cfgVal[7].trim()), (height - Integer.parseInt(cfgVal[8].trim())), Integer.parseInt(cfgVal[9].trim()), (cfgVal[0].trim().equals("left") ? Element.ALIGN_LEFT : (cfgVal[0].trim().equals("right") ? Element.ALIGN_RIGHT : Element.ALIGN_CENTER))); ct.setText(new Phrase(12, propValue, font)); ct.go(); continue; } // draw line directly if (temp.toString().startsWith("__$line")) { cb.setRGBColorStrokeF(0f, 0f, 0f); cb.setLineWidth(Float.parseFloat(cfgVal[4].trim())); cb.moveTo(Float.parseFloat(cfgVal[0].trim()), Float.parseFloat(cfgVal[1].trim())); cb.lineTo(Float.parseFloat(cfgVal[2].trim()), Float.parseFloat(cfgVal[3].trim())); cb.stroke(); } else if (temp.toString().startsWith("__")) { cb.beginText(); cb.setFontAndSize(bf, Integer.parseInt(cfgVal[5].trim())); cb.showTextAligned( (cfgVal[0].trim().equals("left") ? PdfContentByte.ALIGN_LEFT : (cfgVal[0].trim().equals("right") ? PdfContentByte.ALIGN_RIGHT : PdfContentByte.ALIGN_CENTER)), (cfgVal.length >= 7 ? (cfgVal[6].trim()) : propValue), Integer.parseInt(cfgVal[1].trim()), (height - Integer.parseInt(cfgVal[2].trim())), 0); cb.endText(); } else { // write prop text cb.beginText(); cb.setFontAndSize(bf, Integer.parseInt(cfgVal[5].trim())); cb.showTextAligned( (cfgVal[0].trim().equals("left") ? PdfContentByte.ALIGN_LEFT : (cfgVal[0].trim().equals("right") ? PdfContentByte.ALIGN_RIGHT : PdfContentByte.ALIGN_CENTER)), (cfgVal.length >= 7 ? ((propValue.equals("") ? "" : cfgVal[6].trim())) : propValue), Integer.parseInt(cfgVal[1].trim()), (height - Integer.parseInt(cfgVal[2].trim())), 0); cb.endText(); } } } private void plotProperties(Properties tp, Properties props, List<String> xDate, List<String> yHeight, float height, PdfContentByte cb, boolean countEven) { StringBuilder temp = null; String tempValue = null; String className = null; String[] tempYcoords; int origX = 0; int origY = 0; Properties args = new Properties(); for (Enumeration e = tp.propertyNames(); e.hasMoreElements();) { temp = new StringBuilder(e.nextElement().toString()); tempValue = tp.getProperty(temp.toString()).trim(); if (temp.toString().equals("__finalEDB")) args.setProperty(temp.toString(), props.getProperty(tempValue)); else if (temp.toString().equals("__xDateScale")) args.setProperty(temp.toString(), props.getProperty(tempValue)); else if (temp.toString().equals("__dateFormat")) args.setProperty(temp.toString(), tempValue); else if (temp.toString().equals("__nMaxPixX")) args.setProperty(temp.toString(), tempValue); else if (temp.toString().equals("__nMaxPixY")) args.setProperty(temp.toString(), tempValue); else if (temp.toString().equals("__fStartX")) args.setProperty(temp.toString(), tempValue); else if (temp.toString().equals("__fEndX")) args.setProperty(temp.toString(), tempValue); else if (temp.toString().equals("__fStartY")) args.setProperty(temp.toString(), tempValue); else if (temp.toString().equals("__fEndY")) args.setProperty(temp.toString(), tempValue); else if (temp.toString().equals("__origX")) origX = Integer.parseInt(tempValue); else if (temp.toString().equals("__origY")) origY = Integer.parseInt(tempValue); else if (temp.toString().equals("__className")) className = tempValue; else { MiscUtils.getLogger() .debug("Adding xDate " + temp.toString() + " VAL: " + props.getProperty(temp.toString())); MiscUtils.getLogger() .debug("Adding yHeight " + tempValue + " VAL: " + props.getProperty(tempValue)); xDate.add(props.getProperty(temp.toString())); yHeight.add(props.getProperty(tempValue)); } } // end for read in from config file FrmPdfGraphic pdfGraph = FrmGraphicFactory.create(className); pdfGraph.init(args); Properties gProp = pdfGraph.getGraphicXYProp(xDate, yHeight); //draw the pic cb.setLineWidth(1.5f); if (countEven) { cb.setRGBColorStrokeF(0f, 0f, 255f); } else { cb.setRGBColorStrokeF(255f, 0f, 0f); } for (Enumeration e = gProp.propertyNames(); e.hasMoreElements();) { temp = new StringBuilder(e.nextElement().toString()); tempValue = gProp.getProperty(temp.toString(), ""); if (tempValue.equals("")) { continue; } tempYcoords = tempValue.split(","); for (int idx = 0; idx < tempYcoords.length; ++idx) { tempValue = tempYcoords[idx]; cb.circle((origX + Float.parseFloat(temp.toString())), (height - origY + Float.parseFloat(tempValue)), 1.5f); cb.stroke(); } } } }