-
Notifications
You must be signed in to change notification settings - Fork 689
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
:valign=>:center or :bottom in text_box slightly inaccurate #169
Comments
… descender with the bottom of the text box. Closes prawnpdf#169
This issue should not be closed, it is still a problem in 1.0.0.rc2, the fix suggested by @Bluejade works correctly and should be merged. |
@derek-watson I'm not sure why this issue was closed in the first place, but we can definitely re-open if the issue is still present. Because 1.0.0.rc2 is a fairly old release, I'd want to be sure we can reproduce this either in the latest release (0.14.0), or even better, on master. Please confirm that, and I'll re-open. If you want to move things along even further, you can try preparing a pull request with the fix and a test. A commit from 3 years ago might merge cleanly, but it's just as likely that it'll need to be changed somewhat if the underlying code has changed. Right now there are many open issues in Prawn, and I'm currently the only active maintainer. The more you can do to help me prep this fix for release, the sooner it will get taken care of. Thanks! |
@derek-watson Seems you're already working on a fix! Didn't see that until after I commented. Looking forward to seeing a pull request, then 😄 |
Updating this ticket with a fresh example and screenshot of current behavior on master: require_relative "lib/prawn"
Prawn::Document.generate('vertical_align.pdf') do
text_box "The rain in spain falls mainly in the plains.",
:at => [100,450], :width => 100, :height => 100, :size => 16
stroke_rectangle [100, 450], 100, 100
text_box "The rain in spain falls mainly in the plains.",
:at => [250,450], :width => 100, :height => 100,
:valign => :center, :size => 16
stroke_rectangle [250, 450], 100, 100
text_box "The rain in spain falls mainly in the plains.",
:at => [400,450], :width => 100, :height => 100,
:valign => :bottom, :size => 16
stroke_rectangle [400, 450], 100, 100
end Produces: I think we can agree that the top align looks correct. It's the centering and bottom align that has some complications to it. For center valign: it looks like we're currently making the gap between the top and the ascender equal to the gap between the bottom and the descender. Looking at how some other software does it, it looks like what we should be doing is keeping the gap between ascender and the top of the box equal to that of the baseline and the bottom of the box. I propose that we go ahead and change the behavior to compute the bottom gap based on the baseline For bottom valign:, it looks like we're including the line gap. Looking for examples elsewhere, some things I found do this, while others do not. Prawn's text box actually has an option for choosing what behavior you want for this ( I propose we keep behavior as-is when Will these changes make everyone happy? If not, let me know where the problems are. /cc @bradediger, who hopefully knows more about this stuff than I do. |
It occurs to me that for the sake of completeness, we may want to also add an |
Unfortunately not. @Bluejade is the text box expert, and I have only interacted with that code tangentially due to my work on tables. Sorry to pass the buck but I have no direct knowledge here. @sandal: Your assessment of the problem and proposed solutions seem spot-on to me. The lower alignment example seems to be a defect; the center alignment is potentially debatable in that a different example with heavier descenders on the last line might make the box look more balanced. I don't know of any literature on the topic, but it does make intuitive sense that the eye matches the ascender of the first line with the baseline of the last line, not its descender. Count me as a 👍 on this general approach. |
Anyone else with experience on this topic is welcome to chime in. Otherwise, I will plan to either work on a patch that does what is mentioned above myself, or accept one from anyone who wants to put in the work! |
@Bluejade your thoughts are also welcome of course... it's just been tough to get in touch with you 😦 |
@sandal There is already a The final gap can be removed by (in when :bottom
@at[1] = @at[1] - (@height - height) + @descender
@at[1] -= line_gap
end I was able to implement the fixes to |
@jessedoyle A pull request would be welcome, thanks! |
@sandal Here's a few examples of the implemented fixes: Using the same code you demonstrated above: Notice here how the center aligned element has top/bottom gaps equal to the distance from the bottom to the baseline. Using Here we can see that the bottom aligned element does not have a final gap between the box bottom and the descender. I'll submit a pull request shorty. Let me know what you think! |
@jessedoyle: Thanks. I think we still need The default for |
@sandal Adding an Would the option only be relevant to |
It'd apply to both I'm trying to think through how |
@sandal I'm not sure I agree with your last comment. If you set In this case, there would always be an 'initial gap', which consists of the empty space at the top of the box. This seems to be logical to me, even if the font size is reduced due to |
@jessedoyle: Think of the initial gap and final gap as simply being a top and bottom margin, and then we're trying to vertically align the whole box. The edge case with bottom alignment I'm worried about is this one: If we ignore So when |
I'm wondering if we need to think a little more on all of this. I'm having trouble thinking of when you would want to set But if we were to offer finer grained control, we might want to implement something like What do you think? |
@sandal: I definitely understand you now. I agree that there should be some more thought on this. Honestly, I don't think an Furthermore, my efforts to implement the Here's my current code for def process_vertical_alignment(text)
return if defined?(@vertical_alignment_processed) && @vertical_alignment_processed
@vertical_alignment_processed = true
return if @vertical_align == :top
wrap(text)
case @vertical_align
when :center
@at[1] -= (@height - height + @descender) * 0.5
when :bottom
@at[1] -= (@height - height)
@at[1] += line_gap if @final_gap
end
@height = height
end You can change the code to: def process_vertical_alignment(text)
return if defined?(@vertical_alignment_processed) && @vertical_alignment_processed
@vertical_alignment_processed = true
wrap(text)
case @vertical_align
when :top
# Do something if @inital_gap
when :center
@at[1] -= (@height - height + @descender) * 0.5
when :bottom
@at[1] -= (@height - height)
@at[1] += line_gap if @final_gap
end
@height = height
end But this causes tests to break, likely due to not returning before the Any ideas? |
@jessedoyle: Thanks for the work you've done on this so far, it's a huge help. The notion that we include a line gap at the bottom of the text box by default but not at the top is almost certainly a historical accident, and so I'm willing to consider this to be a bug, because it's never going to be desirable behavior. With that in mind, I think we should figure out what the correct behavior is:
I'm in favor of the first approach (supporting all forms of padding) because it's going to be the most natural user experience. Unfortunately, it's also the most complex, and it may mean that I'd need to write this patch myself unless you're up for doing a lot of rework. The original suggestions I made about tweaking |
@jessedoyle It seems like the work you've done gets us close to option 2. Since it's going to be a pre-requisite for implementing option 1 anyway, maybe you can revise your pull request to simply act as if |
Fixes #169. Text::Box :valign option.
When you use :valign=>:bottom in Text::Box, the resulting text isn't quite at the bottom, and there's a similar problem with :valign=>:center. Of course, you're always at the mercy of the font metrics, but after a quick read through the code it sure looks like a bug in Text:Box.
Text::Box ends up calculating the height as the number of (wrapped) lines times the line height. That's the correct amount to advance down the page, but it's actually slightly bigger than the actual extent of the text because for most fonts ascender+descender is measurably smaller than the line height, and so on the final line of text nLines*line_height is a bit too big. Obviously this is most noticeable with one-line text boxes.
The pastie http://pastie.org/1294734 is an example, just drop it in prawn/examples/text and run it to see that this effect is not microscopic; it can easily be 2-3 points away from the expected position. It also demonstrates a way to fix it by providing a subclass of Box which overrides process_vertical_alignment... though hopefully this fix can make its way into Prawn in some form!
The text was updated successfully, but these errors were encountered: