Uploaded image for project: 'Imaging'
  1. Imaging
  2. MGNLIMG-100

Loading image from JCR using AbstractLoader will result in adding the alpha value as a color to generated JPGs

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Critical Critical
    • 2.2.2
    • 2.2.1
    • image operations
    • None

      Description:
      Calling an image generator which uses a FromContent (extends AbstractLoader) operation will result in wrong JPGs.
      If storing PNGs it works fine. As PNGs have a alpha channel, the alpha value is correctly applied.
      Storing a JPG, it seems as the ImageIO.write() method writes the alpha value as a color and not ignoring it as it should.

      Reproduce:
      1. Import the generator attached to this issue. Just containing one operation, the load operation.
      2. Add a test image to DMS.
      3. execute this code with correct paths:

      final ImagingModuleConfig config = (ImagingModuleConfig) ModuleRegistry.Factory.getInstance().getModuleInstance("imaging");
      final ImageGenerator generator = config.getGenerators().get("myOperationChainBResize");
      
      Session dmsSession = MgnlContext.getJCRSession("dms");
      Node origImage = dmsSession.getNode("/test/orig");
      
      final Content content = info.magnolia.cms.util.ContentUtil.asContent(origImage);
      
      final ParameterProvider<Content> parameterProvider = new ContentParameterProvider(new SimpleEqualityContentWrapper(content));
      final BufferedImage bufferedImage = generator.generate(parameterProvider);
      
      ImageIO.write(bufferedImage, "png", new File("/Users/cringele/Documents/temp_stuff/image-test/create/out1-works.png"));
      ImageIO.write(bufferedImage, "jpg", new File("/Users/cringele/Documents/temp_stuff/image-test/create/out1-worksNot.jpg"));
      

      You can also write the stream back into JCR, the result is the same. So for testing much easier into a file.

      Source of the problem:
      info.magnolia.imaging.operations.load.AbstractLoader.apply(BufferedImage, P)

      if (source != null) {
          throw new ImagingException("This operation currently does not support overlaying images");
      }
      final BufferedImage loaded = loadSource(filterParams);
      if (loaded == null) {
          throw new ImagingException("Could not load image for " + filterParams);
      }
      
      //This line is the source of the problem. Using BufferedImage.TYPE_INT_RGB would work because it wouldn't contain any alpha channel. Of course just for testing applicable.
      final BufferedImage img = new BufferedImage(loaded.getWidth(), loaded.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
      final Graphics2D g = img.createGraphics();
      
      if (backgroundColor != null) {
          g.setColor(backgroundColor);
          g.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
      }
      g.drawImage(loaded, null, 0, 0);
      // TODO would this make any difference ? g.drawRenderedImage(loaded, null);
      
      g.dispose();
      return img;
      

      Proof of the problem source:
      First possibility: Execute this code just passing back the loaded BufferedImage

      if (source != null) {
          throw new ImagingException("This operation currently does not support overlaying images");
      }
      final BufferedImage loaded = loadSource(filterParams);
      if (loaded == null) {
          throw new ImagingException("Could not load image for " + filterParams);
      }
      return loaded;
      

      Second possibility: Pass back the created BufferedImage (img) withour loagin the orig image on top.
      Like this you can compare alpha value in PNG to color in JPG.

      if (source != null) {
          throw new ImagingException("This operation currently does not support overlaying images");
      }
      final BufferedImage loaded = loadSource(filterParams);
      if (loaded == null) {
          throw new ImagingException("Could not load image for " + filterParams);
      }
      final BufferedImage img = new BufferedImage(loaded.getWidth(), loaded.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
      final Graphics2D g = img.createGraphics();
      
      if (backgroundColor != null) {
          g.setColor(backgroundColor);
          g.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
      }
      //Image not loaded on top of it
      //g.drawImage(loaded, null, 0, 0);
      // TODO would this make any difference ? g.drawRenderedImage(loaded, null);
      
      g.dispose();
      return img;
      

      It seems to be a known problem:
      http://stackoverflow.com/questions/8410996/java-bufferedimage-saves-with-unwanted-background-color
      Trying out the solution they suggest did not work.

      Was not able to supply a patch with a final solution. Added a pacth as a workaround.

        Acceptance criteria

          1. AbstractLoader.java.patch
            2 kB
          2. Generator.png
            Generator.png
            67 kB
          3. OrigImage-PlacedIntoDMS.jpg
            OrigImage-PlacedIntoDMS.jpg
            103 kB
          4. out1-works.png
            out1-works.png
            412 kB
          5. out1-worksNot.jpg
            out1-worksNot.jpg
            33 kB
          6. Output-using-BufferedImage.TYPE_INT_RGB.jpg
            Output-using-BufferedImage.TYPE_INT_RGB.jpg
            31 kB

              rkovarik Roman Kovařík
              cringele Christian Ringele
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

                Created:
                Updated:
                Resolved:

                  Bug DoR
                  Task DoD