protected Response returnEmptyTile(final int width, final int height, final String format)
      throws Exception {
    // return an empty image
    ImageResponseWriter writer =
        (ImageResponseWriter) ImageHandlerFactory.getHandler(format, ImageResponseWriter.class);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    int bands;
    Double[] nodatas;
    if (format.equalsIgnoreCase("jpg") || format.equalsIgnoreCase("jpeg")) {
      bands = 3;
      nodatas = new Double[] {0.0, 0.0, 0.0};
    } else {
      bands = 4;
      nodatas = new Double[] {0.0, 0.0, 0.0, 0.0};
    }

    Raster raster =
        RasterUtils.createEmptyRaster(width, height, bands, DataBuffer.TYPE_BYTE, nodatas);
    writer.writeToStream(raster, ArrayUtils.toPrimitive(nodatas), baos);
    byte[] imageData = baos.toByteArray();
    IOUtils.closeQuietly(baos);

    final String type = mimeTypeMap.getContentType("output." + format);
    return Response.ok(imageData).header("Content-Type", type).build();

    // A 404 - Not Found response may be the most appropriate, but results in pink tiles,
    // maybe change that behavior on the OpenLayers client?
    // return Response.status( Response.Status.NOT_FOUND).build();

  }
  @SuppressWarnings("static-method")
  @GET
  @Produces("image/*")
  @Path("{version}/{raster}/{z}/{x}/{y}.{format}")
  public Response getTile(
      @PathParam("version") final String version,
      @PathParam("raster") String pyramid,
      @PathParam("z") final Integer z,
      @PathParam("x") final Integer x,
      @PathParam("y") final Integer y,
      @PathParam("format") final String format,
      @QueryParam("color-scale-name") final String colorScaleName,
      @QueryParam("color-scale") final String colorScale,
      @QueryParam("min") final Double min,
      @QueryParam("max") final Double max,
      @DefaultValue("1") @QueryParam("maskMax") final Double maskMax,
      @QueryParam("mask") final String mask) {

    final ImageRenderer renderer;
    Raster raster;

    try {
      renderer = (ImageRenderer) ImageHandlerFactory.getHandler(format, ImageRenderer.class);

      // TODO: Need to construct provider properties from the WebRequest using
      // a new security layer and pass those properties.
      // Apply mask if requested
      ProviderProperties providerProperties = SecurityUtils.getProviderProperties();
      if (mask != null && !mask.isEmpty()) {
        raster = renderer.renderImage(pyramid, x, y, z, mask, maskMax, providerProperties);
      } else {
        raster = renderer.renderImage(pyramid, x, y, z, providerProperties);
      }
      if (!(renderer instanceof TiffImageRenderer)
          && raster.getNumBands() != 3
          && raster.getNumBands() != 4) {
        ColorScale cs = null;
        if (colorScaleName != null) {
          cs = ColorScaleManager.fromName(colorScaleName, props);
        } else if (colorScale != null) {
          cs = ColorScaleManager.fromJSON(colorScale);
        }
        //        else
        //        {
        //          cs = ColorScaleManager.fromPyramid(pyramid, driver);
        //        }

        final double[] extrema = renderer.getExtrema();

        // Check for min/max override values from the request
        if (min != null) {
          extrema[0] = min;
        }
        if (max != null) {
          extrema[1] = max;
        }

        raster =
            ((ColorScaleApplier) ImageHandlerFactory.getHandler(format, ColorScaleApplier.class))
                .applyColorScale(raster, cs, extrema, renderer.getDefaultValues());
      }

      // Apply mask if requested
      //      if (mask != null && !mask.isEmpty())
      //      {
      //        try
      //        {
      //          final MrsImagePyramidMetadata maskMetadata = service.getMetadata(mask);
      //
      //          final Raster maskRaster = renderer.renderImage(mask, x, y, z, props, driver);
      //          final WritableRaster wr = RasterUtils.makeRasterWritable(raster);
      //
      //          final int band = 0;
      //          final double nodata = maskMetadata.getDefaultValue(band);
      //
      //          for (int w = 0; w < maskRaster.getWidth(); w++)
      //          {
      //            for (int h = 0; h < maskRaster.getHeight(); h++)
      //            {
      //              final double maskPixel = maskRaster.getSampleDouble(w, h, band);
      //              if (maskPixel > maskMax || Double.compare(maskPixel, nodata) == 0)
      //              {
      //                wr.setSample(w, h, band, nodata);
      //              }
      //            }
      //          }
      //        }
      //        catch (final TileNotFoundException ex)
      //        {
      //          raster = RasterUtils.createEmptyRaster(raster.getWidth(), raster.getHeight(),
      // raster
      //            .getNumBands(), raster.getTransferType(), 0);
      //        }
      //      }

      return ((ImageResponseWriter)
              ImageHandlerFactory.getHandler(format, ImageResponseWriter.class))
          .write(raster, renderer.getDefaultValues())
          .build();

    } catch (final IllegalArgumentException e) {
      return Response.status(Status.BAD_REQUEST)
          .entity("Unsupported image format - " + format)
          .build();
    } catch (final IOException e) {
      return Response.status(Status.NOT_FOUND).entity("Tile map not found - " + pyramid).build();
    } catch (final MrsImageException e) {
      return Response.status(Status.NOT_FOUND)
          .entity("Tile map not found - " + pyramid + ": " + z)
          .build();
    } catch (final TileNotFoundException e) {
      // return Response.status(Status.NOT_FOUND).entity("Tile not found").build();
      try {
        final MrsImagePyramidMetadata metadata = service.getMetadata(pyramid);

        return createEmptyTile(
            ((ImageResponseWriter)
                ImageHandlerFactory.getHandler(format, ImageResponseWriter.class)),
            metadata.getTilesize(),
            metadata.getTilesize());
      } catch (final Exception e1) {
        log.error(
            "Exception occurred creating blank tile "
                + pyramid
                + "/"
                + z
                + "/"
                + x
                + "/"
                + y
                + "."
                + format,
            e1);
      }
    } catch (final ColorScale.BadJSONException e) {
      return Response.status(Status.NOT_FOUND).entity("Unable to parse color scale JSON").build();

    } catch (final ColorScale.BadSourceException e) {
      return Response.status(Status.NOT_FOUND).entity("Unable to open color scale file").build();
    } catch (final ColorScale.BadXMLException e) {
      return Response.status(Status.NOT_FOUND).entity("Unable to parse color scale XML").build();
    } catch (final ColorScale.ColorScaleException e) {
      return Response.status(Status.NOT_FOUND).entity("Unable to open color scale").build();
    } catch (final Exception e) {
      log.error(
          "Exception occurred getting tile " + pyramid + "/" + z + "/" + x + "/" + y + "." + format,
          e);
    }

    return Response.status(Status.INTERNAL_SERVER_ERROR).entity(GENERAL_ERROR).build();
  }