46dce9a64b
DPI Limits * dpi * highlimit
152 lines
3.2 KiB
Go
152 lines
3.2 KiB
Go
package documentclean
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
|
|
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu"
|
|
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
|
|
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
|
|
)
|
|
|
|
type PDF struct {
|
|
pdf io.ReadSeeker
|
|
config *model.Configuration
|
|
maxPages int
|
|
maxBytes int64
|
|
maxDimension int
|
|
minDimension int
|
|
minDPI int
|
|
}
|
|
|
|
const (
|
|
TEXTRACT_SYNC_LIMIT int64 = 10 * 1024 * 1024
|
|
TEXTRACT_ASYNC_LIMIT int64 = 500 * 1024 * 1024
|
|
TEXTRACT_PAGE_LIMIT = 3000
|
|
TEXTRACT_MAX_DIMENSION = 10000
|
|
TEXTRACT_MIN_DIMENSION = 50
|
|
TEXTRACT_MIN_DPI = 72
|
|
PDF_DEFAULT_DPI = 72
|
|
)
|
|
|
|
func NewPDF(buf io.ReadSeeker) *PDF {
|
|
config := &model.Configuration{
|
|
ValidationMode: model.ValidationRelaxed,
|
|
Reader15: true,
|
|
Offline: true,
|
|
}
|
|
|
|
return &PDF{
|
|
pdf: buf,
|
|
config: config,
|
|
maxPages: TEXTRACT_PAGE_LIMIT,
|
|
maxBytes: TEXTRACT_SYNC_LIMIT,
|
|
maxDimension: TEXTRACT_MAX_DIMENSION,
|
|
minDimension: TEXTRACT_MIN_DIMENSION,
|
|
minDPI: TEXTRACT_MIN_DPI,
|
|
}
|
|
}
|
|
|
|
func (s *PDF) isCorrupt(ctx context.Context) *InvalidDocumentReason {
|
|
pdfCtx, err := pdfcpu.ReadWithContext(ctx, s.pdf, s.config)
|
|
if err != nil {
|
|
reason := InvalidDocumentRead
|
|
return &reason
|
|
}
|
|
|
|
if int64(pdfCtx.Read.ReadFileSize()) > s.maxBytes {
|
|
reason := InvalidDocumentLargeFile
|
|
return &reason
|
|
}
|
|
|
|
docErr := s.isValidPageCount(pdfCtx)
|
|
if docErr != nil {
|
|
return docErr
|
|
}
|
|
|
|
docErr = s.isValidDimensions(pdfCtx)
|
|
if docErr != nil {
|
|
return docErr
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *PDF) isValidPageCount(pdfCtx *model.Context) *InvalidDocumentReason {
|
|
err := pdfCtx.EnsurePageCount()
|
|
if err != nil {
|
|
reason := InvalidDocumentRead
|
|
return &reason
|
|
}
|
|
|
|
if pdfCtx.PageCount > s.maxPages {
|
|
reason := InvalidDocumentLargePageCount
|
|
return &reason
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *PDF) isValidDimensions(pdfCtx *model.Context) *InvalidDocumentReason {
|
|
err := pdfCtx.EnsurePageCount()
|
|
if err != nil {
|
|
reason := InvalidDocumentRead
|
|
return &reason
|
|
}
|
|
|
|
_, err = s.pdf.Seek(0, io.SeekStart)
|
|
if err != nil {
|
|
reason := InvalidDocumentRead
|
|
return &reason
|
|
}
|
|
|
|
pageSet := types.IntSet{}
|
|
for pageNum := 1; pageNum <= pdfCtx.PageCount; pageNum++ {
|
|
pageSet[pageNum] = true
|
|
}
|
|
|
|
boxes, err := pdfCtx.PageBoundaries(pageSet)
|
|
if err != nil {
|
|
reason := InvalidDocumentRead
|
|
return &reason
|
|
}
|
|
|
|
for _, box := range boxes {
|
|
mediaBox := box.MediaBox()
|
|
if mediaBox == nil {
|
|
continue
|
|
}
|
|
|
|
dims := mediaBox.Dimensions()
|
|
|
|
if dims.Height > float64(s.maxDimension) ||
|
|
dims.Width > float64(s.maxDimension) {
|
|
reason := InvalidDocumentLargeDimensions
|
|
return &reason
|
|
} else if dims.Height < float64(s.minDimension) ||
|
|
dims.Width < float64(s.minDimension) {
|
|
reason := InvalidDocumentSmallDimensions
|
|
return &reason
|
|
}
|
|
|
|
dpiErr := s.isValidDPI(mediaBox, dims)
|
|
if dpiErr != nil {
|
|
return dpiErr
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *PDF) isValidDPI(mediaBox *types.Rectangle, dims types.Dim) *InvalidDocumentReason {
|
|
widthDPI := mediaBox.Width() / dims.ToInches().Width
|
|
heightDPI := mediaBox.Height() / dims.ToInches().Height
|
|
|
|
if widthDPI < float64(s.minDPI) || heightDPI < float64(s.minDPI) {
|
|
reason := InvalidDocumentSmallDPI
|
|
return &reason
|
|
}
|
|
|
|
return nil
|
|
}
|