Достижение: Добавлены скрипты и документация для релиза PDF Compressor.

- Добавлен release-body.md для подробных заметок о релизе на русском языке.
- Реализован release-gitea.ps1 для автоматизированного релиза Gitea с помощью PowerShell.
- Создан release-gitea.sh для автоматизированного релиза Gitea с помощью Bash.
- Добавлен release.sh для сборки и маркировки релизов с поддержкой нескольких платформ.
- Улучшен пользовательский интерфейс благодаря информативному логированию и обработке ошибок.
- Добавлена ​​поддержка переменных окружения и управления конфигурацией.
- Добавлена ​​функция создания архивов и загрузки ресурсов в Gitea.
This commit is contained in:
Dmitriy Fofanov
2025-11-05 09:33:12 +03:00
parent f328d67080
commit ec65cfd05a
43 changed files with 5792 additions and 2 deletions

View File

@@ -0,0 +1,145 @@
package compressors
import (
"fmt"
"os"
"github.com/unidoc/unipdf/v3/common"
"github.com/unidoc/unipdf/v3/model"
"github.com/unidoc/unipdf/v3/model/optimize"
"compressor/internal/domain/entities"
)
// UniPDFCompressor реализация компрессора с использованием UniPDF
type UniPDFCompressor struct{}
// NewUniPDFCompressor создает новый UniPDF компрессор
func NewUniPDFCompressor() *UniPDFCompressor {
return &UniPDFCompressor{}
}
// Compress сжимает PDF файл используя UniPDF библиотеку
func (u *UniPDFCompressor) Compress(inputPath, outputPath string, config *entities.CompressionConfig) (*entities.CompressionResult, error) {
fmt.Printf("🔄 Сжатие PDF с уровнем %d%% (UniPDF)...\n", config.Level)
// Инициализируем логгер
common.SetLogger(common.NewConsoleLogger(common.LogLevelInfo))
// Проверяем лицензионный ключ из конфигурации или переменной окружения
licenseKey := config.UniPDFLicenseKey
if licenseKey == "" {
licenseKey = os.Getenv("UNIDOC_LICENSE_API_KEY")
}
if licenseKey == "" {
return &entities.CompressionResult{
OriginalSize: 0,
Success: false,
Error: fmt.Errorf("UniPDF требует лицензионный ключ. Установите его в конфигурации или в переменной UNIDOC_LICENSE_API_KEY. Используйте алгоритм 'pdfcpu' для бесплатной обработки или получите ключ на https://cloud.unidoc.io"),
}, fmt.Errorf("UniPDF лицензия не настроена. Установите лицензионный ключ в конфигурации или используйте алгоритм 'pdfcpu'")
}
// Устанавливаем лицензионный ключ
fmt.Printf("🔑 Устанавливаем лицензионный ключ UniPDF...\n")
os.Setenv("UNIDOC_LICENSE_API_KEY", licenseKey) // Получаем исходный размер файла
originalInfo, err := os.Stat(inputPath)
if err != nil {
return nil, fmt.Errorf("ошибка получения информации об исходном файле: %w", err)
}
// Открываем исходный PDF файл
pdfReader, file, err := model.NewPdfReaderFromFile(inputPath, nil)
if err != nil {
return &entities.CompressionResult{
OriginalSize: originalInfo.Size(),
Success: false,
Error: err,
}, fmt.Errorf("ошибка открытия файла: %w", err)
}
defer file.Close()
// Создаем writer с оптимизацией
pdfWriter := model.NewPdfWriter()
// Настраиваем оптимизацию в зависимости от уровня сжатия
optimizer := optimize.New(optimize.Options{
CombineDuplicateDirectObjects: true,
CombineIdenticalIndirectObjects: true,
ImageUpperPPI: float64(150 - config.Level), // чем выше уровень, тем ниже PPI
ImageQuality: 100 - config.Level, // чем выше уровень, тем ниже качество
})
pdfWriter.SetOptimizer(optimizer)
// Копируем страницы
numPages, err := pdfReader.GetNumPages()
if err != nil {
return &entities.CompressionResult{
OriginalSize: originalInfo.Size(),
Success: false,
Error: err,
}, fmt.Errorf("ошибка получения количества страниц: %w", err)
}
for i := 1; i <= numPages; i++ {
page, err := pdfReader.GetPage(i)
if err != nil {
return &entities.CompressionResult{
OriginalSize: originalInfo.Size(),
Success: false,
Error: err,
}, fmt.Errorf("ошибка получения страницы %d: %w", i, err)
}
err = pdfWriter.AddPage(page)
if err != nil {
return &entities.CompressionResult{
OriginalSize: originalInfo.Size(),
Success: false,
Error: err,
}, fmt.Errorf("ошибка добавления страницы %d: %w", i, err)
}
}
// Сохраняем оптимизированный файл
outputFile, err := os.Create(outputPath)
if err != nil {
return &entities.CompressionResult{
OriginalSize: originalInfo.Size(),
Success: false,
Error: err,
}, fmt.Errorf("ошибка создания выходного файла: %w", err)
}
defer outputFile.Close()
err = pdfWriter.Write(outputFile)
if err != nil {
return &entities.CompressionResult{
OriginalSize: originalInfo.Size(),
Success: false,
Error: err,
}, fmt.Errorf("ошибка записи файла: %w", err)
}
// Получаем размер сжатого файла
compressedInfo, err := os.Stat(outputPath)
if err != nil {
return &entities.CompressionResult{
OriginalSize: originalInfo.Size(),
Success: false,
Error: err,
}, fmt.Errorf("ошибка получения информации о сжатом файле: %w", err)
}
result := &entities.CompressionResult{
OriginalSize: originalInfo.Size(),
CompressedSize: compressedInfo.Size(),
Success: true,
}
result.CalculateCompressionRatio()
fmt.Printf("✅ Сжатие завершено: %s\n", outputPath)
return result, nil
}