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

Add support for vips in the image analyzer #42005

Merged
merged 1 commit into from Jun 21, 2021

Conversation

brenogazzola
Copy link
Contributor

@brenogazzola brenogazzola commented Apr 16, 2021

Summary

Fixes: #41940
Fixes: #41941

Adds support for using vips as an image analyzer in active storage.

Other Information

This is pretty much my first non trivial PR, so advice on how to improve this is welcome. Just trying to get the ball running on this one, since I'd like to use this too.

@@ -192,7 +192,7 @@ def process_variants_with(processor)
previous_processor, ActiveStorage.variant_processor = ActiveStorage.variant_processor, processor
yield
rescue LoadError
skip "Variant processor #{processor.inspect} is not installed"
ENV["CI"] ? raise : skip("Variant processor #{processor.inspect} is not installed")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm probably missing it - what's the reasoning behind this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I originally opened this PR all my vips tests were failing in the CI, even though they passed on the dev box. I got the help of @matthewd and we discovered that the CI environment did not have VIPS installed, and therefore the tests for vips were not running. He asked me to ensure that all vips tests raised errors in the CI, but were allowed to be skipped in contributor's machines to make development easier.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the tests are passing now, I assume that means vips has been installed in CI?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just re-approved the CI to run, let us know if theres any other blockers! 🙇

@brenogazzola
Copy link
Contributor Author

Changes made. Tests passed. There is an error in "Guides" but it seems it is unrelated, and Github says the build passed? There's 2 workflows awaiting approval. What should I do in this case?

@zzak
Copy link
Member

zzak commented Jun 3, 2021

@brenogazzola In the case where workflows are awaiting approval, one of us has to approve to run the CI 😢 Running again but I think based on your last comment we should be good!

@@ -24,7 +26,7 @@ class Engine < Rails::Engine # :nodoc:

config.active_storage = ActiveSupport::OrderedOptions.new
config.active_storage.previewers = [ ActiveStorage::Previewer::PopplerPDFPreviewer, ActiveStorage::Previewer::MuPDFPreviewer, ActiveStorage::Previewer::VideoPreviewer ]
config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer, ActiveStorage::Analyzer::VideoAnalyzer ]
config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer::Vips, ActiveStorage::Analyzer::ImageAnalyzer::ImageMagick, ActiveStorage::Analyzer::VideoAnalyzer ]
Copy link
Member

@ghiculescu ghiculescu Jun 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it could a breaking change. What happens on this branch if you try to use ActiveStorage::Analyzer::ImageAnalyzer directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is. I didn't think about that. I can return my previous code, but it was looking pretty ugly:

def metadata
  if ActiveStorage.variant_processor == :vips
    Analyzer::ImageAnalyzer::Vips.new(@blob).metadata
  else
    Analyzer::ImageAnalyzer::ImageMagick.new(@blob).metadata
  end     
end

It also does not fit the pattern that was set with the PDF previewers, where each lib is a different previewer in the array, instead of having a generic PDFPreviewer that then chooses the correct class based on the libs available:

config.active_storage.previewers = [ 
  ActiveStorage::Previewer::PopplerPDFPreviewer, 
  ActiveStorage::Previewer::MuPDFPreviewer, 
  ActiveStorage::Previewer::VideoPreviewer 
]

I'm not sure where to go from here: breaking change, different patterns, or changing the previewers to have a generic PDFPreviewer that then decides between mu and poppler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've also just noticed I am not respecting the naming pattern and should probably have named the analyzers VipsImageAnalyzer and ImageMagickImageAnalyzer so they match the way the previewers are named.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or I could return the original ImageAnalyzer and just add the VipsVersion ahead of it:

config.active_storage.analyzers = [ 
  ActiveStorage::Analyzer::VipsImageAnalyzer, 
  ActiveStorage::Analyzer::ImageAnalyzer, 
  ActiveStorage::Analyzer::VideoAnalyzer 
]

This would not be a breaking change and it would more or less follow the way the previewers are set. I'd just need another class to place the common metadata method so it stayed DRY.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the approach here is good, and if users have been doing things like config.active_storage.analyzers << MyAnalyzer then it shouldn't cause problems. The risk I can think of is code like config.active_storage.analyzers.insert(config.active_storage.analyzers.index(ActiveStorage::Analyzer::ImageAnalyzer) + 1, MyAnalyzer) breaking. Which seems like a bad pattern anyway.

Can you please update the docs: https://github.com/rails/rails/blob/main/guides/source/configuring.md#configuring-active-storage

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I've also updated the comments in the code. Unfortunately, the CI failed on the same place as last time (the bug report templates I think)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you might need @zzak to approve it again

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brenogazzola @ghiculescu Approved! 🙏

@rails-bot rails-bot bot added the docs label Jun 3, 2021
@zzak
Copy link
Member

zzak commented Jun 9, 2021

@brenogazzola Can you rebase and squash please? 🙇

@brenogazzola
Copy link
Contributor Author

@zzak Done. Though it will conflict again with my #42392 since both updated the CHANGELOG and the same line in CONTRIBUTING. 😅

@zzak
Copy link
Member

zzak commented Jun 10, 2021

@brenogazzola Now that #42392 was merged hopefully this will be easier to rebase, sorry I missed that until now 🙇

@brenogazzola
Copy link
Contributor Author

@zzak It's fine. It's my own fault for opening multiple PRs for the same feature in the Rails at the same time. I'll keep rebasing as needed.

@brenogazzola
Copy link
Contributor Author

Also, done.

@zzak zzak added the ready PRs ready to merge label Jun 10, 2021
@brenogazzola brenogazzola force-pushed the activestorage/vips-analyzer branch 2 times, most recently from a1ff72c to 6251ec2 Compare June 19, 2021 12:59
@zzak zzak requested a review from pixeltrix June 20, 2021 12:25
Copy link
Contributor

@pixeltrix pixeltrix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brenogazzola if can you rebase this, then I'll merge 👍🏻

@brenogazzola
Copy link
Contributor Author

@pixeltrix Rebased. 👍

@pixeltrix pixeltrix merged commit 1f16768 into rails:main Jun 21, 2021
@pixeltrix
Copy link
Contributor

@brenogazzola thanks! 👍🏻

@brenogazzola brenogazzola deleted the activestorage/vips-analyzer branch June 21, 2021 11:27
@wilg
Copy link

wilg commented Jun 21, 2021

Thanks for fixing my issues @brenogazzola!

@sedubois
Copy link
Contributor

sedubois commented Dec 15, 2021

It appears that with this change away from ImageMagick, the analyzer does not store the image's width and height in the metadata any more, it only saves analyzed: true. Is that intended? Was that information used for something to begin with?

I had a test like this which used to pass before I started to migrate to Rails 7.0.0.rc3:

  test "poster is attached" do
    content = contents(:blog_post_1)

    assert content.poster.attached?

    blob = content.poster.blob.tap(&:analyze)

    assert_equal "cover.jpg", blob.filename.to_s
    assert_equal "image/jpeg", blob.content_type
    assert_equal({ identified: true, width: 1600, height: 900, analyzed: true }, # <-- Test fails here
                 blob.metadata.symbolize_keys)
    assert_equal 211486, blob.byte_size
    assert_equal "gDjkvuzYz1oUlbJ9hjbd5w==", blob.checksum
    assert_equal "public", blob.service_name
  end

@brenogazzola
Copy link
Contributor Author

brenogazzola commented Dec 15, 2021

Active Storage has tests specifically to ensure that width and height are being extracted for both ImageMagick and Vips. You can see them in the files changed by this PR.

While upgrading, did you notice that Vips has become the new default in Rails 7.0? It's possible that you don't have Vips installed and this is causing the analyzer to fail.

@sedubois
Copy link
Contributor

I am using Vips already in my 6.1.4 app. I will try to dig deeper to see why those width/height are disappearing in my test.

@brenogazzola
Copy link
Contributor Author

Is it happening to all images or only some of them? There are 3 rescue points in the analyzer that would cause it to skip setting the dimensions:

1 - ruby-vips is not installed
2 - The image is not valid
3 - There was a generic error in vips.

All of them generate log when hit. Try going to test.rb and changing log_level to info before running the test again to see which rescue it's hitting.

@sedubois
Copy link
Contributor

Thanks for your suggestions. After upgrading my local vips binary (brew upgrade vips), the test passes, so I suppose that was the issue!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
6 participants