Merged in feature/dpi (pull request #80)

DPI Limits

* dpi

* highlimit
This commit is contained in:
Michael McGuinness
2025-02-28 17:36:53 +00:00
parent ae1abdb31f
commit 46dce9a64b
3 changed files with 206 additions and 0 deletions
+2
View File
@@ -29,6 +29,8 @@ const (
InvalidDocumentLargeFile InvalidDocumentReason = "large_file"
InvalidDocumentSmallDimensions InvalidDocumentReason = "small_dimensions"
InvalidDocumentLargeDimensions InvalidDocumentReason = "large_dimensions"
InvalidDocumentSmallDPI InvalidDocumentReason = "small_dpi"
InvalidDocumentLargeDPI InvalidDocumentReason = "large_dpi"
)
type ExecuteCleanResponse struct {
+21
View File
@@ -16,6 +16,7 @@ type PDF struct {
maxBytes int64
maxDimension int
minDimension int
minDPI int
}
const (
@@ -24,6 +25,8 @@ const (
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 {
@@ -40,6 +43,7 @@ func NewPDF(buf io.ReadSeeker) *PDF {
maxBytes: TEXTRACT_SYNC_LIMIT,
maxDimension: TEXTRACT_MAX_DIMENSION,
minDimension: TEXTRACT_MIN_DIMENSION,
minDPI: TEXTRACT_MIN_DPI,
}
}
@@ -124,6 +128,23 @@ func (s *PDF) isValidDimensions(pdfCtx *model.Context) *InvalidDocumentReason {
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
+183
View File
@@ -2,13 +2,138 @@ package documentclean
import (
"context"
"math"
"strings"
"testing"
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu"
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
"github.com/stretchr/testify/assert"
)
func TestIsValidDPI(t *testing.T) {
t.Run("no imgs", func(t *testing.T) {
ctx := context.Background()
pdf := NewPDF(strings.NewReader(pdfHelloWorld))
pdfCtx, err := pdfcpu.ReadWithContext(ctx, pdf.pdf, pdf.config)
assert.NoError(t, err)
err = pdfCtx.EnsurePageCount()
assert.NoError(t, err)
dims := types.Dim{
Width: TEXTRACT_MIN_DIMENSION,
Height: TEXTRACT_MIN_DIMENSION,
}
boxes, err := pdfCtx.PageBoundaries(types.IntSet{
1: true,
})
assert.NoError(t, err)
reason := pdf.isValidDPI(boxes[0].MediaBox(), dims)
assert.Nil(t, reason)
})
t.Run("with img", func(t *testing.T) {
ctx := context.Background()
pdf := NewPDF(strings.NewReader(pdfWithImg))
pdfCtx, err := pdfcpu.ReadWithContext(ctx, pdf.pdf, pdf.config)
assert.NoError(t, err)
err = pdfCtx.EnsurePageCount()
assert.NoError(t, err)
dims := types.Dim{
Width: TEXTRACT_MIN_DIMENSION,
Height: TEXTRACT_MIN_DIMENSION,
}
boxes, err := pdfCtx.PageBoundaries(types.IntSet{
1: true,
})
assert.NoError(t, err)
reason := pdf.isValidDPI(boxes[0].MediaBox(), dims)
assert.Nil(t, reason)
})
t.Run("with tiny dpi", func(t *testing.T) {
ctx := context.Background()
pdf := NewPDF(strings.NewReader(pdfWithImg))
pdfCtx, err := pdfcpu.ReadWithContext(ctx, pdf.pdf, pdf.config)
assert.NoError(t, err)
err = pdfCtx.EnsurePageCount()
assert.NoError(t, err)
dims := types.Dim{
Width: math.MaxFloat64,
Height: math.MaxFloat64,
}
boxes, err := pdfCtx.PageBoundaries(types.IntSet{
1: true,
})
assert.NoError(t, err)
reason := pdf.isValidDPI(boxes[0].MediaBox(), dims)
assert.Equal(t, InvalidDocumentSmallDPI, *reason)
})
t.Run("with tiny width dpi", func(t *testing.T) {
ctx := context.Background()
pdf := NewPDF(strings.NewReader(pdfWithImg))
pdfCtx, err := pdfcpu.ReadWithContext(ctx, pdf.pdf, pdf.config)
assert.NoError(t, err)
err = pdfCtx.EnsurePageCount()
assert.NoError(t, err)
dims := types.Dim{
Width: math.MaxFloat64,
Height: 1,
}
boxes, err := pdfCtx.PageBoundaries(types.IntSet{
1: true,
})
assert.NoError(t, err)
reason := pdf.isValidDPI(boxes[0].MediaBox(), dims)
assert.Equal(t, InvalidDocumentSmallDPI, *reason)
})
t.Run("with tiny height dpi", func(t *testing.T) {
ctx := context.Background()
pdf := NewPDF(strings.NewReader(pdfWithImg))
pdfCtx, err := pdfcpu.ReadWithContext(ctx, pdf.pdf, pdf.config)
assert.NoError(t, err)
err = pdfCtx.EnsurePageCount()
assert.NoError(t, err)
dims := types.Dim{
Width: 1,
Height: math.MaxFloat64,
}
boxes, err := pdfCtx.PageBoundaries(types.IntSet{
1: true,
})
assert.NoError(t, err)
reason := pdf.isValidDPI(boxes[0].MediaBox(), dims)
assert.Equal(t, InvalidDocumentSmallDPI, *reason)
})
t.Run("with huge dpi", func(t *testing.T) {
ctx := context.Background()
pdf := NewPDF(strings.NewReader(pdfWithImg))
pdfCtx, err := pdfcpu.ReadWithContext(ctx, pdf.pdf, pdf.config)
assert.NoError(t, err)
err = pdfCtx.EnsurePageCount()
assert.NoError(t, err)
dims := types.Dim{
Width: 1,
Height: 1,
}
boxes, err := pdfCtx.PageBoundaries(types.IntSet{
1: true,
})
assert.NoError(t, err)
reason := pdf.isValidDPI(boxes[0].MediaBox(), dims)
assert.Nil(t, reason)
})
}
func TestIsValidDimensions(t *testing.T) {
t.Run("valid", func(t *testing.T) {
ctx := context.Background()
@@ -871,3 +996,61 @@ trailer
startxref
612
%%EOF`
const pdfWithImg = `%PDF-1.7
1 0 obj
<</Type/Catalog/Pages 2 0 R>>
endobj
2 0 obj
<</Type/Pages/Kids[3 0 R]/Count 1>>
endobj
3 0 obj
<</Type/Page/Parent 2 0 R/Resources<</Font<</F1<</Type/Font/Subtype/Type1/BaseFont/Helvetica>>>>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/MediaBox[0 0 595 842]/Contents 4 0 R>>
endobj
4 0 obj
<</Length 534>>
stream
BT
/F1 12 Tf
50 750 Td
(This is the first line of a multiline string.) Tj
0 -15 Td
(This is the second line of text.) Tj
0 -15 Td
(Below this text will be an inline image.) Tj
ET
q
50 650 Td
BI
/W 500
/H 500
/BPC 8
/CS /RGB
/F [/DCTDecode]
ID
[BINARY JPEG IMAGE DATA WOULD BE HERE - 500x500 pixels]
EI
Q
BT
/F1 12 Tf
50 120 Td
(This text appears after the image in the content stream.) Tj
0 -15 Td
(The entire content is a single multiline string in the PDF.) Tj
ET
endstream
endobj
xref
0 5
0000000000 65535 f
0000000009 00000 n
0000000056 00000 n
0000000107 00000 n
0000000302 00000 n
trailer
<</Size 5/Root 1 0 R>>
startxref
887
%%EOF`