diff --git a/src/NPOI/SS/UserModel/DataFormatter.cs b/src/NPOI/SS/UserModel/DataFormatter.cs
index 379e903..97d7724 100644
--- a/src/NPOI/SS/UserModel/DataFormatter.cs
+++ b/src/NPOI/SS/UserModel/DataFormatter.cs
@@ -118,10 +118,10 @@ namespace NPOI.SS.UserModel
invalidDateTimeString = buf.ToString();
}
/** General FormatBase for whole numbers. */
- private static DecimalFormat generalWholeNumFormat = new DecimalFormat("0");
+ private static DecimalFormat generalWholeNumFormat = new DecimalFormat("0", true);
/** General FormatBase for decimal numbers. */
- private static DecimalFormat generalDecimalNumFormat = new DecimalFormat("#.##########");
+ private static DecimalFormat generalDecimalNumFormat = new DecimalFormat("#.##########", true);
/** A default FormatBase to use when a number pattern cannot be Parsed. */
private FormatBase defaultNumFormat;
diff --git a/src/NPOI/SS/Util/Format.cs b/src/NPOI/SS/Util/Format.cs
index 24c0445..21c7065 100644
--- a/src/NPOI/SS/Util/Format.cs
+++ b/src/NPOI/SS/Util/Format.cs
@@ -173,12 +173,20 @@ namespace NPOI.SS.Util
private string pattern;
+ private bool isGeneral;
+
public DecimalFormat(string pattern)
{
if (pattern.IndexOf("'", StringComparison.Ordinal) != -1)
throw new ArgumentException("invalid pattern");
this.pattern = pattern;
}
+
+ internal DecimalFormat(string pattern, bool isGeneral) : this(pattern)
+ {
+ this.isGeneral = isGeneral;
+ }
+
public string Pattern
{
get
@@ -194,19 +202,19 @@ namespace NPOI.SS.Util
}
public override string Format(object obj, CultureInfo culture)
{
- //invalide fraction
+ // Invalid fraction
pattern = RegexFraction.Replace(pattern, "/");
-
+ double n = Convert.ToDouble(obj, CultureInfo.InvariantCulture);
+
if (pattern.IndexOf("'", StringComparison.Ordinal) != -1)
- {
- //return ((double)obj).ToString();
- return Convert.ToDouble(obj, CultureInfo.InvariantCulture).ToString(culture);
- }
- else
- {
- return Convert.ToDouble(obj, CultureInfo.InvariantCulture).ToString(pattern, culture);
- //return ((double)obj).ToString(pattern) ;
- }
+ return n.ToString(culture);
+
+ // Excel displays in scientific notation if the cell form is General and there are 12 or more digits
+ // https://support.office.com/en-us/article/display-numbers-in-scientific-exponential-notation-f85a96c0-18a1-4249-81c3-e934cd2aae25
+ if (isGeneral && Math.Floor(Math.Log10(n) + 1) >= 12)
+ pattern = "E4";
+
+ return n.ToString(pattern, culture);
}
public override StringBuilder Format(object obj, StringBuilder toAppendTo, CultureInfo culture)
diff --git a/src/NPOI/SS/Util/SheetUtil.cs b/src/NPOI/SS/Util/SheetUtil.cs
index 1469e5f..ac368bd 100644
--- a/src/NPOI/SS/Util/SheetUtil.cs
+++ b/src/NPOI/SS/Util/SheetUtil.cs
@@ -36,7 +36,7 @@ namespace NPOI.SS.Util
// * but the docs say nothing about what particular character is used.
// * '0' looks to be a good choice.
// */
- private static char defaultChar = '0';
+ private const char defaultChar = '0';
// /**
// * This is the multiple that the font height is scaled by when determining the
@@ -300,19 +300,18 @@ namespace NPOI.SS.Util
ICellStyle style = cell.CellStyle;
CellType cellType = cell.CellType;
- IFont defaultFont = wb.GetFontAt((short)0);
- Font windowsFont = IFont2Font(defaultFont);
+
// for formula cells we compute the cell width for the cached formula result
if (cellType == CellType.Formula) cellType = cell.CachedFormulaResultType;
IFont font = wb.GetFontAt(style.FontIndex);
+ Font windowsFont = IFont2Font(font);
//AttributedString str;
//TextLayout layout;
double width = -1;
- using (Bitmap bmp = new Bitmap(1, 1))
- using (Graphics g = Graphics.FromImage(bmp))
+ using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
if (cellType == CellType.String)
{
@@ -324,7 +323,6 @@ namespace NPOI.SS.Util
//str = new AttributedString(txt);
//copyAttributes(font, str, 0, txt.length());
- windowsFont = IFont2Font(font);
if (rt.NumFormattingRuns > 0)
{
// TODO: support rich text fragments
@@ -345,11 +343,11 @@ namespace NPOI.SS.Util
// AffineTransform.getScaleInstance(1, fontHeightMultiple)
// );
double angle = style.Rotation * 2.0 * Math.PI / 360.0;
- SizeF sf = g.MeasureString(txt, windowsFont);
+ SizeF sf = MeasureString(g, txt, windowsFont);
double x1 = Math.Abs(sf.Height * Math.Sin(angle));
double x2 = Math.Abs(sf.Width * Math.Cos(angle));
double w = Math.Round(x1 + x2, 0, MidpointRounding.ToEven);
- width = Math.Max(width, (w / colspan / defaultCharWidth) * 2 + cell.CellStyle.Indention);
+ width = Math.Max(width, (w / colspan / defaultCharWidth) + cell.CellStyle.Indention);
//width = Math.Max(width,
// ((layout.getOutline(trans).getBounds().getWidth()/colspan)/defaultCharWidth) +
// cell.getCellStyle().getIndention());
@@ -359,8 +357,8 @@ namespace NPOI.SS.Util
//width = Math.Max(width,
// ((layout.getBounds().getWidth()/colspan)/defaultCharWidth) +
// cell.getCellStyle().getIndention());
- double w = Math.Round(g.MeasureString(txt, windowsFont).Width, 0, MidpointRounding.ToEven);
- width = Math.Max(width, (w / colspan / defaultCharWidth) * 2 + cell.CellStyle.Indention);
+ double w = Math.Round(MeasureString(g, txt, windowsFont).Width, 0, MidpointRounding.ToEven);
+ width = Math.Max(width, (w / colspan / defaultCharWidth) + cell.CellStyle.Indention);
}
}
}
@@ -388,7 +386,6 @@ namespace NPOI.SS.Util
String txt = sval + defaultChar;
//str = new AttributedString(txt);
//copyAttributes(font, str, 0, txt.length());
- windowsFont = IFont2Font(font);
//layout = new TextLayout(str.getIterator(), fontRenderContext);
if (style.Rotation != 0)
{
@@ -407,19 +404,19 @@ namespace NPOI.SS.Util
// ((layout.getOutline(trans).getBounds().getWidth()/colspan)/defaultCharWidth) +
// cell.getCellStyle().getIndention());
double angle = style.Rotation * 2.0 * Math.PI / 360.0;
- SizeF sf = g.MeasureString(txt, windowsFont);
+ SizeF sf = MeasureString(g, txt, windowsFont);
double x1 = sf.Height * Math.Sin(angle);
double x2 = sf.Width * Math.Cos(angle);
double w = Math.Round(x1 + x2, 0, MidpointRounding.ToEven);
- width = Math.Max(width, (w / colspan / defaultCharWidth) * 2 + cell.CellStyle.Indention);
+ width = Math.Max(width, (w / colspan / defaultCharWidth) + cell.CellStyle.Indention);
}
else
{
//width = Math.max(width,
// ((layout.getBounds().getWidth()/colspan)/defaultCharWidth) +
// cell.getCellStyle().getIndention());
- double w = Math.Round(g.MeasureString(txt, windowsFont).Width, 0, MidpointRounding.ToEven);
- width = Math.Max(width, (w * 1.0 / colspan / defaultCharWidth) * 2 + cell.CellStyle.Indention);
+ double w = Math.Round(MeasureString(g, txt, windowsFont).Width, 0, MidpointRounding.ToEven);
+ width = Math.Max(width, (w / colspan / defaultCharWidth) + cell.CellStyle.Indention);
}
}
}
@@ -449,14 +446,12 @@ namespace NPOI.SS.Util
IWorkbook wb = sheet.Workbook;
DataFormatter formatter = new DataFormatter();
- IFont defaultFont = wb.GetFontAt((short)0);
//str = new AttributedString((defaultChar));
//copyAttributes(defaultFont, str, 0, 1);
//layout = new TextLayout(str.Iterator, fontRenderContext);
//int defaultCharWidth = (int)layout.Advance;
- Font font = IFont2Font(defaultFont);
- int defaultCharWidth = TextRenderer.MeasureText("" + new String(defaultChar, 1), font).Width;
+ int defaultCharWidth = getDefaultCharWidth(wb);
//DummyEvaluator dummyEvaluator = new DummyEvaluator();
double width = -1;
@@ -491,14 +486,11 @@ namespace NPOI.SS.Util
IWorkbook wb = sheet.Workbook;
DataFormatter formatter = new DataFormatter();
- IFont defaultFont = wb.GetFontAt((short)0);
-
//str = new AttributedString((defaultChar));
//copyAttributes(defaultFont, str, 0, 1);
//layout = new TextLayout(str.Iterator, fontRenderContext);
//int defaultCharWidth = (int)layout.Advance;
- Font font = IFont2Font(defaultFont);
- int defaultCharWidth = TextRenderer.MeasureText("" + new String(defaultChar, 1), font).Width;
+ int defaultCharWidth = getDefaultCharWidth(wb);
double width = -1;
for (int rowIdx = firstRow; rowIdx <= lastRow; ++rowIdx)
@@ -662,15 +654,23 @@ namespace NPOI.SS.Util
public static int getDefaultCharWidth(IWorkbook wb)
{
- //TODO: Implement!
- return 1;
- //throw new NotImplementedException();
- //IFont defaultFont = wb.GetFontAt(0);
+ IFont defaultFont = wb.GetFontAt(0);
+ Font font = IFont2Font(defaultFont);
+ using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
+ {
+ double width = MeasureString(g, new string(defaultChar, 1), font).Width;
+ return (int)Math.Round(width, 0, MidpointRounding.ToEven);
+ }
+ }
+
+ private static SizeF MeasureString(Graphics g, string text, Font font)
+ {
+ var size = g.MeasureString(text, font);
- //IAttributedString str = new AttributedString(defaultChar.ToString());
- //copyAttributes(defaultFont, str, 0, 1);
- //ITextLayout layout = new TextLayout(str.getIterator(), fontRenderContext);
- //return (int)layout.getAdvance();
+ // MeasureString adds padding so we do this to remove it
+ // https://stackoverflow.com/a/11708952/1409101
+ var actualWidth = g.MeasureString(text + text, font).Width - size.Width;
+ return new SizeF(actualWidth, size.Height);
}
}
}
diff --git a/src/NPOI/TextRenderer.cs b/src/NPOI/TextRenderer.cs
deleted file mode 100644
index 513d454..0000000
--- a/src/NPOI/TextRenderer.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Drawing;
-
-namespace NPOI
-{
- /// Provides methods used to measure and render text. This class cannot be inherited.
- public sealed class TextRenderer
- {
- private TextRenderer()
- {
- }
-
- /// Provides the size, in pixels, of the specified text when drawn with the specified font.
- /// The text to measure.
- /// The to apply to the measured text.
- /// The , in pixels, of drawn on a single line with the specified . You can manipulate how the text is drawn by using one of the overloads that takes a parameter. For example, the default behavior of the is to add padding to the bounding rectangle of the drawn text to accommodate overhanging glyphs. If you need to draw a line of text without these extra spaces you should use the versions of and that take a and parameter. For an example, see .
- public static Size MeasureText(string text, Font font)
- {
- if (string.IsNullOrEmpty(text))
- {
- return Size.Empty;
- }
- Size result = new Size(19, 19);
- return result;
- }
- }
-}
\ No newline at end of file