From f1ffb5cbb086d900df2b8d050d3a1c33052dcc73 Mon Sep 17 00:00:00 2001 From: SemenchenkoA Date: Tue, 31 Mar 2026 17:46:30 +0400 Subject: [PATCH] speed up spring app --- Demos/Spring/configuration.yml | 2 +- .../controller/AnnotationController.java | 32 ++ .../annotation/service/AnnotationService.java | 10 + .../service/AnnotationServiceImpl.java | 469 +++++++++++------- .../main/resources/defaultConfiguration.yml | 2 +- Demos/annotation-spring.iml | 6 + Examples/.idea/.gitignore | 8 + 7 files changed, 342 insertions(+), 187 deletions(-) create mode 100644 Demos/annotation-spring.iml create mode 100644 Examples/.idea/.gitignore diff --git a/Demos/Spring/configuration.yml b/Demos/Spring/configuration.yml index f270a61..ac4599e 100644 --- a/Demos/Spring/configuration.yml +++ b/Demos/Spring/configuration.yml @@ -58,7 +58,7 @@ annotation: # Pages preload # How many pages from a document should be loaded, remaining pages will be loaded on page scrolling # Set 0 to load all pages at once - preloadPageCount: 0 + preloadPageCount: 1 # Fonts path # Absolute path to custom fonts directory fontsDirectory: diff --git a/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/controller/AnnotationController.java b/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/controller/AnnotationController.java index 5ec5e73..fdd7c1f 100644 --- a/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/controller/AnnotationController.java +++ b/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/controller/AnnotationController.java @@ -113,6 +113,38 @@ public PageDataDescriptionEntity loadDocumentPage(@RequestBody LoadDocumentPageR return annotationService.getDocumentPage(loadDocumentPageRequest); } + /** + * Get raw page image (PNG) - avoids Base64/JSON overhead for better performance + * + * @param documentGuid document path + * @param page page number (1-based) + * @param password document password (optional) + * @param response http response with PNG image + */ + @RequestMapping(value = "/pageImage", method = RequestMethod.GET, produces = "image/png") + public void getPageImage(@RequestParam("guid") String documentGuid, + @RequestParam("page") int page, + @RequestParam(value = "password", required = false) String password, + HttpServletResponse response) { + try { + byte[] imageBytes = annotationService.getPageImageBytes(documentGuid, page, password); + + // Enable browser caching + response.setContentType("image/png"); + response.setContentLength(imageBytes.length); + response.setHeader("Cache-Control", "private, max-age=300"); + + String etag = "\"" + documentGuid.hashCode() + "-" + page + "-" + new java.io.File(documentGuid).lastModified() + "\""; + response.setHeader("ETag", etag); + + ServletOutputStream outputStream = response.getOutputStream(); + outputStream.write(imageBytes); + outputStream.flush(); + } catch (Exception ex) { + throw new TotalGroupDocsException(ex.getMessage(), ex); + } + } + /** * Download document * diff --git a/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/service/AnnotationService.java b/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/service/AnnotationService.java index 7c7e5cf..a265ab0 100644 --- a/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/service/AnnotationService.java +++ b/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/service/AnnotationService.java @@ -69,4 +69,14 @@ public interface AnnotationService { * @return stream of annotated document */ InputStream annotateByStream(AnnotationPostedDataEntity annotateDocumentRequest); + + /** + * Get raw page image bytes (PNG) for streaming endpoint + * + * @param guid document path + * @param pageNumber page number (1-based) + * @param password document password (nullable) + * @return PNG image bytes + */ + byte[] getPageImageBytes(String guid, int pageNumber, String password); } diff --git a/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/service/AnnotationServiceImpl.java b/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/service/AnnotationServiceImpl.java index 5bb8d64..539a2eb 100644 --- a/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/service/AnnotationServiceImpl.java +++ b/Demos/Spring/src/main/java/com/groupdocs/ui/annotation/service/AnnotationServiceImpl.java @@ -39,6 +39,7 @@ import java.io.*; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; @@ -59,6 +60,200 @@ public class AnnotationServiceImpl implements AnnotationService { private final List annotationPageDescriptionEntityList = new ArrayList<>(); + // ============================================================ + // Document session cache - keeps Annotator open to avoid + // re-parsing the document (~60s) on every page request + // ============================================================ + private static final ConcurrentHashMap documentSessionCache = new ConcurrentHashMap<>(); + private static final long SESSION_EXPIRY_MS = 30 * 60 * 1000; // 30 minutes + + private static class DocumentSession { + final Annotator annotator; + final IDocumentInfo info; + final List annotations; + final String documentType; + final long lastModified; + volatile long lastAccessTime; + final Object renderLock = new Object(); + + DocumentSession(Annotator annotator, IDocumentInfo info, List annotations, + String documentType, long lastModified) { + this.annotator = annotator; + this.info = info; + this.annotations = annotations; + this.documentType = documentType; + this.lastModified = lastModified; + this.lastAccessTime = System.currentTimeMillis(); + } + + boolean isExpired() { + return System.currentTimeMillis() - lastAccessTime > SESSION_EXPIRY_MS; + } + + void touch() { + this.lastAccessTime = System.currentTimeMillis(); + } + + byte[] renderPage(int pageNumber) { + synchronized (renderLock) { + return renderPageToBytes(annotator, pageNumber); + } + } + + void dispose() { + try { + annotator.dispose(); + } catch (Exception e) { + // ignore dispose errors + } + } + } + + private static String buildSessionKey(String guid) { + return guid; + } + + private DocumentSession getOrCreateSession(String guid, String password) { + String key = buildSessionKey(guid); + long currentLastModified = new File(guid).lastModified(); + + DocumentSession session = documentSessionCache.get(key); + if (session != null && !session.isExpired() && session.lastModified == currentLastModified) { + session.touch(); + return session; + } + + // Evict old session if exists + if (session != null) { + documentSessionCache.remove(key); + session.dispose(); + } + + // Clean up expired sessions + cleanExpiredSessions(); + + logger.debug("Creating new document session for: {}", guid); + long startTime = System.currentTimeMillis(); + + try { + Annotator annotator = new Annotator(guid, getLoadOptions(password)); + IDocumentInfo info = annotator.getDocument().getDocumentInfo(); + List annotations = annotator.get(); + + String documentType = ""; + if (info.getFileType() != null) { + documentType = SupportedImageFormats.contains(info.getFileType().getExtension()) ? "image" : info.getFileType().toString(); + } else { + documentType = "Portable Document Format"; + } + + long elapsed = System.currentTimeMillis() - startTime; + logger.debug("Document session created in {}ms: pageCount={}, fileType={}", elapsed, info.getPageCount(), info.getFileType()); + + DocumentSession newSession = new DocumentSession(annotator, info, annotations, documentType, currentLastModified); + documentSessionCache.put(key, newSession); + return newSession; + } catch (Exception e) { + logger.error("Failed to create document session for: {}", guid, e); + throw new TotalGroupDocsException(e.getMessage(), e); + } + } + + private void invalidateSession(String guid) { + DocumentSession session = documentSessionCache.remove(buildSessionKey(guid)); + if (session != null) { + session.dispose(); + } + } + + private static void cleanExpiredSessions() { + documentSessionCache.entrySet().removeIf(entry -> { + if (entry.getValue().isExpired()) { + entry.getValue().dispose(); + return true; + } + return false; + }); + } + + // ============================================================ + // Page image cache + // ============================================================ + private static final ConcurrentHashMap pageImageCache = new ConcurrentHashMap<>(); + private static final long CACHE_EXPIRY_MS = 30 * 60 * 1000; // 30 minutes + + private static class CacheEntry { + final byte[] data; + final long createdAt; + + CacheEntry(byte[] data) { + this.data = data; + this.createdAt = System.currentTimeMillis(); + } + + boolean isExpired() { + return System.currentTimeMillis() - createdAt > CACHE_EXPIRY_MS; + } + } + + private static String buildImageCacheKey(String guid, long lastModified, int pageNumber) { + return guid + "|" + lastModified + "|" + pageNumber; + } + + private static void cleanExpiredImageCache() { + pageImageCache.entrySet().removeIf(entry -> entry.getValue().isExpired()); + } + + private byte[] getCachedOrRenderPage(DocumentSession session, String guid, int pageNumber) { + String cacheKey = buildImageCacheKey(guid, session.lastModified, pageNumber); + CacheEntry cached = pageImageCache.get(cacheKey); + if (cached != null && !cached.isExpired()) { + return cached.data; + } + + byte[] bytes = session.renderPage(pageNumber); + pageImageCache.put(cacheKey, new CacheEntry(bytes)); + + if (pageImageCache.size() > 500) { + cleanExpiredImageCache(); + } + return bytes; + } + + // ============================================================ + // Rendering helper + // ============================================================ + private static byte[] renderPageToBytes(Annotator annotator, int pageNumberToRender) { + try { + final ByteArrayOutputStream result = new ByteArrayOutputStream(); + PreviewOptions previewOptions = new PreviewOptions( + new CreatePageStream() { + @Override + public OutputStream invoke(int pageNumber) { + return result; + } + } + ); + previewOptions.setPreviewFormat(PreviewFormats.PNG); + previewOptions.setPageNumbers(new int[]{pageNumberToRender}); + previewOptions.setRenderComments(false); + + annotator.getDocument().generatePreview(previewOptions); + return result.toByteArray(); + } catch (Exception ex) { + throw new TotalGroupDocsException(ex); + } + } + + private static LoadOptions getLoadOptions(String password) { + LoadOptions loadOptions = new LoadOptions(); + loadOptions.setPassword(password); + return loadOptions; + } + + // ============================================================ + // Initialization + // ============================================================ @PostConstruct public void init() { try { @@ -71,7 +266,7 @@ public void init() { SupportedImageFormats.add(".dwg"); SupportedImageFormats.add(".dcm"); SupportedImageFormats.add(".dxf"); - + // set GroupDocs license License license = new License(); license.setLicense(globalConfiguration.getApplication().getLicensePath()); @@ -90,6 +285,9 @@ public AnnotationConfiguration getAnnotationConfiguration() { return annotationConfiguration; } + // ============================================================ + // File list + // ============================================================ @Override public List getFileList(FileTreeRequest fileTreeRequest) { String path = fileTreeRequest.getPath(); @@ -125,57 +323,45 @@ public List getFileDescriptionEntities(List filesLi return fileList; } + // ============================================================ + // Document loading (initial open) + // ============================================================ @Override public AnnotatedDocumentEntity getDocumentDescription(LoadDocumentRequest loadDocumentRequest) { try { return loadDocument( - loadDocumentRequest, + loadDocumentRequest, annotationConfiguration.getPreloadPageCount() == 0 ); } catch (Throwable ex) { throw new TotalGroupDocsException(ex); } } - + public final AnnotatedDocumentEntity loadDocument(LoadDocumentRequest loadDocumentRequest, boolean loadAllPages) { - Annotator annotator = null; AnnotatedDocumentEntity description = new AnnotatedDocumentEntity(); String guid = loadDocumentRequest.getGuid(); String password = loadDocumentRequest.getPassword(); - LoadOptions loadOptions = new LoadOptions(); - loadOptions.setPassword(password); - - try { - annotator = new Annotator(guid, loadOptions); - IDocumentInfo info = annotator.getDocument().getDocumentInfo(); - List annotations = annotator.get(); - - description.setGuid(loadDocumentRequest.getGuid()); - - String documentType = ""; - if (info.getFileType() != null) { - documentType = SupportedImageFormats.contains(info.getFileType().getExtension()) ? "image" : info.getFileType().toString(); - } else { - documentType = "Portable Document Format"; - } + try { + DocumentSession session = getOrCreateSession(guid, password); - description.supportedAnnotations = SupportedAnnotations.getSupportedAnnotations(documentType); + description.setGuid(guid); + description.supportedAnnotations = SupportedAnnotations.getSupportedAnnotations(session.documentType); List pagesContent = new ArrayList<>(); - if (loadAllPages) { - pagesContent = getAllPagesContent(password, guid, info); + pagesContent = getAllPagesContent(session, guid); } - for (int i = 0; i < info.getPageCount(); i++) { + for (int i = 0; i < session.info.getPageCount(); i++) { PageDataDescriptionEntity page = new PageDataDescriptionEntity(); page.setNumber(i + 1); - page.setHeight(info.getPagesInfo().get(i).getHeight()); - page.setWidth(info.getPagesInfo().get(i).getWidth()); + page.setHeight(session.info.getPagesInfo().get(i).getHeight()); + page.setWidth(session.info.getPagesInfo().get(i).getWidth()); - if (annotations != null && annotations.size() > 0) { - page.setAnnotations(AnnotationMapper.mapForPage(annotations, i + 1, info.getPagesInfo().get(i))); + if (session.annotations != null && session.annotations.size() > 0) { + page.setAnnotations(AnnotationMapper.mapForPage(session.annotations, i + 1, session.info.getPagesInfo().get(i))); } if (pagesContent.size() > 0) { @@ -183,157 +369,102 @@ public final AnnotatedDocumentEntity loadDocument(LoadDocumentRequest loadDocume } description.getPages().add(page); } - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (annotator != null) { - annotator.dispose(); - } + } catch (Exception e) { + logger.error("Error loading document: {}", guid, e); + throw new TotalGroupDocsException(e.getMessage(), e); } - description.setGuid(guid); - // return document description return description; } - - public static String getStringFromStream(InputStream inputStream) throws IOException { + + public static String getStringFromStream(InputStream inputStream) throws IOException { inputStream.reset(); inputStream.skip(0); - + byte[] bytes = IOUtils.toByteArray(inputStream); // encode ByteArray into String return Base64.getEncoder().encodeToString(bytes); } + // ============================================================ + // Single page loading + // ============================================================ @Override public PageDataDescriptionEntity getDocumentPage(LoadDocumentPageRequest loadDocumentPageRequest) { - String password = ""; try { - // get/set parameters String documentGuid = loadDocumentPageRequest.getGuid(); int pageNumber = loadDocumentPageRequest.getPage(); - password = loadDocumentPageRequest.getPassword(); + String password = loadDocumentPageRequest.getPassword(); PageDataDescriptionEntity loadedPage = new PageDataDescriptionEntity(); - // get page image - byte[] bytes; - - final Annotator annotator = new Annotator(documentGuid, getLoadOptions(password)); - try { - final OutputStream renderPage = renderPageToMemoryStream(pageNumber, documentGuid, password); - - ByteArrayOutputStream bufferRenderPage = (ByteArrayOutputStream) renderPage; - byte[] bytesRenderPage = bufferRenderPage.toByteArray(); - InputStream streamRenderPage = new ByteArrayInputStream(bytesRenderPage); - - try { - bytes = IOUtils.toByteArray(streamRenderPage); - } finally { - if (streamRenderPage != null) { - streamRenderPage.close(); - } - } - - IDocumentInfo info = annotator.getDocument().getDocumentInfo(); - List annotations = annotator.get(); - - if (annotations != null && annotations.size() > 0) { - loadedPage.setAnnotations(AnnotationMapper.mapForPage(annotations, pageNumber, info.getPagesInfo().get(pageNumber - 1))); - } - - String encodedImage = Base64.getEncoder().encodeToString(bytes); - loadedPage.setData(encodedImage); + DocumentSession session = getOrCreateSession(documentGuid, password); - loadedPage.setHeight(info.getPagesInfo().get(pageNumber - 1).getHeight()); - loadedPage.setWidth(info.getPagesInfo().get(pageNumber - 1).getWidth()); - loadedPage.setNumber(pageNumber); - } finally { - if (annotator != null) { - annotator.dispose(); - } + if (session.annotations != null && session.annotations.size() > 0) { + loadedPage.setAnnotations(AnnotationMapper.mapForPage( + session.annotations, pageNumber, + session.info.getPagesInfo().get(pageNumber - 1))); } - // return loaded page object + byte[] bytes = getCachedOrRenderPage(session, documentGuid, pageNumber); + loadedPage.setData(Base64.getEncoder().encodeToString(bytes)); + loadedPage.setHeight(session.info.getPagesInfo().get(pageNumber - 1).getHeight()); + loadedPage.setWidth(session.info.getPagesInfo().get(pageNumber - 1).getWidth()); + loadedPage.setNumber(pageNumber); + return loadedPage; } catch (Exception ex) { throw new TotalGroupDocsException(ex); } } - - private static OutputStream renderPageToMemoryStream(int pageNumberToRender, String documentGuid, String password) { - try { - OutputStream result = new ByteArrayOutputStream(); - InputStream inputStream = new FileInputStream(documentGuid); - try { - final Annotator annotator = new Annotator(inputStream, getLoadOptions(password)); - try { - PreviewOptions previewOptions = new PreviewOptions( - new CreatePageStream() { - @Override - public OutputStream invoke(int pageNumber) { - return result; - } - } - ); - previewOptions.setPreviewFormat(PreviewFormats.PNG); - previewOptions.setPageNumbers(new int[]{pageNumberToRender}); - previewOptions.setRenderComments(false); - annotator.getDocument().generatePreview(previewOptions); - } finally { - if (annotator != null) { - annotator.dispose(); - } - } - } finally { - if (inputStream != null) { - inputStream.close(); - } - } - return result; - } catch (Exception ex) { - throw new TotalGroupDocsException(ex); - } - } - - private static LoadOptions getLoadOptions(String password) { - LoadOptions loadOptions = new LoadOptions(); - loadOptions.setPassword(password); - return loadOptions; + // ============================================================ + // Streaming image endpoint (raw PNG) + // ============================================================ + @Override + public byte[] getPageImageBytes(String guid, int pageNumber, String password) { + DocumentSession session = getOrCreateSession(guid, password); + return getCachedOrRenderPage(session, guid, pageNumber); } + // ============================================================ + // Annotation operations + // ============================================================ public InputStream annotateDocument(String documentGuid, String documentType, List annotations) throws FileNotFoundException { + // Invalidate session since document will be modified + invalidateSession(documentGuid); + Annotator annotator = new Annotator(documentGuid); - + SaveOptions saveOptions = new SaveOptions(); saveOptions.setAnnotationTypes(AnnotationType.NONE); - + annotator.save(documentGuid, saveOptions); - + if (annotations.size() > 0) { annotator.add(annotations); annotator.save(documentGuid, new SaveOptions()); } - + return new FileInputStream(documentGuid); } - + @Override public AnnotatedDocumentEntity annotate(AnnotationPostedDataEntity annotateDocumentRequest) { AnnotatedDocumentEntity annotatedDocument = new AnnotatedDocumentEntity(); try { - // get/set parameters String documentGuid = annotateDocumentRequest.getGuid(); String password = annotateDocumentRequest.getPassword(); + // Invalidate cached session since we're modifying the document + invalidateSession(documentGuid); + String documentType = SupportedImageFormats.contains( FilenameUtils.getExtension(annotateDocumentRequest.getGuid()) ) ? "image" : annotateDocumentRequest.getDocumentType(); - + String tempPath = getTempPath(documentGuid); AnnotationDataEntity[] annotationsData = annotateDocumentRequest.getAnnotationsData(); - // initiate list of annotations to add List annotations = new ArrayList<>(); final Annotator annotator = new Annotator(documentGuid, getLoadOptions(password)); @@ -342,8 +473,7 @@ public AnnotatedDocumentEntity annotate(AnnotationPostedDataEntity annotateDocum for (int i = 0; i < annotationsData.length; i++) { AnnotationDataEntity annotationData = annotationsData[i]; - PageInfo pageInfo = info.getPagesInfo().get(annotationsData[i].getPageNumber() - 1);//-1 - // add annotation, if current annotation type isn't supported by the current document type it will be ignored + PageInfo pageInfo = info.getPagesInfo().get(annotationsData[i].getPageNumber() - 1); try { BaseAnnotator baseAnnotator = AnnotatorFactory.createAnnotator(annotationData, pageInfo); if (baseAnnotator.isSupported(documentType)) { @@ -359,13 +489,10 @@ public AnnotatedDocumentEntity annotate(AnnotationPostedDataEntity annotateDocum } } - // Add annotation to the document removeAnnotations(documentGuid, password); - // check if annotations array contains at least one annotation to add if (annotations.size() != 0) { final Annotator annotator1 = new Annotator(documentGuid, getLoadOptions(password)); try { - //foreach to while statements conversion Iterator tmp0 = (annotations).iterator(); while (tmp0.hasNext()) { @@ -393,42 +520,26 @@ public AnnotatedDocumentEntity annotate(AnnotationPostedDataEntity annotateDocum Files.move(Paths.get(documentGuid), Paths.get(annotateDocumentRequest.getGuid())); } } catch (Exception ex) { - // set exception message throw new TotalGroupDocsException(ex); } return annotatedDocument; - } - + private List getAnnotatedPagesForPrint(String password, String documentGuid) { AnnotatedDocumentEntity description = new AnnotatedDocumentEntity(); try { - InputStream outputStream = new FileInputStream(documentGuid); - try { - final Annotator annotator = new Annotator(outputStream, getLoadOptions(password)); - try { - IDocumentInfo info = annotator.getDocument().getDocumentInfo(); - List pagesContent = getAllPagesContent(password, documentGuid, info); - - for (int i = 0; i < info.getPageCount(); i++) { - PageDataDescriptionEntity page = new PageDataDescriptionEntity(); + DocumentSession session = getOrCreateSession(documentGuid, password); + List pagesContent = getAllPagesContent(session, documentGuid); - if (pagesContent.size() > 0) { - page.setData(pagesContent.get(i)); - } + for (int i = 0; i < session.info.getPageCount(); i++) { + PageDataDescriptionEntity page = new PageDataDescriptionEntity(); - description.getPages().add(page); - } - } finally { - if (annotator != null) { - annotator.dispose(); - } - } - } finally { - if (outputStream != null) { - outputStream.close(); + if (pagesContent.size() > 0) { + page.setData(pagesContent.get(i)); } + + description.getPages().add(page); } return description.getPages(); @@ -436,18 +547,17 @@ private List getAnnotatedPagesForPrint(String passwor throw new TotalGroupDocsException(ex.getMessage(), ex); } } - + private static String getTempPath(String documentGuid) { File fileName = new File(documentGuid); return fileName.getParentFile().getPath() + "//tmp_" + fileName.getName(); } - + public static void removeAnnotations(String documentGuid, String password) { String tempPath = getTempPath(documentGuid); try { final InputStream inputStream = new FileInputStream(documentGuid); - //final Stream inputStream = File.open(documentGuid, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); try { final Annotator annotator = new Annotator(inputStream, getLoadOptions(password)); try { @@ -464,12 +574,12 @@ public static void removeAnnotations(String documentGuid, String password) { inputStream.close(); } } - - - try (PrintWriter writer = new PrintWriter(documentGuid)) { - writer.print(""); + + + try (PrintWriter writer = new PrintWriter(documentGuid)) { + writer.print(""); } - + try (OutputStream fileStream = new FileOutputStream(documentGuid)) { InputStream inputStream1 = new FileInputStream(tempPath); IOUtils.copyLarge(inputStream1, fileStream); @@ -478,21 +588,13 @@ public static void removeAnnotations(String documentGuid, String password) { throw new TotalGroupDocsException(ex.getMessage(), ex); } } - - private List getAllPagesContent(String password, String documentGuid, IDocumentInfo pages) { - List allPages = new ArrayList<>(); - for (int i = 0; i < pages.getPageCount(); i++) { - byte[] bytes; - try (OutputStream memoryStream = renderPageToMemoryStream(i + 1, documentGuid, password)) { - ByteArrayOutputStream bos = (ByteArrayOutputStream) memoryStream; - bytes = bos.toByteArray(); - } catch (IOException ex) { - throw new TotalGroupDocsException(ex.getMessage(), ex); - } + private List getAllPagesContent(DocumentSession session, String documentGuid) { + List allPages = new ArrayList<>(); - String encodedImage = new String(Base64.getEncoder().encode(bytes)); - allPages.add(encodedImage); + for (int i = 0; i < session.info.getPageCount(); i++) { + byte[] bytes = getCachedOrRenderPage(session, documentGuid, i + 1); + allPages.add(Base64.getEncoder().encodeToString(bytes)); } return allPages; @@ -501,18 +603,15 @@ private List getAllPagesContent(String password, String documentGuid, ID public List getAnnotationInfos(AnnotationPostedDataEntity annotateDocumentRequest, String documentType) { try { AnnotationDataEntity[] annotationsData = annotateDocumentRequest.getAnnotationsData(); - // get document info - required to get document page height and calculate annotation top position List annotations = new ArrayList<>(); for (AnnotationDataEntity annotationData : annotationsData) { - // create annotator - // add annotation, if current annotation type isn't supported by the current document type it will be ignored - PageDataDescriptionEntity pageData = annotationPageDescriptionEntityList.get(annotationData.getPageNumber() - 1);//-1 - - PageInfo pageInfo = new PageInfo(); + PageDataDescriptionEntity pageData = annotationPageDescriptionEntityList.get(annotationData.getPageNumber() - 1); + + PageInfo pageInfo = new PageInfo(); pageInfo.setHeight((int) pageData.getHeight()); pageInfo.setWidth((int) pageData.getWidth()); - + try { annotations.add(AnnotatorFactory.createAnnotator(annotationData, pageInfo).getAnnotationBase(documentType)); } catch (Throwable ex) { @@ -536,4 +635,4 @@ public InputStream annotateByStream(AnnotationPostedDataEntity annotateDocumentR throw new TotalGroupDocsException(ex.getMessage(), ex); } } -} \ No newline at end of file +} diff --git a/Demos/Spring/src/main/resources/defaultConfiguration.yml b/Demos/Spring/src/main/resources/defaultConfiguration.yml index 6543f7e..1225b06 100644 --- a/Demos/Spring/src/main/resources/defaultConfiguration.yml +++ b/Demos/Spring/src/main/resources/defaultConfiguration.yml @@ -58,7 +58,7 @@ annotation: # Pages preload # How many pages from a document should be loaded, remaining pages will be loaded on page scrolling # Set 0 to load all pages at once - preloadPageCount: 0 + preloadPageCount: 1 # Fonts path # Absolute path to custom fonts directory fontsDirectory: diff --git a/Demos/annotation-spring.iml b/Demos/annotation-spring.iml new file mode 100644 index 0000000..dec6098 --- /dev/null +++ b/Demos/annotation-spring.iml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Examples/.idea/.gitignore b/Examples/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/Examples/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml