@Override
    public RenderedImage postProcessBlankResponse(RenderedImage finalImage, RenderingHints hints) {
      // force the current image in RGB or Gray
      final ImageWorker imageWorker = new ImageWorker(finalImage);
      hints = prepareHints(hints);
      imageWorker.setRenderingHints(hints);

      // make sure the mosaic image is either gray of RGB
      if (!imageWorker.isColorSpaceGRAYScale()) {
        if (!imageWorker.isColorSpaceRGB()) {
          imageWorker.forceColorSpaceRGB();
        }
      }
      imageWorker.forceComponentColorModel(); // todo optimize with paletted imagery

      if (!imageWorker.getRenderedImage().getColorModel().hasAlpha()) {
        // create an alpha band that is transparent
        final ImageWorker imageWorker2 = new ImageWorker(finalImage);
        imageWorker2.setRenderingHints(hints);

        // trick to get a 0 band
        RenderedImage alpha =
            imageWorker2.retainFirstBand().multiplyConst(new double[] {0.0}).getRenderedImage();
        imageWorker2.dispose();
        imageWorker.addBand(alpha, false);
      }

      RenderedImage result = imageWorker.getRenderedImage();
      imageWorker.dispose();
      return result;
    }
    @Override
    public RenderedImage postProcessMosaic(
        RenderedImage mosaic, ROI overallROI, RenderingHints hints) {

      // force the current image in RGB or Gray
      final ImageWorker imageWorker = new ImageWorker(mosaic);
      hints = prepareHints(hints);
      imageWorker.setRenderingHints(hints);

      // make sure the mosaic image is either gray of RGB
      if (!imageWorker.isColorSpaceGRAYScale()) {
        if (!imageWorker.isColorSpaceRGB()) {
          imageWorker.forceColorSpaceRGB();
        }
      }
      imageWorker.forceComponentColorModel(); // todo optimize with paletted imagery

      // do we already have a alpha band in the input image?
      if (imageWorker.getRenderedImage().getColorModel().hasAlpha()) {
        // if so we reuse it applying the ROI on top of it
        RenderedImage alpha = imageWorker.retainLastBand().getRenderedImage();
        RenderedImage maskedAlpha =
            new ImageWorker(hints)
                .mosaic(
                    new RenderedImage[] {alpha},
                    MosaicDescriptor.MOSAIC_TYPE_OVERLAY,
                    null,
                    new ROI[] {overallROI},
                    null,
                    null)
                .getRenderedImage();

        imageWorker.retainBands(mosaic.getColorModel().getNumColorComponents());
        imageWorker.addBand(maskedAlpha, false, true, null);
      } else {

        // turn the roi into a single band image and add it to the mosaic as transparency
        final ImageWorker roiImageWorker = new ImageWorker(overallROI.getAsImage());
        roiImageWorker.setRenderingHints(hints);

        PlanarImage alpha =
            roiImageWorker.forceComponentColorModel().retainFirstBand().getPlanarImage();
        if (!alpha.getBounds().equals(imageWorker.getPlanarImage().getBounds())) {
          // build final layout and use it for giving the alpha band a simil size and tiling
          // to the one of the image
          final ImageLayout layout =
              new ImageLayout(
                  mosaic.getMinX(), mosaic.getMinY(), mosaic.getWidth(), mosaic.getHeight());

          //
          final SampleModel sampleModel = mosaic.getSampleModel();
          layout.setTileHeight(sampleModel.getWidth()).setTileWidth(sampleModel.getHeight());
          hints.add(new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout));

          // correct bounds of the current image
          alpha =
              new ImageWorker(hints)
                  .mosaic(
                      new RenderedImage[] {alpha},
                      MosaicDescriptor.MOSAIC_TYPE_OVERLAY,
                      null,
                      new ROI[] {overallROI},
                      null,
                      null)
                  .getRenderedOperation();
        }
        imageWorker.addBand(alpha, false, true, null);
      }

      RenderedImage result = imageWorker.getRenderedImage();
      return result;
    }