-
Notifications
You must be signed in to change notification settings - Fork 73
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
Fixes #88 - created and modified are not parsed/encoded correctly #94
Fixes #88 - created and modified are not parsed/encoded correctly #94
Conversation
lib/ttfunk/table/head.rb
Outdated
# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html | ||
|
||
# January 1, 1904 00:00:00 UTC offset from Epoch | ||
LDT_BASIS_OFFSET = 2_082_844_800 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use Time.new(1904, 1, 1)
and use that for calculations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, that'd be fine and probably clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to include all fields plus the TZ to get it right, but I've made that change.
Looks good to me! |
|
@pointlessone So honestly, those comments don't make sense to me. At a minimum they are contradictory, and more generally they seem to ignore the fact that this is a Ruby library. We can't at the same time say "we don't care about what these values are" and "we shouldn't change them because they're in a public API". It's one or the other. As the values have simply never been even remotely correct, I don't see why there's an issue with changing them. No one could have possibly ever used the values for anything. Moreover, as this is a Ruby library, it should conform to Ruby's extremely well-established conventions for time. Ruby uses Epoch time - a zero of January 1, 1970 00:00:00 UTC - a convention it inherited from UNIX. Using an alternate zero - in this case January 1, 1904 00:00:00 UTC - is going to be confusing to everyone. If the
It doesn't. In my view there's no point having incorrect, confusing values in a public API. If the values are incorrect, you fix them, you don't just say "eh, doing this right is just too complex". Especially since we're talking about addition here. |
…ctly The created and modified values in the TTF header is a custom type called a long date time. A definition can be found here: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html The bytes are big endian encoded, and the basis is offset from standard Epoch. To make these values at all useful in Ruby, they need to be properly decoded from bytes and then offset corrected to get a Time. Similarly, we need to do the reverse transition when encoding in the header.
Switch from using it as an offset to using it as a basis, which required changing some signs
5374636
to
ab0f973
Compare
No, it's both.
I agree that having them as a Time is better. I recognize that these particular fields are probably not that important as they're basically arbitrarily set in font files. Yet, I want us to take a little bit more serious approach towards breaking changes. |
I care about those values. I’m building my own fonts and reading this value when the fonts are analyzed for inclusion in our web shop. I’ve been working around this issue like this, using the same approach as the established Python FontTools: def date_from_sfnt_timestamp(value)
# Convert the head created or modified timestamp to a readable value.
return Time.zone.now unless value
# FIXME: Work around endianness bug in ttfunk
value = [value].pack("q").unpack1("q>")
# Timestamp is out of range; ignore top bytes
value &= 0xFFFFFFFF if value > 0xFFFFFFFF
# Timestamp seems very low; regard as unix timestamp
value += 0x7C259DC0 if value < 0x7C259DC0 # January 1, 1970 00:00:00
Time.at([0, value + Time.new(1904, 1, 1, 0, 0, 0, 0).to_i].max)
end ttf = TTFunk::File.open(...)
date_from_sfnt_timestamp(ttf.header.modified)
Most font editors set those fields to a reasonable value by default nowadays. I agree that for the average font user, it is probably not very important. |
@petergoldstein I took a look a this again and I think we should keep We might also add Will you be able to work on this any time soon? |
@petergoldstein I merged parts of this PR outside of GitHub. Thank you for your contribution. |
The created and modified values in the TTF header is a custom type called a long date time. A definition can be found here:
https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html
The bytes are big endian encoded, and the basis is offset from standard Epoch. To make these values at all useful in Ruby, they need to be properly decoded from bytes and then offset corrected to get a Time. Similarly, we need to do the reverse transition when encoding in the header.
Fixes #88
@gettalong and @pointlessone , a technical review would be helpful if you've got the time. Thanks.