Skip to content
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

Dynamic images should attempt to resize uncompressed "original" images #10283

Closed
allouis opened this issue Dec 13, 2018 · 2 comments · Fixed by #10314
Closed

Dynamic images should attempt to resize uncompressed "original" images #10283

allouis opened this issue Dec 13, 2018 · 2 comments · Fixed by #10314
Assignees
Labels
needs:info [triage] Blocked on missing information server / core Issues relating to the server or core of Ghost

Comments

@allouis
Copy link
Contributor

allouis commented Dec 13, 2018

When images are uploaded to ghost, we automatically optimize them, and store the original as filename_o.ext

To avoid double compression, we should be using these optimized images when resizing for dynamic images.

But! It is a little easier said than done, because the _o suffix, isn't always a suffix 👻

Image optimization

The image optimization we have is a piece of middleware that sits on file upload routes.

When it receives an image my-image.jpg it optimizes it (details unnecessary) and asks the StorageAdapter to save my-image.jpg (the new optimized image) and my-image_o.jpg (the original pre-optimized image)

StorageAdapter

The storage adapter base class includes a method called getUniqueFileName which takes a requested filename e.g. my-coole-img.jpg and returns a filename which it can be stored as, the current implementation appends a -n where n is the lowest number that would make the filename unique. e.g. my-coole-img-4.jpg

The problem

The problem lies when we upload an image with a non unique name already-exists.jpg,.

When we hit the image optimization layer it will ask the StorageAdapter to store already-exists.jpg and already-exists_o.jpg.

The StorageAdapter will find a unique name and so save already-exists-1.jpg and already-exists_o-1.jpg - This is how the _o suffix does not always act as a suffix.

The solution???

The "easy" route

The easiest solution is a lil regex to match against optimized images /_o(?:-\d+)?\.[a-zA-Z]+$/

This matches "_o" optionally followed by -n (where n is at least one digit) followed by .ext where ext is some letters

What's wrong with that?

What's wrong with that is that the resize image stuff is really tied to the implementation of the StorageAdapter and how it deals with unique filenames - this is a sign that our code is not structured correctly. If anyone implements a storage adapter with a different unique filename mechanism, this logic will no longer hold.

What else can we do?

We can re-evaluate what the StorageAdapter's responsibilities are, should it handle image optimization?

If it should, then the code can be moved to there, and we can be aware of how files are stored and everything is dandy. (Whether it is part of the base storage adapter, the local file storage adapter, or a brand new one would have to be discussed too - all are viable options IMO)

If it shouldn't then we need to give a nicer API to consumers of the storage adapter so that they can "tag" files with a certain piece of data, e.g "original" or "optimized", whether this is in the form of a suffix or prefix or whatever - I don't know.

This decision will set a precedent for any other manipulation/modifications of storage level data - so if we decide to keep these manipulations outside - we should give a generic and fairly powerful API for modules like the image one to work with.

@allouis allouis self-assigned this Dec 13, 2018
@allouis allouis added server / core Issues relating to the server or core of Ghost media needs:info [triage] Blocked on missing information labels Dec 13, 2018
@kirrg001
Copy link
Contributor

Very nice write up 👍

We can re-evaluate what the StorageAdapter's responsibilities are, should it handle image optimization?

IMO it's correct that Ghost simply asks the storage adapter:

  • store image x (size w)
  • store image y (size k)

Why should the storage adapter know about image optimisation? 🤔The adapter is only a directive to save and get images. But other opinions are welcome 👍 😇


Is there a way to achieve this:

  • already-exists-1.jpg
  • already-exists-1_o.jpg

e.g. call getUniqueFileName in Ghost.

@allouis
Copy link
Contributor Author

allouis commented Jan 2, 2019

@kirrg001 And I spoke about this IRL and think that the best (long term) solution is to have a DB that manages a mapping of the locations of files to names. This would allow ghost to store metadata against files, without asking storage adapter implementations to update or change their modules.

This is a longer term solution however, which we've no plans to design or do anytime soon. So for now we think using a regex and assuming the getUniqueFileName method works in the way described above is good enough.

kevinansfield pushed a commit that referenced this issue Jan 8, 2019
closes #10283 

Updated middleware for dynamic image sizes to attempt to read the unoptimized image first, taking into account the `-n` suffix for duplicate image names, by using a regex.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs:info [triage] Blocked on missing information server / core Issues relating to the server or core of Ghost
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants