ScreenshotDrawing.java

// Copyright (c) 2023 Tobias Briones. All rights reserved.
// SPDX-License-Identifier: BSD-3-Clause
// This file is part of https://github.com/tobiasbriones/blog

package engineer.mathsoftware.blog.slides.drawing;

import engineer.mathsoftware.blog.slides.Colors;
import engineer.mathsoftware.blog.slides.Slide;
import engineer.mathsoftware.blog.slides.SlideSize;
import javafx.scene.Group;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;

import static engineer.mathsoftware.blog.slides.drawing.Drawings.*;

class ScreenshotDrawing {
    private final SlideSize size;
    private final Group group;
    private final Rectangle background;
    private final CaptionRenderer captionRenderer;
    private final double padding;

    ScreenshotDrawing(SlideSize size) {
        this.size = size;
        this.group = new Group();
        this.background = new Rectangle();
        this.captionRenderer = new CaptionRenderer();
        this.padding = size.width() * 0.1;

        captionRenderer.setContentArc(48.0);
        captionRenderer
            .widthProperty()
            .set(size.width() - padding * 2.0);
        captionRenderer
            .xProperty()
            .set(padding);
        captionRenderer
            .yProperty()
            .set(size.height());
    }

    Group draw(Slide.Screenshot screenshot) {
        var image = screenshot.image();

        drawImage(image, screenshot.background());
        drawCaption(screenshot);
        return group;
    }

    Group draw(Slide.CodeShot codeShot) {
        var image = codeShot.image();
        var lang = codeShot.language();
        var langColor = Colors.color(lang);

        drawImage(image, langColor);
        drawCaption(codeShot);
        return group;
    }

    private void drawImage(Image image, Color bgColor) {
        var iv = new ImageView();

        iv.setSmooth(true);
        iv.setPreserveRatio(true);
        fitImageView(iv, image);
        drawImage(image, iv);
        centerImageView(iv);

        clear(bgColor);
        group.getChildren().add(iv);
    }

    private void drawCaption(Slide slide) {
        slide.caption().ifPresent(caption -> {
            captionRenderer.renderCaption(caption);
            captionRenderer.draw(group);
            background
                .heightProperty()
                .bind(captionRenderer
                    .heightProperty()
                    .add(size.height())
                    .add(padding)
                );
        });
    }

    private void clear(Color color) {
        background.setWidth(size.width());
        background.setHeight(size.height());
        clearRect(group, color, background);
    }

    private void centerImageView(ImageView iv) {
        var imageLeft = (size.width() - iv.getFitWidth()) / 2.0;
        var imageTop = (size.height() - iv.getFitHeight()) / 2.0;
        iv.setX(imageLeft);
        iv.setY(imageTop);
    }

    private static void drawImage(Image image, ImageView iv) {
        var shadow = new DropShadow();
        var arc = getImageCornerRadius(image);

        var roundedImage = getRoundedImage(image, iv, arc);

        shadow.setColor(Color.web("#212121"));
        shadow.setRadius(48.0);

        iv.setEffect(shadow);
        iv.setImage(roundedImage);
    }

    private void fitImageView(ImageView iv, Image originalImage) {
        var w = originalImage.getWidth();
        var h = originalImage.getHeight();

        iv.setFitWidth(w);
        iv.setFitHeight(h);

        // If the original image is bigger (out of bound) resize the ImageView
        if (size.width() < w || size.height() < h) {
            if (size.width() < w) {
                var hRatio = iv.getFitHeight() / iv.getFitWidth();

                iv.setFitWidth(size.width());
                iv.setFitHeight(size.width() * hRatio);
            }
            if (size.height() < h) {
                var wRatio = iv.getFitWidth() / iv.getFitHeight();

                iv.setFitWidth(size.height() * wRatio);
                iv.setFitHeight(size.height());
            }
        }
    }
}