String getCacheKey(
     XWikiAttachment attachment,
     ImageDimensions dimension,
     String copyright,
     String watermark,
     int cropX,
     int cropY,
     int cropW,
     int cropH)
     throws NoSuchAlgorithmException {
   String key =
       attachment.getId()
           + "-"
           + attachment.getVersion()
           + "-"
           + getType(attachment.getMimeType(getContext()))
           + "-"
           + attachment.getDate().getTime()
           + "-"
           + dimension.getWidth()
           + "-"
           + dimension.getHeight()
           + "-"
           + getAditionalInfoHash(copyright, watermark, cropX, cropY, cropW, cropH);
   return key;
 }
  /**
   * Set the response HTTP headers common to both partial (Range) and full responses.
   *
   * @param attachment the attachment to get content from
   * @param request the current client request
   * @param response the response to write to.
   * @param context the current request context
   */
  private static void setCommonHeaders(
      final XWikiAttachment attachment,
      final XWikiRequest request,
      final XWikiResponse response,
      final XWikiContext context) {
    // Choose the right content type
    String mimetype = attachment.getMimeType(context);
    response.setContentType(mimetype);
    try {
      response.setCharacterEncoding("");
    } catch (IllegalCharsetNameException ex) {
      response.setCharacterEncoding(XWiki.DEFAULT_ENCODING);
    }

    String ofilename = Util.encodeURI(attachment.getFilename(), context).replaceAll("\\+", "%20");

    // The inline attribute of Content-Disposition tells the browser that they should display
    // the downloaded file in the page (see http://www.ietf.org/rfc/rfc1806.txt for more
    // details). We do this so that JPG, GIF, PNG, etc are displayed without prompting a Save
    // dialog box. However, all mime types that cannot be displayed by the browser do prompt a
    // Save dialog box (exe, zip, xar, etc).
    String dispType = "inline";

    // Determine whether the user who attached the file has Programming Rights or not.
    boolean hasPR = false;
    String author = attachment.getAuthor();
    try {
      hasPR =
          context
              .getWiki()
              .getRightService()
              .hasAccessLevel("programming", author, "XWiki.XWikiPreferences", context);
    } catch (Exception e) {
      hasPR = false;
    }
    // If the mimetype is not authorized to be displayed inline, let's force its content disposition
    // to download.
    if ((!hasPR && !isAuthorized(mimetype)) || "1".equals(request.getParameter("force-download"))) {
      dispType = ATTACHMENT;
    }
    // Use RFC 2231 for encoding filenames, since the normal HTTP headers only allows ASCII
    // characters.
    // See http://tools.ietf.org/html/rfc2231 for more details.
    response.addHeader("Content-disposition", dispType + "; filename*=utf-8''" + ofilename);

    response.setDateHeader("Last-Modified", attachment.getDate().getTime());
    // Advertise that downloads can be resumed
    response.setHeader("Accept-Ranges", "bytes");
  }
Example #3
0
  /**
   * {@inheritDoc}
   *
   * <p>Allows to scale images server-side, in order to have real thumbnails for reduced traffic.
   * The new image dimensions are passed in the request as the {@code width} and {@code height}
   * parameters. If only one of the dimensions is specified, then the other one is computed to
   * preserve the original aspect ratio of the image.
   *
   * @see XWikiDefaultPlugin#downloadAttachment(XWikiAttachment, XWikiContext)
   */
  @Override
  public XWikiAttachment downloadAttachment(XWikiAttachment attachment, XWikiContext context) {
    if (!this.imageProcessor.isMimeTypeSupported(attachment.getMimeType(context))) {
      return attachment;
    }

    int height = -1;
    try {
      height = Integer.parseInt(context.getRequest().getParameter("height"));
    } catch (NumberFormatException e) {
      // Ignore.
    }

    int width = -1;
    try {
      width = Integer.parseInt(context.getRequest().getParameter("width"));
    } catch (NumberFormatException e) {
      // Ignore.
    }

    float quality = -1;
    try {
      quality = Float.parseFloat(context.getRequest().getParameter("quality"));
    } catch (NumberFormatException e) {
      // Ignore.
    } catch (NullPointerException e) {
      // Ignore.
    }

    // If no scaling is needed, return the original image.
    if (height <= 0 && width <= 0 && quality < 0) {
      return attachment;
    }

    try {
      // Transform the image attachment before is it downloaded.
      return downloadImage(attachment, width, height, quality, context);
    } catch (Exception e) {
      LOG.warn("Failed to transform image attachment.", e);
      return attachment;
    }
  }
Example #4
0
  /**
   * Reduces the size (i.e. the number of bytes) of an image by scaling its width and height and by
   * reducing its compression quality. This helps decreasing the time needed to download the image
   * attachment.
   *
   * @param attachment the image to be shrunk
   * @param requestedWidth the desired image width; this value is taken into account only if it is
   *     greater than zero and less than the current image width
   * @param requestedHeight the desired image height; this value is taken into account only if it is
   *     greater than zero and less than the current image height
   * @param keepAspectRatio {@code true} to preserve the image aspect ratio even when both requested
   *     dimensions are properly specified (in this case the image will be resized to best fit the
   *     rectangle with the requested width and height), {@code false} otherwise
   * @param requestedQuality the desired compression quality
   * @param context the XWiki context
   * @return the modified image attachment
   * @throws Exception if shrinking the image fails
   */
  private XWikiAttachment shrinkImage(
      XWikiAttachment attachment,
      int requestedWidth,
      int requestedHeight,
      boolean keepAspectRatio,
      float requestedQuality,
      XWikiContext context)
      throws Exception {
    Image image = this.imageProcessor.readImage(attachment.getContentInputStream(context));

    // Compute the new image dimension.
    int currentWidth = image.getWidth(null);
    int currentHeight = image.getHeight(null);
    int[] dimensions =
        reduceImageDimensions(
            currentWidth, currentHeight, requestedWidth, requestedHeight, keepAspectRatio);

    float quality = requestedQuality;
    if (quality < 0) {
      // If no scaling is needed and the quality parameter is not specified, return the original
      // image.
      if (dimensions[0] == currentWidth && dimensions[1] == currentHeight) {
        return attachment;
      }
      quality = this.defaultQuality;
    }

    // Scale the image to the new dimensions.
    RenderedImage shrunkImage = this.imageProcessor.scaleImage(image, dimensions[0], dimensions[1]);

    // Create an image attachment for the shrunk image.
    XWikiAttachment thumbnail = (XWikiAttachment) attachment.clone();
    thumbnail.loadContent(context);

    OutputStream acos = thumbnail.getAttachment_content().getContentOutputStream();
    this.imageProcessor.writeImage(shrunkImage, attachment.getMimeType(context), quality, acos);

    IOUtils.closeQuietly(acos);

    return thumbnail;
  }