unidoc / unipdf

Golang PDF library for creating and processing PDF files (pure go)
https://unidoc.io
Other
2.46k stars 250 forks source link

[BUG] Table background color glitch #528

Closed ricardogama closed 7 months ago

ricardogama commented 9 months ago

Description

When drawing tables in a consecutive manner, I see some glitches on the background color of some cells.

It seems to happen when a table starts at the very beginning of a page, but it might be coincidence.

Expected Behavior

Every header should be consistent:

Screenshot 2023-09-27 at 2 54 16 PM

Actual Behavior

Glitch observable on pages 14 and 27, and it's consistent every time I run the application and the PDF is generated.

Screenshot 2023-09-27 at 2 54 36 PM

Steps to reproduce the behavior:

  1. go run main.go
  2. open result.pdf
  3. Scroll to page 14

Attachments

package main

import (
    "bytes"
    "fmt"
    "os"

    "github.com/unidoc/unipdf/v3/common/license"
    "github.com/unidoc/unipdf/v3/creator"
    "github.com/unidoc/unipdf/v3/model"
)

var (
    regularFont *model.PdfFont
    boldFont    *model.PdfFont
)

var (
    darkGrayColor  = creator.ColorRGBFromHex("#B3B3B3")
    darkBlueColor  = creator.ColorRGBFromHex("#0D99FF")
    lightBlueColor = creator.ColorRGBFromHex("#BDE3FF")
    lightGrayColor = creator.ColorRGBFromHex("#E6E6E6")
)

func main() {
    if err := license.SetMeteredKey(os.Getenv("UNIDOC_KEY")); err != nil {
        panic(err)
    }

    var err error
    regularFont, err = model.NewStandard14Font("Helvetica")
    if err != nil {
        panic(err)
    }

    boldFont, err = model.NewStandard14Font("Helvetica-Bold")
    if err != nil {
        panic(err)
    }

    c := creator.New()
    c.SetPageMargins(30, 30, 30, 30)

    c.DrawFooter(func(block *creator.Block, args creator.FooterFunctionArgs) {
        p := c.NewStyledParagraph()
        p.SetTextAlignment(creator.TextAlignmentCenter)

        chunk := p.Append(fmt.Sprintf("Page %d of %d", args.PageNum, args.TotalPages))
        chunk.Style.Font = regularFont
        chunk.Style.FontSize = 8
        chunk.Style.Color = creator.ColorBlack

        if err := block.Draw(p); err != nil {
            panic(err)
        }
    })

    for i := 0; i < 200; i++ {
        if err := itemTable(c); err != nil {
            panic(err)
        }
    }

    var content bytes.Buffer
    if err := c.Write(&content); err != nil {
        panic(err)
    }

    f, err := os.Create("./result.pdf")
    if err != nil {
        panic(err)
    }
    _, err = f.Write(content.Bytes())
    if err != nil {
        panic(err)
    }
    err = f.Close()
    if err != nil {
        panic(err)
    }

    fmt.Println("result.pdf created")
}

func newParagraph(c *creator.Creator, font *model.PdfFont, color creator.Color, text string) *creator.StyledParagraph {
    p := c.NewStyledParagraph()
    p.SetMargins(2, 2, 5, 5)
    chunk := p.Append(text)
    chunk.Style.Font = font
    chunk.Style.Color = color
    return p
}

func newCell(t *creator.Table, colspan int, bgColor creator.Color, content creator.VectorDrawable) {
    cell := t.MultiColCell(colspan)
    cell.SetBorder(creator.CellBorderSideAll, creator.CellBorderStyleSingle, 0.3)
    cell.SetHorizontalAlignment(creator.CellHorizontalAlignmentLeft)
    cell.SetBackgroundColor(bgColor)
    if err := cell.SetContent(content); err != nil {
        panic(err)
    }
}

func itemTable(c *creator.Creator) error {
    table := c.NewTable(6)
    table.SetMargins(0, 0, 30, 0)

    drawHeaders := func(text1, text2, text3, text4 string) {
        newCell(table, 1, darkGrayColor, newParagraph(c, boldFont, creator.ColorBlack, text1))
        newCell(table, 2, darkGrayColor, newParagraph(c, boldFont, creator.ColorBlack, text2))
        newCell(table, 1, lightBlueColor, newParagraph(c, boldFont, creator.ColorBlack, text3))
        newCell(table, 2, lightBlueColor, newParagraph(c, regularFont, creator.ColorBlack, text4))
    }

    drawSubHeader := func(text string) {
        newCell(table, 1, lightGrayColor, newParagraph(c, boldFont, creator.ColorBlack, text))
        newCell(table, 2, lightGrayColor, newParagraph(c, boldFont, creator.ColorBlack, ""))
        newCell(table, 1, lightGrayColor, newParagraph(c, boldFont, creator.ColorBlack, ""))
        newCell(table, 2, lightGrayColor, newParagraph(c, boldFont, creator.ColorBlack, ""))
    }

    drawCells := func(text1, text2, text3, text4 string) {
        newCell(table, 1, creator.ColorWhite, newParagraph(c, boldFont, creator.ColorBlack, text1))
        newCell(table, 2, creator.ColorWhite, newParagraph(c, regularFont, creator.ColorBlack, text2))
        newCell(table, 1, creator.ColorWhite, newParagraph(c, boldFont, creator.ColorBlack, text3))
        newCell(table, 2, creator.ColorWhite, newParagraph(c, regularFont, creator.ColorBlack, text4))
    }

    newCell(table, 1, creator.ColorBlack, newParagraph(c, boldFont, creator.ColorWhite, "Product and materials"))
    newCell(table, 2, creator.ColorBlack, newParagraph(c, boldFont, creator.ColorWhite, "Description"))
    newCell(table, 1, darkBlueColor, newParagraph(c, boldFont, creator.ColorWhite, "GSAP"))
    newCell(table, 2, darkBlueColor, newParagraph(c, boldFont, creator.ColorWhite, "*Additional references at the bottom of the deal recap"))

    drawHeaders("Item details", "", "Contract and item number", "12389123987123897")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")

    drawHeaders("Volume", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")

    drawHeaders("Payment", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")

    drawHeaders("Pricing", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")

    drawSubHeader("Compulsory fees")
    drawCells("", "", "", "")
    drawCells("", "", "", "")

    drawSubHeader("ENR")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")

    drawHeaders("Backup depot", "", "Contract and item number", "1000000003-04*")
    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")

    drawHeaders("Different volume", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")

    drawCells("", "", "", "")
    drawCells("", "", "", "")
    drawCells("", "", "", "")

    return c.Draw(table)
}

result.pdf

3ace commented 9 months ago

@ricardogama Hello, thank you reporting this issue. I can confirm that this is reproducible when table is moved entirely to a new page.

We'll definitely need to fix this. We'll let you ASAP when we've fixed this.

3ace commented 8 months ago

@ricardogama a fix for this issue has been merged in our code base. It should be available with our next release.

ricardogama commented 7 months ago

@3ace Is there any chance you can make a minor release with this fix? It's quite frequent for our business case and we got some complains already, and I see there's another user with the same request: https://github.com/unidoc/unipdf/issues/534

3ace commented 7 months ago

@ricardogama we should have a new version released by the end of this week. I'll inform you later if the new version is released.

3ace commented 7 months ago

@ricardogama we have a new release that should fix this issue. Let us know if you have further issue.

https://github.com/unidoc/unipdf/releases/tag/v3.52.0