-
Notifications
You must be signed in to change notification settings - Fork 483
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
Exploration: Make Locale configurable for formatting of tags (not to be merged) #538
base: main
Are you sure you want to change the base?
Conversation
I think this should be handled using the long fabled MetadataContext. Getting this implemented would also open other possibilities, like an updated take on #225. Even though I've said it before in other places, I'd like to say once again that setting the default I edited the comment because I mixed this up with the similar issue of relying on default character encoding, which also causes issues. Generally, if presenting the information directly to the user, using the default |
Thanks for your thoughts, and giving some more context, much appreciated. I had actually considered creating a I agree with you that the What could be a way forward? I am thinking it would be relatively easy to introduce a small interface MetadataContext {
Locale getLocale();
} Future concerns like filtering (#225) could be added to the interface in a separate issue. However, actually applying the |
@rdvdijk I think your plan sounds like a good one. I don't know how much it matters how "big" the PR is when measured in code changes or lines, as I see it, making "one logical change"/feature is as small as it can be. However, it doesn't really matter that much what I think, @drewnoakes is the one that will have to make the decisions. I don't know if it's preferable to make the "context class", the overloaded API calls and a partial application of As I remember it, @drewnoakes wanted to minimize the number of places where such an object would have to be passed on. This is where I didn't see clearly what would be the best solution, as storing it as any kind of "global" introduces potential concurrency traps very fast. I guess that if it could be attached to a "reader" that is used for only a single extraction for example, it would be safe though. I think agreeing on exactly how the "context object" should be made accessible all the places it's needed is essential before a lot of work is invested. |
This is very interesting. Thanks for picking this up. I agree with @Nadahar that, given you're going to the effort of threading this through, it'd be worth adding a broader type into which other kinds of state/settings/etc can be added. I'm not worried about a large PR, so long as the change is clear and consistent and doesn't change the world in some fundamental way. Your idea of breaking it down by file type, for example, makes sense too. |
I'll introduce the @Nadahar wrote above:
Related to that, I have a concrete implementation question: Shall I add Option 1: public class TagDescriptor<T extends Directory>
{
@NotNull
protected final T _directory;
@NotNull
protected final MetadataContext _context;
public TagDescriptor(@NotNull T directory, @NotNull MetadataContext context)
{
_directory = directory;
_context = context;
} Option 2: public class TagDescriptor<T extends Directory>
{
@NotNull
protected final T _directory;
@NotNull
protected final Locale _locale;
public TagDescriptor(@NotNull T directory, @NotNull Locale locale)
{
_directory = directory;
_locale = locale;
} I am leaning towards Option 2 in this case, but I'm not sure if there is a need for other state/settings/etc here. |
Please make it a class. It's easier to version a class over time than an interface. If we add to an interface, it breaks all existing implementations. I don't think this would be an extension point for external code either.
I'm happy for you to add it in the same branch. It'll be easier to see how it works that way, and change it before it is merged if it needs to.
I'd suggest adding the whole context. There may be other bits on it we want in future. |
Thanks for the swift reply. I'll work on this and report back when I think the branch is at a point to discuss some more details. |
Add overloaded methods to TagDescriptor to supply Locale where needed. Deprecate overloaded methods that now need a Locale, and are unused.
…dataReader#readJpegSegments.
Did some work on this. My approach was to start at It's not all done yet, but it's a start. Here is the progress as far as I can tell:
@drewnoakes Can you see if this is going in the right direction? Things of note:
|
@Nadahar Also curious what you think of the changes so far. |
@NotNull | ||
public static Metadata readMetadata(@NotNull InputStream inputStream) throws JpegProcessingException, IOException | ||
{ | ||
return readMetadata(inputStream, null); | ||
// TODO document this default context? |
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.
As explained in the PR discussion: I've added this comment throughout to mark where new MetadataContext()
is called, which is done mostly for backwards compatibility.
@@ -55,11 +58,17 @@ | |||
// Ev=BV+Sv Sv=log2(ISOSpeedRating/3.125) | |||
// ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32. | |||
|
|||
// TODO can be removed once context has been added to all sub-classes |
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.
There are 4 sub-classes of this, that are still on the to-do list, so I expect this constructor to be removed in this PR, eventually.
@@ -59,7 +60,13 @@ | |||
{ | |||
public ExifTiffHandler(@NotNull Metadata metadata, @Nullable Directory parentDirectory) |
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.
This constructor cannot be removed, because it is also used by Png, Tiff and Eps, which are out of scope of this pull request. Eventually it can be removed.
/** | ||
* Locale used to format metadata. | ||
*/ | ||
private Locale _locale; |
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.
I would make MetadataContext
immutable so that it can be passed around without worrying about threads. Thus, this, and any other fields in this class should be final
in my opinion.
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.
I fully agree with that! Since we only have a Locale
for now, I could create a constructor on MetadataContext
.
However, using the builder pattern would make this more future proof (albeit more verbose).
This is quite a lot to look through. Once things I've noticed already is the chosen approach to preserve the existing API. This is only my opinion, and others might not share it, but I would have done it slightly differently. Instead of requiring the I don't know if it makes much practical difference, but I prefer not to create objects when they're not needed, and I think using Here's an example to illustrate what I mean, here is the "pre context version": public SomeType foo(SomeOtherType bar) {
...
} This is the corresponding "post context version": public SomeType foo(SomeOtherType bar) {
return foo(bar, null);
}
public SomeType foo(SomeOtherType bar, @Nullable MetadataContext context) {
...
} Don't make any changes based on my opinion alone though. |
@Nadahar Thanks for the notes, much appreciated.
I personally disagree with that. I really dislike passing along Allowing
My approach was to create one |
@rdvdijk I hope this PR will eventually reach maturity and get merged. Is there any blocker? |
I do not think there are any blockers, but discussion here kind of just stalled two years ago. What do you think, @Nadahar and @drewnoakes ? Should I spend some time to bring this PR back to life? |
Ping @Nadahar and @drewnoakes . Today we ran into something similar: a difference in system timezone caused unexpected timestamps. This is something that could also be fixed by the changes in this branch, or a subsequent pull request that adds configurable I would like to make progress with this PR, but I really need some more feedback if this PR is heading in the right direction. I'd be happy to take another approach if that is preferred. |
As initially discussed in drewnoakes/metadata-extractor-images#35, the current formatting of certain tag descriptions are locale-dependent. The only way to influence the formatting is to set the locale globally, using
Locale#setLocale
. This can have undesirable effects when integratingmetadata-extractor
in a larger application.This pull request explores the idea of making the
Locale
configurable. A specificLocale
is passed toJpegMetadataReader#readMetadata
, and all the way down to theDescriptor
s that need it to format specific values. Two descriptors have been altered to show two specific examples:ExifDescriptorBase
: to render the F-number (f/6.0
vsf/6,0
)GpsDescriptor
: to render the longitude and latitude (54° 59' 22.8"
vs54° 59' 22,8"
)See the two added tests in
JpegMetadataReaderTest
(testConfigurableLocaleEnglish
andtestConfigurableLocaleDutch
).There is still much left to be done:
TODO
s with further ideas, I did not want to make the pull request even largerI am curious what you think of this, any feedback is welcome.