objcio / attributed-string-builder

Attributed String Builders
108 stars 8 forks source link

The page background related `customAttributes`, such as `pageBackground`, is ignored when text is short #8

Open onevcat opened 1 year ago

onevcat commented 1 year ago

For example, if we have this code:

Group {
    "ABCDE".modify {
        $0.customAttributes[NSAttributedString.Key.pageBackground.rawValue] = NSColor.blue
    }
    "\n"
    "\u{0c}"
}

The PDF page can be rendered correctly with a blue background color.

截屏2023-07-11 0 01 12

However, if we render a shorter string, such as "ABCD":

Group {
-   "ABCDE".modify {
+   "ABCD".modify {
        $0.customAttributes[NSAttributedString.Key.pageBackground.rawValue] = NSColor.blue
    }
    "\n"
    "\u{0c}"
}

It produces a page with the default white background.

截屏2023-07-11 0 01 35

I tried to dig into the issue, and it seems to be due to the way of calculating location, in the PDFRenderer class:

https://github.com/objcio/attributed-string-builder/blob/4ebe6debc25c09532b110eece5138435e4fd77b8/Sources/AttributedStringBuilder/AttributedStringToPDF_TextKit.swift#L362-L369

It chooses range.location + range.length/2 and gets the attributes there. So if the input text (usually the Chapter title in the objc.io books) is too short, the renderer cannot pick the attributes with background color, but the one from \n or page break. It is a surprising issue and really hidden, hard to track.

Is there a better way than picking the middle? Or do you have any suggestion if I want to render a very short chapter title (say, only two characters)?

onevcat commented 1 year ago

I can move the pageBackground (and pageBackgroundView) outside, to the Group to make it work, as a workaround.

Group {
    "ABCD"
    "\n"
    "\u{0c}"
}.modify {
    $0.customAttributes[NSAttributedString.Key.pageBackground.rawValue] = NSColor.blue
}

However, the original issue is still existing and it would be great if you have a better idea on how to fix, or at least adding some documentation.

chriseidhof commented 1 year ago

Yes, I'd like to fix this. I'm not sure when I find the time yet (could be tonight, could be in a month). So if you can use the workaround for now and it's not blocking you then let's do that until it gets fixed 😅

onevcat commented 1 year ago

No problem. I am going with the workaround for now by moving the pageBackground and pageBackgroundView to an outside modify.