protected void encodeImage(BufferedImage image, OutputStream out) throws IOException {
      Timer timer = new Timer();
      log.info("encodeImage(): request format= " + contentType);

      if (contentType.equals("image/png")) {
        new ImageWorker(image).writePNG(out, "PNG", 0.8f, false, false);
      } else if (contentType.equals("image/jpeg")) {
        new ImageWorker(image).writeJPEG(out, "JPEG", 0.8f, false);
      } else {
        throw new RuntimeException("Unknown contentType: " + contentType);
      }
      log.info("    done. (" + timer.elapsedTime() + "ms)");
    }
  protected void encodeImage(BufferedImage _image, OutputStream out)
      throws WmsException, IOException {
    Timer timer = new Timer();

    // use GeoServer code to encode result image
    String requestFormat = mapContext.getRequest().getFormat();
    log.debug("encodeImage(): request format= " + requestFormat);

    if (requestFormat == null || requestFormat.equals("image/png")) {
      PNGMapProducer producer = new PNGMapProducer(wms);
      producer.setMapContext(mapContext);
      producer.formatImageOutputStream(_image, out);
    } else if (requestFormat.equals("image/gif")) {
      GIFMapProducer producer = new GIFMapProducer(wms);
      producer.setMapContext(mapContext);
      producer.formatImageOutputStream(_image, out);
    } else if (requestFormat.equals("image/jpeg")) {
      JPEGMapProducer producer = new JPEGMapProducer(wms);
      producer.setMapContext(mapContext);
      producer.formatImageOutputStream(_image, out);
    }
    log.debug("    done. (" + timer.elapsedTime() + "ms)");
  }
  public void writeTo(final OutputStream out) throws ServiceException, IOException {
    Timer timer = new Timer();

    // single layer? -> request ENCODED_IMAGE
    if (mapContext.getLayerCount() == 1) {
      MapLayer mapLayer = mapContext.getLayers()[0];
      ILayer layer = loader.findLayer(mapLayer);
      try {
        Pipeline pipeline = loader.getOrCreatePipeline(layer, LayerUseCase.ENCODED_IMAGE);

        ProcessorRequest request = prepareProcessorRequest();
        pipeline.process(
            request,
            new ResponseHandler() {
              public void handle(ProcessorResponse pipeResponse) throws Exception {

                HttpServletResponse response = GeoServerWms.response.get();
                if (pipeResponse == EncodedImageResponse.NOT_MODIFIED) {
                  log.info("Response: 304!");
                  response.setStatus(304);
                } else {
                  long lastModified = ((EncodedImageResponse) pipeResponse).getLastModified();
                  // allow caches and browser clients to cache for 1h
                  // response.setHeader( "Cache-Control", "public,max-age=3600" );
                  if (lastModified > 0) {
                    response.setHeader("Cache-Control", "no-cache,must-revalidate");
                    response.setDateHeader("Last-Modified", lastModified);
                  } else {
                    response.setHeader("Cache-Control", "no-cache,must-revalidate");
                    response.setDateHeader("Expires", 0);
                  }

                  byte[] chunk = ((EncodedImageResponse) pipeResponse).getChunk();
                  int len = ((EncodedImageResponse) pipeResponse).getChunkSize();
                  out.write(chunk, 0, len);
                }
              }
            });
        log.debug("    flushing response stream. (" + timer.elapsedTime() + "ms)");
        out.flush();
      } catch (IOException e) {
        throw e;
      } catch (Exception e) {
        throw new IOException(e);
      }
    }

    // multiple layers -> render into one image
    else {
      List<Job> jobs = new ArrayList();
      final Map<MapLayer, Image> images = new HashMap();

      // run jobs for all layers
      for (final MapLayer mapLayer : mapContext.getLayers()) {
        final ILayer layer = loader.findLayer(mapLayer);
        // job
        UIJob job =
            new UIJob(getClass().getSimpleName() + ": " + layer.getLabel()) {
              protected void runWithException(IProgressMonitor monitor) throws Exception {
                try {
                  // XXX this excludes Cache304 (which supports EncodedImageResponse only)
                  Pipeline pipeline = loader.getOrCreatePipeline(layer, LayerUseCase.IMAGE);

                  GetMapRequest targetRequest = prepareProcessorRequest();
                  pipeline.process(
                      targetRequest,
                      new ResponseHandler() {
                        public void handle(ProcessorResponse pipeResponse) throws Exception {
                          Image layerImage = ((ImageResponse) pipeResponse).getImage();
                          images.put(mapLayer, layerImage);
                        }
                      });
                } catch (Exception e) {
                  // XXX put a special image in the map
                  log.warn("", e);
                  images.put(mapLayer, null);
                  throw e;
                }
              }
            };
        job.schedule();
        jobs.add(job);
      }

      // join jobs
      for (Job job : jobs) {
        try {
          job.join();
        } catch (InterruptedException e) {
          // XXX put a special image in the map
          log.warn("", e);
        }
      }

      // put images together (MapContext order)
      Graphics2D g = null;
      try {
        // result image
        BufferedImage result =
            ImageUtils.createImage(mapContext.getMapWidth(), mapContext.getMapHeight(), null, true);
        g = result.createGraphics();

        // rendering hints
        RenderingHints hints =
            new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        hints.add(
            new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
        hints.add(
            new RenderingHints(
                RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON));
        g.setRenderingHints(hints);

        for (MapLayer mapLayer : mapContext.getLayers()) {
          Image layerImage = images.get(mapLayer);

          // load image data
          //                  new javax.swing.ImageIcon( image ).getImage();

          ILayer layer = loader.findLayer(mapLayer);
          int rule = AlphaComposite.SRC_OVER;
          float alpha = ((float) layer.getOpacity()) / 100;

          g.setComposite(AlphaComposite.getInstance(rule, alpha));
          g.drawImage(layerImage, 0, 0, null);
        }
        encodeImage(result, out);
      } finally {
        if (g != null) {
          g.dispose();
        }
      }
    }
  }