7 Replies Latest reply on Jun 27, 2012 6:05 AM by snemarch

    How can you re-size an image on the fly in CQ?

    stewa52 Level 1

      How can you re-size an image on the fly in CQ?  I have a few components that are using the image associated with a page, but all the components require a different size but same aspect ratio of the same image.  I don't want to have the DAM create the sizes on upload.

        • 1. Re: How can you re-size an image on the fly in CQ?
          snemarch Level 1

          I would suggest creating your own i mage resizing servlet, derived from AbstractImageServlet. You can look at /libs/foundation/components/page/img.png.java for some inspiration, but I would suggest a full-fledged servlet registered with a combination of the extensions you need and an appropriate selector.

           

          You'll want to use "named size selectors" rather than putting pixel dimensions to avoid potential denial-of-service attacks. And you do want to use selectors rather than query parameters - the built-in image resizing code is slow, and query parameters bypass the dispatcher.

          • 2. Re: How can you re-size an image on the fly in CQ?
            Ryan Lunka Level 3

            If you use selectors instead of query string parameters, I don't think it will bypass the dispatcher cache.  Good point about preventing DoS attacks.

            • 3. Re: How can you re-size an image on the fly in CQ?
              stewa52 Level 1

              Are you suggesting that the servlet create a new image size on the fly based on the dynamic selector that is used?  For example, the page would request a new image using a selector of .img32x32.png and the servlet would parse out the selector parameters and create a new image.

              • 4. Re: How can you re-size an image on the fly in CQ?
                Ryan Lunka Level 3

                I believe that is what snemarch is suggesting and what I would as well.  In your servlet, if you use SlingHttpServletRequest, you have a simple getter to retrieve selectors from the request, so no "parsing" is necessary.  If you look at the foundation parbase component, there is an example of this type of thing in a file called something like img.GET.jsp.  The servlet basically becomes an abstraction layer between the requester and the actual image.  To the requester, nothing is different except the URI of the resource.

                • 5. Re: How can you re-size an image on the fly in CQ?
                  snemarch Level 1

                  awstewar1 wrote:

                   

                  Are you suggesting that the servlet create a new image size on the fly based on the dynamic selector that is used?  For example, the page would request a new image using a selector of .img32x32.png and the servlet would parse out the selector parameters and create a new image.

                  Yes, except you would do ".myresizeselector.descriptivename.png" - i.e., you trigger the servlet with the ".img" or ".resize" (or whatever) part of the selector, and choose a size based on the next selector part, e.g. ".searchthumbnail" or ".productsmall". You do NOT want to specify arbitrary pixel sizes there; one issue is updating code if your design changes, another is the possibility of DOS attacks.

                   

                  And yes, you let the servlet resize on-the-fly. This is slow, but you need a dispatcher under all circumstances anyway, CQ is just too slow without it... and the dispatcher will cache your resized images as long as you stick with selectors and don't use query paramters.

                   

                  Also, a thing to watch out for: if you're using SmartImage for crop/resize and users reference images from the DAM instead of uploading to individual pages (this is often a good idea), be careful if DAM images are larger than the default DAM rendition - there's (easy to hit) race conditions if the cropping tool is used before the default DAM rendition is available, which will cause the cropping dimensions stored at the smartimage node to refer to original-size dimensions, which are outside the default-rendition boundaries, which will subsequently cause "RasterFormatException: x + width is outside Raster" exceptions at runtime. Haven't found a code solution for this, authors just need a bit of patience (and checking the DAM tool to see if default rendition is done) before cropping.

                  • 6. Re: How can you re-size an image on the fly in CQ?
                    kinyelo

                    snemarch, I think your suggestion is great and what I've ultimately arrived at for my particular situation.  However, I can't figure out how to override the AbstractImageServlet.  The file you mention is java source code.  I don't see where it is compiled or how it is called from the servlet (or the image.draw() command).  Do you have any details on where to put the override file/how to configure it as a servlet?

                    • 7. Re: How can you re-size an image on the fly in CQ?
                      snemarch Level 1

                      I personally don't like the practice of putting java source code inside the components themselves - Day probably supports it to make life a bit easier, but it feels wrong... and it gives errorsquiggles in CRXDE.

                       

                      We've made a custom ImageResizeServlet.java that's hosted in our OSGi code bundle. I can't post the customer's code here, but I can show the service annotions we use. The important bits to note is that we use the selector "resize", and handle jpg/png/gif file extensions. This is CQ5.4, iirc sling.servlet.extensions was ignored or not in CQ5.3 - can't remember exactly what the issue was, though, but when we upgraded our site broke because we hadn't registered 'png'.

                      @Component

                      @Service

                      @Properties({

                                @Property(name="sling.servlet.resourceTypes", value="sling/servlet/default"),

                                @Property(name="sling.servlet.selectors", value="resize"),

                                @Property(name="sling.servlet.extensions", value={"jpg", "png", "gif"}),

                                @Property(name="sling.servlet.methods", value="GET")

                      })

                      public class ImageResizeServlet extends AbstractImageServlet {

                      //... code.

                      }

                       

                       

                      I don't know if it's possible to override handling of the default ".img" selector this way - we use our custom ".resize". We've also made a /apps/ourcompany/components/image component, which is a modified copy of the one in foundation (since foundation/image uses the .img selector). Note that if you start with a copy of the foundation component, be sure to fix sling:resourceType in cq_dropTargets parameters, or you'll be in for some nasty surprises .

                       

                      Note that the codebase I'm working on is somewhat legacy, so there might be better ways to handle some of these things - I'm personally not too fond of overriding foundation components unless you really need to.