class ImgscalrImageManipulator extends AbstractImageManipulator {

	protected BufferedImage resizeIfRequested(BufferedImage originalImage, ImageManipulationParameters parameters) {
		int originalHeight = originalImage.getHeight();
		int originalWidth = originalImage.getWidth();
		double aspectRatio = (double) originalWidth / (double) originalHeight;

		// Resize if required and calculate missing parameters if needed
		Integer pHeight = NumberUtils.toInt(parameters.getHeight(), 0);
		Integer pWidth = NumberUtils.toInt(parameters.getWidth(), 0);

		// Resizing is only needed when one of the parameters has been specified
		if (pHeight != 0 || pWidth != 0) {

			// No operation needed when width is the same and no height was set
			if (pHeight == 0 && pWidth == originalWidth) {
				return originalImage;
			}

			// No operation needed when height is the same and no width was set
			if (pWidth == 0 && pHeight == originalHeight) {
				return originalImage;
			}

			// No operation needed when width and height match original image
			if (pWidth != 0 && pWidth == originalWidth && pHeight != 0 && pHeight == originalHeight) {
				return originalImage;
			}
			ResizeMode resizeMode = parameters.getResizeMode();
			// if the mode used is smart, and one of the dimensions is auto then set this dimension to the original Value
			if (resizeMode == ResizeMode.SMART) {
				if (parameters.getWidth() != null && parameters.getWidth().equals("auto")) {
					pWidth = originalWidth;
				}
				if (parameters.getHeight() != null && parameters.getHeight().equals("auto")) {
					pHeight = originalHeight;
				}
			}
			int width = pWidth == 0 ? (int) (pHeight * aspectRatio) : pWidth;
			int height = pHeight == 0 ? (int) (width / aspectRatio) : pHeight;


			// if we want to use smart resizing we need to crop the original image to the correct format before resizing to avoid distortion
			if (pWidth != 0 && pHeight != 0 && resizeMode == ResizeMode.SMART) {

				double pAspectRatio = (double) pWidth / (double) pHeight;
				if (aspectRatio != pAspectRatio) {
					if (aspectRatio < pAspectRatio) {
						// crop height (top & bottom)
						int resizeHeight = Math.max(1, (int) (originalWidth / pAspectRatio));
						int startY = (int) (originalHeight * 0.5 - resizeHeight * 0.5);
						originalImage = crop(originalImage, new ImageRect(0, startY, resizeHeight, originalWidth));
					} else {
						// crop width (left & right)
						int resizeWidth = Math.max(1, (int) (originalHeight * pAspectRatio));
						int startX = (int) (originalWidth * 0.5 - resizeWidth * 0.5);
						originalImage = crop(originalImage, new ImageRect(startX, 0, originalHeight, resizeWidth));
					}
				}
			}

			// if we want to use proportional resizing we need to make sure the destination dimension fits inside the provided dimensions
			if (pWidth != 0 && pHeight != 0 && resizeMode == ResizeMode.PROP) {
				double pAspectRatio = (double) pWidth / (double) pHeight;
				if (aspectRatio < pAspectRatio) {
					// scale to pHeight
					width = Math.max(1, (int) (pHeight * aspectRatio));
					height = Math.max(1, pHeight);
				} else {
					// scale to pWidth
					width = Math.max(1, pWidth);
					height = Math.max(1, (int) (pWidth / aspectRatio));
				}

				// Should the resulting format be the same as the original image we do not need to resize
				if (width == originalWidth && height == originalHeight) {
					return originalImage;
				}
			}

			try {
				BufferedImage image = Scalr.apply(originalImage, new ResampleOp(width, height, options.getResampleFilter().getFilter()));
				originalImage.flush();
				return image;
			} catch (IllegalArgumentException e) {
				throw error(BAD_REQUEST, "image_error_resizing_failed", e);
			}
		}

		return originalImage;
	}

	public  ImgscalrImageManipulator(Vertx vertx, MeshOptions options, BootstrapInitializer boot);
	  ImgscalrImageManipulator(Vertx vertx, ImageManipulatorOptions options, BootstrapInitializer boot);

}