Skip to content

Constrain the size of the ImageCrop for large images. #8

@gmerton

Description

@gmerton

Feature proposal

Some images have a natural size that is quite large. Users typically expect that image to scale appropriately to fit within the screen. It would be cool if ImageCrop followed that convention. The image below shows an example... note that the cropping tool is barely visible and users have to scroll down to find it.

image

Describe solution expectations

My caveman approach to solving this is to set some styles for the div containing imageCrop. The code below shows the modifications I made to the openCropDialog method of the UploadImageCropDemo class. Note the use of dialogLayout.getStyle().set() method.

As I said, it's quite crude. It would probably be better to set dimensions as percentages and ensure this works on all devices. Nonetheless, it is effective and creates a much better user experience (provided you can ignore many overlapping dialogs, which is my fault not yours) as you can see in the screenshot.

private void openCropDialog(ByteArrayOutputStream outputStream, String mimeType, Avatar avatar) {
        ImageCropGabe imageCrop;
        // Set up image crop dialog
        Dialog dialog = new Dialog();
        dialog.setCloseOnOutsideClick(false);
        dialog.setMaxHeight("100%");
        dialog.setMaxWidth(dialog.getHeight());

        Button cropButton = new Button("Crop image");
        Button dialogCancelButton = new Button("Cancel");
        dialogCancelButton.addThemeVariants(ButtonVariant.LUMO_ERROR);

        String src = getImageAsBase64(outputStream.toByteArray(), mimeType);
        imageCrop = new ImageCropGabe(src);
        imageCrop.setAspect(1.0);
        //imageCrop.setCircularCrop(true);
        imageCrop.setCrop(new CropGabe("%", 25, 25, 50, 50)); // centered crop
        imageCrop.setKeepSelection(true);
        int targetHeight;
        int targetWidth = 175;
        int naturalWidth = 0;
        int naturalHeight = 0;
        try {
            // Decode base64 back to a byte array
            byte[] decodedBytes = Base64.getDecoder().decode(src.split(",")[1]); // Removing "data:image/...;base64,"
            ByteArrayInputStream inputStream = new ByteArrayInputStream(decodedBytes);

            // Use ImageIO to read the image dimensions
            BufferedImage bufferedImage = ImageIO.read(inputStream);
            if (bufferedImage != null) {
                naturalWidth = bufferedImage.getWidth();
                naturalHeight = bufferedImage.getHeight();
            }
            logger.info("Image dimensions: " + naturalWidth + " x " + naturalHeight);
        } catch (Exception e) {
            logger.error("Failed to load image dimensions: " + e.getMessage(), e);
        }

        double aspectRatio = naturalWidth > 0 && naturalHeight > 0 ? (double) naturalHeight / naturalWidth : 1.0;
        targetHeight = (int) (targetWidth * aspectRatio);

        logger.info("target dimensions: " + targetWidth + ", " + targetHeight);
        cropButton.addClickListener(event -> {
            byte[] newCroppedPicture = null;
            newCroppedPicture = imageCrop.getCroppedImageBase64();
            avatar.setImage(imageCrop.getCroppedImageDataUri());
            dialog.close();
        });
        dialogCancelButton.addClickListener(c -> dialog.close());

        HorizontalLayout buttonLayout = new HorizontalLayout(dialogCancelButton, cropButton);
        Div dialogLayout = new Div(imageCrop);
        dialogLayout.setId("imageCropContainer");
        dialogLayout.getStyle()
                .set("width", targetWidth + "px")     // Scale the container
                .set("height", targetHeight + "px")  // Maintain desired height
                .set("overflow", "hidden")           // Crop overflow content
                .set("margin", "0 auto");
        buttonLayout.setWidthFull();
        buttonLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
        dialog.add(dialogLayout);
        dialog.getFooter().add(buttonLayout);
        dialog.open();
    }

Screenshot 2024-12-17 at 8 38 34 PM

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    To Do

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions