Полное руководство по размеру шрифтов в Excel PDF
Узнайте, как исправить проблемы с размером шрифтов при конвертации файлов Excel в PDF с использованием ClosedXML и iTextSharp. Найдите решения для расчета ширины столбцов, внедрения шрифтов и правильного размещения текста в ячейках PDF.
Проблема с преобразованием Excel в PDF: изменение размера текста с использованием ClosedXML и iTextSharp
Я столкнулся с проблемой изменения размера текста при преобразовании файла Excel в PDF с использованием ClosedXML и iTextSharp. Моя цель - обеспечить идеальное соответствие текста внутри каждой ячейки, но иногда текст изменяется некорректно. Интересно, что когда я отключаю изменение размера, текст фактически правильно помещается внутри ячейки.
Текущая реализация
Вот мой текущий код для обработки ширины столбцов и размера текста:
Dim colWidthsExcel As New List(Of Double)
For c As Integer = firstColNum To lastColNum
Dim widthCol As Double = worksheet.Column(c).Width
If widthCol <= 0 Then widthCol = 1
widthCol = widthCol
colWidthsExcel.Add(widthCol)
Next
Dim sumWidths As Double = colWidthsExcel.Sum()
Dim availablePageWidth As Single = document.PageSize.Width - document.LeftMargin - document.RightMargin
Dim colWidthsPoints(colCount - 1) As Single
For i As Integer = 0 To colCount - 1
colWidthsPoints(i) = CSng((colWidthsExcel(i) / sumWidths) * availablePageWidth)
Next
For row As Integer = firstRowNum To lastRowNum
For col As Integer = firstColNum To lastColNum
Dim cell = worksheet.Cell(row, col)
If cell Is Nothing Then Continue For
Dim idx = col - firstColNum
Dim cellWidth As Single = 40.0F
If idx >= 0 AndAlso idx < colWidthsPoints.Length Then
If cell.IsMerged() Then
Dim mRange As IXLRange = cell.MergedRange()
Dim spanCols As Integer = Math.Max(1, mRange.ColumnCount())
cellWidth = 0
For k As Integer = idx To Math.Min(idx + spanCols - 1, colWidthsPoints.Length - 1)
cellWidth += colWidthsPoints(k)
Next
Else
cellWidth = colWidthsPoints(idx)
End If
End If
Dim cellPadding As Single = 4.0F ' Внутренний отступ ячейки PDF (2 точки с каждой стороны)
Dim availableWidth As Single = cellWidth - cellPadding
Dim text As String = cell.GetFormattedString().Trim()
Dim fx = cell.Style.Font
Dim cellsize As Single = cell.Style.Font.FontSize * scaleFactor
Dim pdfFont As iTextSharp.text.Font = getFont(cell, cellsize)
Dim baseFont As iTextSharp.text.pdf.BaseFont = pdfFont.BaseFont
If baseFont Is Nothing Then
baseFont = iTextSharp.text.pdf.BaseFont.CreateFont(iTextSharp.text.pdf.BaseFont.HELVETICA, iTextSharp.text.pdf.BaseFont.CP1252, iTextSharp.text.pdf.BaseFont.NOT_EMBEDDED)
End If
Dim size As Single = GetFittingFontSize_SingleLine(baseFont:=baseFont, text:=text, cellSize:=cellsize, availableWidth:=availableWidth, isWrapCell:=cell.Style.Alignment.WrapText)
Next
Next
Private Function GetFittingFontSize_SingleLine(baseFont As iTextSharp.text.pdf.BaseFont, text As String, cellSize As Single, availableWidth As Single, isWrapCell As Boolean, Optional minSize As Single = 2.0F, Optional stepSize As Single = 0.5F) As Single
If String.IsNullOrEmpty(text) OrElse isWrapCell Then
Return cellSize
End If
Dim size As Single = cellSize
While size > minSize
getMinValuelStep05(size)
Dim textWidth As Single = baseFont.GetWidthPoint(text, size)
If textWidth <= availableWidth Then Exit While
size -= stepSize
End While
If size < minSize Then size = minSize
Return size
End Function
Проблема
Несмотря на реализацию этой логики, текст иногда изменяется некорректно при преобразовании Excel в PDF. Когда я отключаю функцию изменения размера, текст правильно помещается внутри ячейки. Это указывает на возможную проблему с моими вычислениями размера шрифта или определения ширины.
Вопрос
Что может вызывать некорректное изменение размера текста в моем преобразовании Excel в PDF с использованием ClosedXML и iTextSharp? Есть ли какие-либо проблемы в моем вычислении ширины столбцов или логике изменения размера шрифта, которые мне следует исправить?
Проблемы с изменением размера текста при преобразовании Excel в PDF с использованием ClosedXML и iTextSharp
Проблемы с изменением размера текста при преобразовании Excel в PDF с использованием ClosedXML и iTextSharp обычно связаны с несколькими распространенными проблемами в расчетах шрифтов, определении ширины и обработке шрифтов. Ваша реализация имеет несколько областей, которые могут вызывать некорректное поведение изменения размера, которое вы наблюдаете.
Основные проблемы, скорее всего, связаны с неправильными расчетами ширины шрифта, некорректным масштабированием ширины столбцов из единиц Excel в единицы PDF, несоответствиями встраивания шрифтов и недостаточной обработкой отступов ячеек и полей.
Содержание
- Основные причины проблем с размером текста
- Проблемы с расчетом ширины столбцов
- Ошибки в расчетах размера шрифта
- Проблемы с встраиванием и сопоставлением шрифтов
- Рекомендуемые исправления и улучшения
- Альтернативные подходы
- Лучшие практики для преобразования Excel в PDF
Основные причины проблем с размером текста
Несколько факторов способствуют некорректному изменению размера текста при преобразовании Excel в PDF:
Неточности в расчетах ширины шрифта - Метод GetWidthPoint в iTextSharp вычисляет ширину строки, но он может не учитывать все характеристики шрифта, которые учитывает Excel. Согласно исследованиям на Stack Overflow, хотя BaseFont.getWidthPoint(String text, float fontSize) предоставляет ширину в пунктах, он может не идеально соответствовать рендеринг-движку Excel.
Несоответствия отступов ячеек и полей - Ваш код использует фиксированные отступы в 4 пункта, но отступы ячеек в Excel измеряются иначе и могут варьироваться в зависимости от границ и форматирования. Расчет доступной ширины может быть неверным, что приводит к чрезмерно агрессивному уменьшению шрифта.
Несогласованность масштабирования шрифта - Используемый вами scaleFactor может корректно не переводить между системой изменения размера шрифта Excel и пунктами PDF. Excel использует разные единицы и масштабирование, чем PDF, что требует тщательного преобразования.
Обработка объединенных ячеек - Ваш расчет ширины объединенных ячеек складывает ширины столбцов, но не учитывает, как Excel распределяет пространство в объединенных диапазонах, что может привести к неверным расчетам доступной ширины.
Проблемы с расчетом ширины столбцов
Ваш текущий расчет ширины столбцов имеет несколько проблем, которые могут вызывать затруднения:
Dim widthCol As Double = worksheet.Column(c).Width
If widthCol <= 0 Then widthCol = 1
Единицы ширины столбцов Excel - Ширины столбцов в Excel измеряются в символах, а не в пунктах. Ширина 8.43 в Excel представляет среднее количество символов, помещающихся в ширину столбца по умолчанию. Ваше преобразование в пункты должно корректно учитывать это.
Отсутствие учета шрифта - Расчеты ширины столбцов в Excel зависят от шрифта по умолчанию (обычно Calibri 11pt). При расчете доступной ширины следует использовать это как отправную точку, а не предполагать прямое преобразование.
Проблемы пропорционального распределения - Ваш текущий подход делит доступную ширину страницы пропорционально на основе ширин столбцов Excel, но это не учитывает ограничения страницы PDF, такие как поля, верхние и нижние колонтитулы, которые могут уменьшить фактическое доступное пространство.
Резервная фиксированная ширина ячейки - Резервное значение cellWidth = 40.0F для индексов вне границ может вызывать несогласованное изменение размера при добавлении или удалении столбцов из файла Excel.
Ошибки в расчетах размера шрифта
Функция GetFittingFontSize_SingleLine имеет несколько проблемных областей:
Private Function GetFittingFontSize_SingleLine(baseFont As iTextSharp.text.pdf.BaseFont, text As String, cellSize As Single, availableWidth As Single, isWrapCell As Boolean, Optional minSize As Single = 2.0F, Optional stepSize As Single = 0.5F) As Single
If String.IsNullOrEmpty(text) OrElse isWrapCell Then
Return cellSize
End If
Dim size As Single = cellSize
While size > minSize
getMinValuelStep05(size) ' Этот вызов метода вызывает подозрения
Dim textWidth As Single = baseFont.GetWidthPoint(text, size)
If textWidth <= availableWidth Then Exit While
size -= stepSize
End While
If size < minSize Then size = minSize
Return size
End Function
Вызов неопределенного метода - Вызов getMinValuelStep05(size) кажется неопределенным или неправильно названным, что может вызывать непредвиденное поведение или ошибки.
Неточный расчет ширины - Согласно документации iTextSharp, GetWidthPoint вычисляет ширину, но не учитывает метрики шрифта, такие как подъем (ascent) и спуск (descent), которые влияют на использование вертикального пространства.
Фиксированный размер шага - Использование фиксированного размера шага 0.5F может быть слишком агрессивным для некоторых шрифтов и слишком консервативным для других, что приводит к оптимальному изменению размера.
Отсутствие учета метрик шрифта - Расчет не учитывает ограничивающие рамки шрифта (bounding boxes) или кернинг, которые могут влиять на горизонтальное размещение текста.
Проблемы с встраиванием и сопоставлением шрифтов
Обработка шрифтов является распространенным источником проблем при преобразовании Excel в PDF:
Несоответство резервного шрифта - Ваш переход на Helvetica может не соответствовать исходному шрифту Excel, вызывая разные расчеты ширины:
If baseFont Is Nothing Then
baseFont = iTextSharp.text.pdf.BaseFont.CreateFont(iTextSharp.text.pdf.BaseFont.HELVETICA, iTextSharp.text.pdf.BaseFont.CP1252, iTextSharp.text.pdf.BaseFont.NOT_EMBEDDED)
End If
Проблемы с встраиванием шрифтов - Согласно исследованиям Document Solutions, шрифты должны быть правильно встроены, и путь к шрифту должен быть указан, особенно на системах, отличных от Windows.
Несоответства стилей шрифта - Стили шрифта Excel (жирный, курсив, подчеркивание) могут быть неправильно переведены в шрифты iTextSharp, что приводит к разным расчетам ширины.
Проблемы кодировки символов - Кодировка CP1252 может не поддерживать все символы в исходном файле Excel, вызывая расхождения в расчетах ширины.
Рекомендуемые исправления и улучшения
Вот конкретные исправления для решения проблем в вашей реализации:
Улучшенный расчет ширины столбцов
' Более точный расчет ширины столбца Excel в пунктах
Dim widthCol As Double = worksheet.Column(c).Width
If widthCol <= 0 Then widthCol = 1 ' Ширина по умолчанию
' Преобразование единиц символов Excel в пункты (используя шрифт по умолчанию как эталон)
' В Excel по умолчанию используется Calibri 11pt, средняя ширина символа составляет примерно 7 пунктов
Dim colWidthPoints As Single = CSng(widthCol * 7.0F) ' Более точное преобразование
colWidthsExcel.Add(colWidthPoints)
Улучшенная функция изменения размера шрифта
Private Function GetFittingFontSize_SingleLine(baseFont As iTextSharp.text.pdf.BaseFont, text As String, cellSize As Single, availableWidth As Single, isWrapCell As Boolean, Optional minSize As Single = 2.0F, Optional maxIterations As Integer = 20) As Single
If String.IsNullOrEmpty(text) OrElse isWrapCell Then
Return cellSize
End If
' Удаляем подозрительный вызов метода
Dim size As Single = cellSize
Dim iteration As Integer = 0
' Используем двоичный поиск для более эффективного изменения размера
Dim low As Single = minSize
Dim high As Single = cellSize
Dim bestFit As Single = minSize
While iteration < maxIterations AndAlso (high - low) > 0.1F
size = (low + high) / 2
Dim textWidth As Single = baseFont.GetWidthPoint(text, size)
If textWidth <= availableWidth Then
bestFit = size
low = size + 0.1F
Else
high = size - 0.1F
End If
iteration += 1
End While
Return bestFit
End Function
Лучшая обработка шрифтов
Private Function getFont(cell As IXLCell, targetSize As Single) As iTextSharp.text.Font
Try
Dim fx = cell.Style.Font
Dim fontName As String = fx.FontName
Dim fontStyle As iTextSharp.text.Font.FontStyle = iTextSharp.text.Font.NORMAL
If fx.Bold Then fontStyle = fontStyle Or iTextSharp.text.Font.BOLD
If fx.Italic Then fontStyle = fontStyle Or iTextSharp.text.Font.ITALIC
If fx.Underline Then fontStyle = fontStyle Or iTextSharp.text.Font.UNDERLINE
' Пытаемся более точно соответствовать шрифту Excel
Dim baseFont As iTextSharp.text.pdf.BaseFont
Try
' Сопоставляем распространенные шрифты Excel с эквивалентами iTextSharp
Select Case fontName.ToLower()
Case "arial", "arial narrow"
baseFont = iTextSharp.text.pdf.BaseFont.CreateFont(iTextSharp.text.pdf.BaseFont.HELVETICA, iTextSharp.text.pdf.BaseFont.WINANSI, iTextSharp.text.pdf.BaseFont.EMBEDDED)
Case "times new roman", "times"
baseFont = iTextSharp.text.pdf.BaseFont.CreateFont(iTextSharp.text.pdf.BaseFont.TIMES_ROMAN, iTextSharp.text.pdf.BaseFont.WINANSI, iTextSharp.text.pdf.BaseFont.EMBEDDED)
Case "courier new", "courier"
baseFont = iTextSharp.text.pdf.BaseFont.CreateFont(iTextSharp.text.pdf.BaseFont.COURIER, iTextSharp.text.pdf.BaseFont.WINANSI, iTextSharp.text.pdf.BaseFont.EMBEDDED)
Case Else
baseFont = iTextSharp.text.pdf.BaseFont.CreateFont(fontName, iTextSharp.text.pdf.BaseFont.WINANSI, iTextSharp.text.pdf.BaseFont.EMBEDDED)
End Select
Catch ex As Exception
' Переходим на Arial, если шрифт не найден
baseFont = iTextSharp.text.pdf.BaseFont.CreateFont(iTextSharp.text.pdf.BaseFont.HELVETICA, iTextSharp.text.pdf.BaseFont.WINANSI, iTextSharp.text.pdf.BaseFont.EMBEDDED)
End Try
Return New iTextSharp.text.Font(baseFont, targetSize, fontStyle)
Catch ex As Exception
Return New iTextSharp.text.Font(iTextSharp.text.pdf.BaseFont.HELVETICA, targetSize)
End Try
End Function
Альтернативные подходы
Если вы продолжаете испытывать проблемы с текущим подходом, рассмотрите эти альтернативы:
Использование коммерческих библиотек
Document Solutions for Excel - Согласно документации Document Solutions, эта библиотека предоставляет встроенное преобразование Excel в PDF с правильной обработкой шрифтов:
' Использование Document Solutions for Excel
Dim workbook = new Workbook()
workbook.Load("input.xlsx")
workbook.SaveAsPdf("output.pdf")
Корректировка расчета отступов ячеек
Вместо фиксированных отступов используйте динамические отступы, основанные на размере шрифта:
' Динамический расчет отступов
Dim paddingFactor As Single = 0.15F ' 15% от размера шрифта
Dim cellPadding As Single = CSng(cellsize * paddingFactor * 2) ' С обеих сторон
Рассмотрите возможность переноса текста
Для длинного текста рассмотрите возможность включения переноса текста вместо уменьшения шрифта:
If textWidth > availableWidth AndAlso text.Length > 10 Then
' Включаем перенос и используем исходный размер шрифта
Return cellSize
End If
Лучшие практики для преобразования Excel в PDF
Для обеспечения надежного преобразования Excel в PDF с правильным изменением размера текста:
Тестируйте с различными шрифтами - Разные шрифты имеют разные характеристики. Тестируйте ваше преобразование с Arial, Times New Roman и другими часто используемыми шрифтами.
Проверяйте встраивание шрифтов - Убедитесь, что все шрифты правильно встроены с помощью BaseFont.EMBEDDED для поддержания согласованности на разных системах.
Обрабатывайте крайние случаи - Учитывайте объединенные ячейки, скрытые столбцы и специальные символы, которые могут влиять на расчеты ширины.
Используйте подходящие единицы измерения - Будьте последовательны в использовании пунктов во всем процессе преобразования.
Учитывайте производительность - Подход с двоичным поиском для изменения размера шрифта более эффективен, чем линейный поиск, особенно для больших документов.
Тестируйте на разных системах - Рендеринг шрифтов может различаться в средах Windows, macOS и Linux.
Устраняя эти проблемы в расчетах изменения размера шрифта, определении ширины столбцов и обработке шрифтов, вы должны решить проблемы некорректного изменения размера текста в вашем преобразовании Excel в PDF с использованием ClosedXML и iTextSharp.
Источники
- Stack Overflow - Расчет ширины строки с использованием BaseFont.GetWidthPoint
- Документация iTextSharp - Расчет ширины шрифта
- Document Solutions for Excel - Преобразование Excel в PDF
- Stack Overflow - Проблемы с преобразованием ширины из XLSX (Closed XML) в PDF (iTextSharp)
- Документация iTextSharp - Автоматическая корректировка размера шрифта
- Примеры кода C# - Использование BaseFont.GetWidthPoint
Заключение
Основные проблемы, вызывающие некорректное изменение размера текста в вашем преобразовании Excel в PDF, включают:
Неточности в расчетах ширины шрифта - Метод GetWidthPoint должен использоваться с правильными метриками шрифта и учетом характеристик шрифта по умолчанию в Excel.
Проблемы преобразования ширины столбцов - Ширины столбцов Excel, измеряемые в символах, требуют точного преобразования в пункты PDF с использованием шрифта по умолчанию как эталона.
Проблемы с встраиванием и сопоставлением шрифтов - Правильное сопоставление и встраивание шрифтов критически важны для поддержания согласованности изменения размера на разных системах.
Неэффективность алгоритма - Подход с линейным поиском в вашей функции изменения размера шрифта можно улучшить с помощью двоичного поиска для лучшей производительности и точности.
Реализуя рекомендуемые исправления, особенно улучшая расчет ширины столбцов, совершенствуя алгоритм изменения размера шрифта и обеспечивая правильное встраивание и сопоставление шрифтов, вы должны добиться согласованного и точного изменения размера текста в ваших преобразованиях Excel в PDF. Всегда тестируйте с различными шрифтами и крайними случаями для обеспечения надежной работы на разных файлах Excel и в системных средах.