@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`
|
||||
|
||||
Reference in New Issue
Block a user