class PDFRenderTargetBuilder implements RenderTargetBuilder {

    @Override
    public String getName() {
        return RenderTarget.PDF_TARGET;
    }

    @Override
    public RenderTarget buildRenderTarget(PreviewModel previewModel) {<FILL_FUNCTION_BODY>}

    public static class PDFRenderTargetImpl extends AbstractRenderTarget implements PDFTarget {

        private final PDPageContentStream cb;
        private final PDDocument document;
        //Parameters
        private final float marginTop;
        private final float marginBottom;
        private final float marginLeft;
        private final float marginRight;
        private final boolean landscape;
        private final PDRectangle pageSize;

        private Map<String, PDFont> fontMap;

        public PDFRenderTargetImpl(
            PDDocument doc,
            PDPageContentStream cb,
            CanvasSize cs,
            PDRectangle size,
            Color backgroundColor,
            float marginLeft,
            float marginRight,
            float marginTop,
            float marginBottom,
            boolean landscape) {
            this.document = doc;
            this.cb = cb;
            this.marginTop = marginTop;
            this.marginLeft = marginLeft;
            this.marginBottom = marginBottom;
            this.marginRight = marginRight;
            this.pageSize = size;
            this.landscape = landscape;
            this.fontMap = new HashMap<>();

            double centerX = cs.getX() + cs.getWidth() / 2;
            double centerY = cs.getY() + cs.getHeight() / 2;

            //Transform
            double pageWidth = size.getWidth() - marginLeft - marginRight;
            double pageHeight = size.getHeight() - marginTop - marginBottom;
            double ratioWidth = pageWidth / cs.getWidth();
            double ratioHeight = pageHeight / cs.getHeight();
            double scale = (float) (ratioWidth < ratioHeight ? ratioWidth : ratioHeight);
            double translateX = (marginLeft + pageWidth / 2.) / scale;
            double translateY = (marginBottom + pageHeight / 2.) / scale;
            try {
                // Background
                if (backgroundColor != null) {
                    cb.setNonStrokingColor(backgroundColor);
                    cb.addRect(0, 0, size.getWidth(), size.getHeight());
                    cb.fill();
                }

                // Transformations
                cb.transform(Matrix.getTranslateInstance((float) (-centerX * scale), (float) (centerY * scale)));
                cb.transform(Matrix.getScaleInstance((float) scale, (float) scale));
                cb.transform(Matrix.getTranslateInstance((float) translateX, (float) translateY));
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }

        @Override
        public PDPageContentStream getContentStream() {
            return this.cb;
        }

        public PDFont getPDFont(java.awt.Font font) {
            final String fontKey = getFontKey(font);
            return fontMap.computeIfAbsent(fontKey, (key) -> {
                FontMapping<TrueTypeFont> mapping = FontMappers.instance().getTrueTypeFont(fontKey, null);
                if (mapping != null) {
                    try {
                        return PDType0Font.load(document, mapping.getFont(), true);
                    } catch (IOException ex) {
                        Exceptions.printStackTrace(ex);
                    }
                }
                return PDType1Font.HELVETICA;
            });
        }

        private static String getFontKey(Font font) {
            StringBuilder name = new StringBuilder(font.getName().replace(" ", "-"));
            if (font.isBold()) {
                name.append("-Bold");
            }
            if (font.isItalic()) {
                name.append("-Italic");
            }

            return name.toString();
        }

        @Override
        public float getMarginBottom() {
            return marginBottom;
        }

        @Override
        public float getMarginLeft() {
            return marginLeft;
        }

        @Override
        public float getMarginRight() {
            return marginRight;
        }

        @Override
        public float getMarginTop() {
            return marginTop;
        }

        @Override
        public boolean isLandscape() {
            return landscape;
        }

        @Override
        public PDRectangle getPageSize() {
            return pageSize;
        }
    }
}

        CanvasSize cs = previewModel.getGraphicsCanvasSize();
        PreviewProperties properties = previewModel.getProperties();
        float marginBottom = properties.getFloatValue(PDFTarget.MARGIN_BOTTOM);
        float marginLeft = properties.getFloatValue(PDFTarget.MARGIN_LEFT);
        float marginRight = properties.getFloatValue(PDFTarget.MARGIN_RIGHT);
        float marginTop = properties.getFloatValue(PDFTarget.MARGIN_TOP);
        final PDRectangle pageSize = properties.getValue(PDFTarget.PAGESIZE);
        boolean landscape = properties.getBooleanValue(PDFTarget.LANDSCAPE);
        boolean transparentBackground = properties.getBooleanValue(PDFTarget.TRANSPARENT_BACKGROUND);
        Color backgroundColor = transparentBackground ? null : properties.getColorValue(PreviewProperty.BACKGROUND_COLOR);
        PDPageContentStream cb = properties.getValue(PDFTarget.PDF_CONTENT_BYTE);
        PDDocument doc = properties.getValue(PDFTarget.PDF_DOCUMENT);
        PDFRenderTargetImpl renderTarget = new PDFRenderTargetImpl(
            doc,
            cb,
            cs,
            pageSize,
            backgroundColor,
            marginLeft,
            marginRight,
            marginTop,
            marginBottom,
            landscape);
        return renderTarget;
    
<no_super_class>