Browse Source

PDFNumber.doubleOut() rewritten using java.text.DecimalFormat.

This fixes a bug of doubleOut() not recognizing the scientific format sometimes returned by Double.toString(double).
This change may result in slightly different value being written to the PDF stream. The former doubleOut contained specific code to do special rounding where the new method using DecimalFormat implicitly uses the BigDecimal.ROUND_HALF_EVEN strategy when rounding. These different values hopefully won't make a big visual difference. They don't in my tests.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@265688 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-0_90-alpha1
Jeremias Maerki 19 years ago
parent
commit
64701bbb87

+ 28
- 52
src/java/org/apache/fop/pdf/PDFNumber.java View File

@@ -18,6 +18,12 @@
package org.apache.fop.pdf;

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;

import com.sun.corba.se.internal.orbutil.Lock;

/**
* This class represents a simple number object. It also contains contains some
* utility methods for outputing numbers to PDF.
@@ -53,41 +59,20 @@ public class PDFNumber extends PDFObject {
}

/**
* Output a double value to a string suitable for PDF.
* Output a double value to a string suitable for PDF (6 decimal digits).
*
* @param doubleDown the double value
* @return the value as a string
*/
public static String doubleOut(double doubleDown) {
StringBuffer p = new StringBuffer();
if (doubleDown < 0) {
doubleDown = -doubleDown;
p.append("-");
}
double trouble = doubleDown % 1;

if (trouble > 0.950) {
p.append((int)doubleDown + 1);
} else if (trouble < 0.050) {
p.append((int)doubleDown);
} else {
String doubleString = new String(doubleDown + "");
int decimal = doubleString.indexOf(".");
if (decimal != -1) {
p.append(doubleString.substring(0, decimal));

if ((doubleString.length() - decimal) > 6) {
p.append(doubleString.substring(decimal, decimal + 6));
} else {
p.append(doubleString.substring(decimal));
}
} else {
p.append(doubleString);
}
}
return (p.toString());
return doubleOut(doubleDown, 6);
}

// Static cache. Possible concurrency implications. See comment in doubleOut(double, int).
private static DecimalFormat[] decimalFormatCache = new DecimalFormat[17];
private static final String BASE_FORMAT = "0.################";
/**
* Output a double value to a string suitable for PDF.
* In this method it is possible to set the maximum
@@ -98,33 +83,24 @@ public class PDFNumber extends PDFObject {
* @return the value as a string
*/
public static String doubleOut(double doubleDown, int dec) {
StringBuffer p = new StringBuffer();
if (doubleDown < 0) {
doubleDown = -doubleDown;
p.append("-");
if (dec < 0 || dec >= decimalFormatCache.length) {
throw new IllegalArgumentException("Parameter dec must be between 1 and "
+ (decimalFormatCache.length + 1));
}
double trouble = doubleDown % 1;

if (trouble > (1.0 - (5.0 / (Math.pow(10.0, dec))))) {
p.append((int)doubleDown + 1);
} else if (trouble < (5.0 / (Math.pow(10.0, dec)))) {
p.append((int)doubleDown);
} else {
String doubleString = new String(doubleDown + "");
int decimal = doubleString.indexOf(".");
if (decimal != -1) {
p.append(doubleString.substring(0, decimal));

if ((doubleString.length() - decimal) > dec) {
p.append(doubleString.substring(decimal, decimal + dec));
} else {
p.append(doubleString.substring(decimal));
}
} else {
p.append(doubleString);
if (decimalFormatCache[dec] == null) {
//We don't care about the rare case where a DecimalFormat might be replaced in
//a multi-threaded environment, so we don't synchronize the access to the static
//array (mainly for performance reasons). After all, the DecimalFormat instances
//read-only objects so it doesn't matter which instance is used as long as one
//is available.
String s = "0";
if (dec > 0) {
s = BASE_FORMAT.substring(0, dec + 2);
}
DecimalFormat df = new DecimalFormat(s, new DecimalFormatSymbols(Locale.US));
decimalFormatCache[dec] = df;
}
return (p.toString());
return decimalFormatCache[dec].format(doubleDown);
}

/**

+ 2
- 0
test/java/org/apache/fop/UtilityCodeTestSuite.java View File

@@ -20,6 +20,7 @@ package org.apache.fop;

import org.apache.fop.util.ASCII85InputStreamTestCase;
import org.apache.fop.util.ASCII85OutputStreamTestCase;
import org.apache.fop.util.PDFNumberTestCase;

import junit.framework.Test;
import junit.framework.TestSuite;
@@ -39,6 +40,7 @@ public class UtilityCodeTestSuite {
//$JUnit-BEGIN$
suite.addTest(new TestSuite(ASCII85OutputStreamTestCase.class));
suite.addTest(new TestSuite(ASCII85InputStreamTestCase.class));
suite.addTest(new TestSuite(PDFNumberTestCase.class));
//$JUnit-END$
return suite;
}

+ 113
- 0
test/java/org/apache/fop/util/PDFNumberTestCase.java View File

@@ -0,0 +1,113 @@
/*
* Copyright 2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.util;

import org.apache.fop.pdf.PDFNumber;

import junit.framework.TestCase;

/**
* This test tests PDFNumber's doubleOut() methods.
*/
public class PDFNumberTestCase extends TestCase {

/**
* Tests PDFNumber.doubleOut().
* @throws Exception if the test fails
*/
public void testDoubleOut1() throws Exception {
//Default is 6 decimal digits
assertEquals("0", PDFNumber.doubleOut(0.0f));
assertEquals("0", PDFNumber.doubleOut(0.0000000000000000000123f));
assertEquals("0.1", PDFNumber.doubleOut(0.1f));
assertEquals("100", PDFNumber.doubleOut(100.0f));
assertEquals("100", PDFNumber.doubleOut(99.99999999999999999999999f));
//You'd expect 100.123456 here but DecimalFormat uses the BigDecimal.ROUND_HALF_EVEN
//strategy. I don't know if that's a problem. The strange thing testDoubleOut2
//seems to return the normally expected value. Weird.
assertEquals("100.123459", PDFNumber.doubleOut(100.12345611111111f));
assertEquals("-100.123459", PDFNumber.doubleOut(-100.12345611111111f));
}
/**
* Tests PDFNumber.doubleOut().
* @throws Exception if the test fails
*/
public void testDoubleOut2() throws Exception {
//4 decimal digits in this case
assertEquals("0", PDFNumber.doubleOut(0.0f, 4));
assertEquals("0", PDFNumber.doubleOut(0.0000000000000000000123f, 4));
assertEquals("0.1", PDFNumber.doubleOut(0.1f, 4));
assertEquals("100", PDFNumber.doubleOut(100.0f, 4));
assertEquals("100", PDFNumber.doubleOut(99.99999999999999999999999f, 4));
assertEquals("100.1234", PDFNumber.doubleOut(100.12341111111111f, 4));
assertEquals("-100.1234", PDFNumber.doubleOut(-100.12341111111111f, 4));
}
/**
* Tests PDFNumber.doubleOut().
* @throws Exception if the test fails
*/
public void testDoubleOut3() throws Exception {
//0 decimal digits in this case
assertEquals("0", PDFNumber.doubleOut(0.0f, 0));
assertEquals("0", PDFNumber.doubleOut(0.1f, 0));
assertEquals("1", PDFNumber.doubleOut(0.6f, 0));
assertEquals("100", PDFNumber.doubleOut(100.1234f, 0));
assertEquals("-100", PDFNumber.doubleOut(-100.1234f, 0));
}
/**
* Tests PDFNumber.doubleOut(). Special cases (former bugs).
* @throws Exception if the test fails
*/
public void testDoubleOut4() throws Exception {
double d = Double.parseDouble("5.7220458984375E-6");
assertEquals("0.000006", PDFNumber.doubleOut(d));
assertEquals("0", PDFNumber.doubleOut(d, 4));
assertEquals("0.00000572", PDFNumber.doubleOut(d, 8));
}
/**
* Tests PDFNumber.doubleOut(). Tests for wrong parameters.
* @throws Exception if the test fails
*/
public void testDoubleOutWrongParameters() throws Exception {
try {
PDFNumber.doubleOut(0.1f, -1);
fail("IllegalArgument expected!");
} catch (IllegalArgumentException iae) {
//we want that
}
try {
PDFNumber.doubleOut(0.1f, 17); //We support max 16 decimal digits
fail("IllegalArgument expected!");
} catch (IllegalArgumentException iae) {
//we want that
}
try {
PDFNumber.doubleOut(0.1f, 98274659);
fail("IllegalArgument expected!");
} catch (IllegalArgumentException iae) {
//we want that
}
}
}

Loading…
Cancel
Save