Загрузка Image из PDF в базу

Привет, коллеги!
Подскажите, как правильно реализовать такую схему:

  1. В одной форме Edit парсится pdf файл.
  2. Кроме всего прочего из pdf выдергиваются картинки. После ряда преобразований картинка из pdf бывает byte[], BufferedImage или InputStream. :slight_smile:
  3. Если картинок несколько вызывается вспомогательная форма в которой предлагается выбрать одну картинку.
    Снимок экрана 2023-03-07 в 10.00.17
  4. Далее картинка возвращается в исходную форму и надо ее записать в сущность.
    Снимок экрана 2023-03-07 в 10.00.26

На этапе парсинга все работает и изображение из Image вспомогательной формы в которой мы выбираем “правильное” изображение из списка что нашлось в pdf, попадает в основную. Но когда записываешь основную форму в сущность, то при последующем просмотре сущности картинки там не оказывается в Image.
Снимок экрана 2023-03-07 в 10.00.55

Вот код парсинга в основной форме:

        List<RenderedImage> images = new ArrayList<>();

textResume = parsePdfCV(inputStream);
                RandomAccessRead rad = new RandomAccessReadBuffer(fileLoader.openStream(fileDescriptor));

                PDFParser parser = new PDFParser(rad);
                PDDocument pdDoc = parser.parse();
// тут нашли страницы в pdf и ц цикле поместили 
                for (PDPage page : pdDoc.getPages()) {
                    images.addAll(getImagesFromResources(page.getResources()));
                }

                if (images.size() > 1) {
// это вызов вспомогательной формы в которой выбираем из всех картинок найденных в pdf одну
                    SelectRenderedImagesFromList selectRenderedImagesFromList =
                            screens.create(SelectRenderedImagesFromList.class);
                    selectRenderedImagesFromList.setRenderedImages(images);
                    selectRenderedImagesFromList.setCandidateCV(getEditedEntity());

                    selectRenderedImagesFromList.addAfterCloseListener(evnt -> {
// при закрытии формы теперь возвращаем элемент Image который выбрали
                        if (((SelectedCloseAction) evnt.getCloseAction()).getResult()
                                .equals(CandidateCV.SelectedCloseActionType.SELECTED)) {
                            Image selectedImage = selectRenderedImagesFromList
                                    .getSelectedImage();
// готовим размещение этой картинки в Image основной формы
                            FileDescriptor fd = dataManager
                                    .commit(selectRenderedImagesFromList.getSelectedImageFileDescriptor());

                            candidatePic
                                    .setSource(FileDescriptorResource.class)
                                    .setFileDescriptor(fd);
                        }
                    });

                    selectRenderedImagesFromList.show();
                }

ну а тут описание дескриптора элемента Image в основной форме, который привязан к контейнеру данных

                            <image id="candidatePic"
                                   dataContainer="candidateCVDc"
                                   property="fileImageFace"
                                   width="100%"
                                   align="TOP_RIGHT"
                                   height="100%"
                                   stylename="widget-border"
                                   scaleMode="FILL"/>

Итого вопрос: как правильно выгрузив из pdf BufferedImage или InputStream запихать его через Image в контейнер и чтоб записалось в сущность?

Из приведенных фрагментов кода и описания, вижу, что нужное изображение вы в selectedImage получаете.
На форму вы его показываете.
Если selectRenderedImagesFromList.getSelectedImageFileDescriptor() корректно создает дескриптор файла, то FileDescriptor в БД у вас пишется.
Но нигде не вижу чтобы вы загружали выбранное изображение в хранилище.
Это осталось где-то за пределами приведенного кода? Или я это просмотрел?

А если вы этого не делаете - все логично.
Вы отображаете изображение на форме, создаете для него FileDescriptor и камитите его в БД.
Но изображения в файловое хранилище не загружаете и при последующем открытии на экране сущности у вас есть дескриптор описательными данными файла изображения, но самого файла в хранилище нет.
Посмотрите пример работы с файлами. Загрузка файлов - Платформа CUBA. Руководство по разработке приложений (cuba-platform.com)
Там идея понятна. Дескриптор файлов - это метаданные файла + имя файла в хранилище. Кроме создания и камита в БД дескриптора надо еще и сам файл поместить в хранилище.

Если мое предположение верно - вам просто над загрузить выбранное изображение в файловое хранилище.
Посмотрите в документации про FileLoader: Интерфейс FileLoader - Платформа CUBA. Руководство по разработке приложений (cuba-platform.com)
Он умеет сохранять содержимое потока InputStream в хранилище.

Большое спасибо за ответ.

В методе вспомогательной формы, которая выбирает одно из нескольких изображений, SelectRenderedImagesFromList, есть кусок кода которое я взял из документации.

                    selectedImageFileDescriptor = metadata.create(FileDescriptor.class);
                    selectedImageFileDescriptor.setSize((long) bytes.length);
                    selectedImageFileDescriptor.setCreateDate(createDate);
                    selectedImageFileDescriptor.setName(userSession.getUser()
                            + "-"
                            + sdf.format(createDate)); // тут формирую уникальное имя файла в хранилище

                    try {
                        fileLoader.saveStream(selectedImageFileDescriptor,
                                () -> new ByteArrayInputStream(bytes));
                    } catch (FileStorageException e) {
                        notifications.create(Notifications.NotificationType.ERROR)
                                .withCaption(messageBundle.getMessage("msgError"))
                                .withDescription(messageBundle.getMessage("msgErrorSaveFile"))
                                .show();

                        e.printStackTrace();
                    }

Насколько я понял, что тут-то я и загружаю из потока и создаю дискриптор. В доке еще сказано, что я должен переместить из временного хранилища файл в постоянное.

В приведенном выше (что в самом изначальном вопросе) я только что вставил после строки где получаю FileDescriptor (dataManager.commit(…))

                            try {
                                fileUploadingAPI.putFileIntoStorage(fd.getUuid(), fd);
                            } catch (FileStorageException e) {
                                e.printStackTrace();
                            }

Это единственное что мне пришло в голову, что возможно не так. Тем не менее после этих манипуляций при выборе в вспомогательной форме одной из найденных в pdf картинок все как обычно переносится в основную форму, но после записи в базу и открытии резюме с картинкой, получается что изображение не попало в форму.
Я уж думаю, что может записать изображение не с помощью хранилища файлов, в какой нибудь BLOB в базу :slight_smile:

Можно и так, но в общем случае хранение файлов в БД это не есть хорошо…

fileUploadingAPI.putFileIntoStorage(fd.getUuid(), fd); - это явно лишнее.
Не надо путать процесс загрузки изображения с ПК и сохранения в хранилище стрима.

Вот фрагмент кода метода сервиса, который у нас генерирует автар сотрудника-пользователя, сохраняет в шатное хранилище и формирует незакомиченный fileDescriptor:

@Override
public FileDescriptor generateAvatar(Employees employees, Boolean convertPhotoSize) {

        byte[] bytesImage = null;
...
//Генерация PNG аватарки по инициалом пользователя в bytesImage
...
//Формирование дискриптора и сохранение PNG
        String nameImage;
 
        String surname = getTranslateFileName(employees.getSurname().toString());
        nameImage = "avatar_"+surname;
        long numberImage = uniqueNumbersService.getNextNumber(nameImage);

        fileDescriptor = metadata.create(FileDescriptor.class);
        fileDescriptor.setName(nameImage+"("+numberImage+")");
        fileDescriptor.setExtension("png");
        fileDescriptor.setSize((long) bytes.length);
        fileDescriptor.setCreateDate(new Date());

        try {
            byte[] finalBytes = bytesImage;
            fileLoader.saveStream(fileDescriptor, () -> new ByteArrayInputStream(finalBytes));
        } catch (FileStorageException e) {
            throw new RuntimeException(e);
        }

        return fileDescriptor;
}

Посмотрите под отладчиком что там у вас происходит.
Сохраняется ли файл по фату в хранилище (…\work\filestorage).
Прилетает ли оно потом в контейнер candidateCVDc на экран для отображения фото.

Очень похоже на то, что у вас где-то есть мелкий ляп, который трудно увидеть по разрозненным фрагментам кода.

1 симпатия