Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gopdf.go
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,7 @@ func (gp *GoPdf) compilePdf(w io.Writer) (n int64, err error) {
}
max := len(gp.pdfObjs)
writer := newCountingWriter(w)
fmt.Fprint(writer, "%PDF-1.7\n%����\n\n")
fmt.Fprint(writer, "%PDF-1.7\n%\xe2\xe3\xcf\xd3\n\n")
linelens := make([]int64, max)
i := 0

Expand Down
39 changes: 39 additions & 0 deletions gopdf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,45 @@ func TestAddHeaderFooter(t *testing.T) {
}
}

// TestPdfBinaryHeader verifies that the compiled PDF starts with the correct
// "%PDF-1.7" version header followed by the 4-byte binary marker
// (0xE2 0xE3 0xCF 0xD3). Per the PDF spec, this binary marker must contain
// at least four bytes >= 128 so that file-transfer tools treat the file as
// binary instead of text.
func TestPdfBinaryHeader(t *testing.T) {
if err := initTesting(); err != nil {
t.Fatal(err)
}

pdf := GoPdf{}
pdf.Start(Config{PageSize: *PageSizeA4})
pdf.AddPage()

got, err := pdf.GetBytesPdfReturnErr()
if err != nil {
t.Fatalf("GetBytesPdfReturnErr() error = %v", err)
}

want := []byte("%PDF-1.7\n%\xe2\xe3\xcf\xd3\n\n")
if len(got) < len(want) {
t.Fatalf("compiled pdf too short: got %d bytes, want at least %d", len(got), len(want))
}
if !bytes.Equal(got[:len(want)], want) {
t.Fatalf("pdf header mismatch:\n got: % x\nwant: % x", got[:len(want)], want)
}

binaryMarker := got[10:14]
expectedMarker := []byte{0xE2, 0xE3, 0xCF, 0xD3}
if !bytes.Equal(binaryMarker, expectedMarker) {
t.Fatalf("binary marker mismatch:\n got: % x\nwant: % x", binaryMarker, expectedMarker)
}
for i, b := range binaryMarker {
if b < 128 {
t.Fatalf("binary marker byte %d (0x%02x) must be >= 128 to satisfy PDF spec", i, b)
}
}
}

func initTesting() error {
err := os.MkdirAll("./test/out", 0777)
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion page_obj.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ func (p *PageObj) write(w io.Writer, objID int) error {
}
me.buffer.WriteString(" >>\n")*/
//me.buffer.WriteString(" >>\n")
fmt.Fprintf(w, " /Contents %s\n", p.Contents) //sample Contents 8 0 R
if p.Contents != "" {
fmt.Fprintf(w, " /Contents %s\n", p.Contents) //sample Contents 8 0 R
}
if !p.pageOption.isEmpty() {
fmt.Fprintf(w, " /MediaBox [ 0 0 %0.2f %0.2f ]\n", p.pageOption.PageSize.W, p.pageOption.PageSize.H)
}
Expand Down
52 changes: 52 additions & 0 deletions page_obj_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package gopdf

import (
"bytes"
"strings"
"testing"
)

// TestPageObjWriteOmitsContentsWhenEmpty verifies that PageObj.write does not
// emit a "/Contents" entry when PageObj.Contents is empty.
//
// Previously the write method always wrote " /Contents %s\n", which produced
// a malformed " /Contents \n" line in the PDF when no content stream was
// attached (e.g. when importing pages from an existing source).
func TestPageObjWriteOmitsContentsWhenEmpty(t *testing.T) {
p := &PageObj{
ResourcesRelate: "5 0 R",
}

var buf bytes.Buffer
if err := p.write(&buf, 1); err != nil {
t.Fatalf("PageObj.write error = %v", err)
}

out := buf.String()
if strings.Contains(out, "/Contents") {
t.Fatalf("PageObj.write emitted /Contents for empty Contents; output:\n%s", out)
}
if !strings.HasPrefix(out, "<<\n") || !strings.HasSuffix(out, ">>\n") {
t.Fatalf("PageObj.write produced malformed dictionary:\n%s", out)
}
}

// TestPageObjWriteIncludesContentsWhenSet verifies that PageObj.write emits the
// "/Contents" entry with the correct indirect reference when PageObj.Contents
// is populated.
func TestPageObjWriteIncludesContentsWhenSet(t *testing.T) {
p := &PageObj{
Contents: "8 0 R",
ResourcesRelate: "5 0 R",
}

var buf bytes.Buffer
if err := p.write(&buf, 1); err != nil {
t.Fatalf("PageObj.write error = %v", err)
}

want := " /Contents 8 0 R\n"
if !strings.Contains(buf.String(), want) {
t.Fatalf("PageObj.write missing %q in:\n%s", want, buf.String())
}
}
Loading