public async Task CreatePDF(PDFItem pDFItem) => await Task.Run(async () => { byte[] bytes = null; using (var oriStream = new MemoryStream()) { if (pDFItem.OriFileData == null) { byte[] pdfBytes = await new DbHandler().GetOriFileData(pDFItem.ID); if (pdfBytes != null) pDFItem.OriFileData = pdfBytes; else { _logManager.Log(LogLevel.Error, $"Error creating PDF: no file data found in DB"); return bytes; } } oriStream.Write(pDFItem.OriFileData, 0, pDFItem.OriFileData.Length); oriStream.Position = 0; var ext = Path.GetExtension(pDFItem.FileName).ToLower(); if (!string.IsNullOrEmpty(ext) && General.isValidFile(pDFItem.FileName)) { try { //Cropboxes are not correctly handled by the document analysis service, so we need to correct them here using (PDFDoc sourceDoc = new PDFDoc(oriStream)) { sourceDoc.InitSecurityHandler(); // Create a new PDF document using (PDFDoc newDoc = new PDFDoc()) { //First add all pages to the new document for (int i = 1; i <= sourceDoc.GetPageCount(); i++) { newDoc.PagePushBack(sourceDoc.GetPage(i)); } int NrOfPages = newDoc.GetPageCount(); //Then check if the cropbox is different from the mediabox and if so, create a new page with the cropbox content for (int i = 1; i <= NrOfPages; i++) { pdftron.PDF.Page sourcePage = newDoc.GetPage(i); Rect cropBox = sourcePage.GetCropBox(); Rect mediaBox = sourcePage.GetMediaBox(); //Check if we have a cropBox which is smaller/larger than the mediaBox if (cropBox.x1 != mediaBox.x1 || cropBox.y1 != mediaBox.y1 || cropBox.x2 != mediaBox.x2 || cropBox.y2 != mediaBox.y2) { double offsetX = -cropBox.x1; double offsetY = -cropBox.y1; // Add a new page to the PDFTRON document pdftron.PDF.Page newPage = newDoc.PageCreate(new Rect(0, 0, cropBox.Width(), cropBox.Height())); Matrix2D transform = new Matrix2D(1, 0, 0, 1, offsetX / 2, offsetY / 2); ElementReader reader = new ElementReader(); ElementWriter writer = new ElementWriter(); reader.Begin(sourcePage); writer.Begin(newPage); Element element; while ((element = reader.Next()) != null) { // Apply the transformation to the element element.GetGState().SetTransform(transform); // Write the transformed element to the new page writer.WriteElement(element); } reader.End(); writer.End(); newDoc.PagePushBack(newPage); } else newDoc.PagePushBack(sourcePage); } //Remove initial pages for (int i = 1; i <= NrOfPages; i++) { newDoc.PageRemove(newDoc.GetPageIterator(1)); } // Save the new document using (MemoryStream msOut = new MemoryStream()) { newDoc.Save(msOut, SDFDoc.SaveOptions.e_linearized); bytes = msOut.ToArray(); } newDoc.Close(); } } } catch (Exception ex) { _logManager.Log(LogLevel.Error, $"Error creating PDF: {ex.Message}"); return bytes; } } else { _logManager.Log(LogLevel.Error, "Invalid file extension"); return bytes; } } return bytes; }); private async Task RetrieveSpdfAsync() => await Task.Run(async () => { try { string apiVersion = "2024-07-31-preview"; string ocrJsonUrl = string.Empty; string pdfUrl = string.Empty; bool isPdfDownloaded = false; var uploadToDocumentAnalysisTask = Task.Run(async () => { try { using (var stream = new MemoryStream()) { stream.Write(_pdfItem.OriFileData, 0, _pdfItem.OriFileData.Length); stream.Position = 0; using (var httpClient = new HttpClient()) { httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key); string url = $"{endpoint}/documentintelligence/documentModels/prebuilt-read:analyze?api-version={apiVersion}&output=pdf"; var content = new StreamContent(stream); content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); HttpResponseMessage response = await httpClient.PostAsync(url, content); if (response.IsSuccessStatusCode) { // Extract the operation-location header string operationLocation = response.Headers.GetValues("operation-location").FirstOrDefault(); if (operationLocation != null) { // The operation ID is part of the URL returned in operation-location string resultId = operationLocation.Split('/').Last().Split('?').First(); _logManager.Log(LogLevel.Info, $"Document submitted. Result ID: {resultId}"); ocrJsonUrl = operationLocation; pdfUrl = operationLocation.Replace("?", "/pdf?"); } } } } } catch { return false; } return pdfUrl != string.Empty; }); var exec1 = Task.WhenAny(uploadToDocumentAnalysisTask, Task.Delay(TimeSpan.FromMinutes(10))); if (exec1.Result == uploadToDocumentAnalysisTask) { if (!uploadToDocumentAnalysisTask.Result) { _logManager.Log(LogLevel.Error, $"Error sending file {_pdfItem.FileName} to Form Recognizer"); return false; } var downloadPdfTask = Task.Run(async () => { try { int maxRetries = 10; int retryInterval = 2000; int retryCount = 0; do { using (var httpClient = new HttpClient()) { httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key); HttpResponseMessage response = await httpClient.GetAsync(pdfUrl); if (response.IsSuccessStatusCode && response.Content.Headers.ContentType.ToString().ToLower() == "application/pdf") { byte[] pdfData = await response.Content.ReadAsByteArrayAsync(); //Store the downloaded searchable PDF to the database using (var dbHandler = new DbHandler()) await Task.Run(() => dbHandler.AddOcrData(_pdfItem.ID, SqlEntry.StatusEnum.OcrCompleted, pdfData)); isPdfDownloaded = true; _logManager.Log(LogLevel.Info, $"Directly downloaded searchable pdf {_pdfItem.FileName} from Form Recognizer"); break; } } await Task.Delay(retryInterval); retryCount++; } while (retryCount < maxRetries); } catch { return false; } return isPdfDownloaded; }); var exec2 = Task.WhenAny(downloadPdfTask, Task.Delay(TimeSpan.FromMinutes(10))); if (exec2.Result == downloadPdfTask) { if (!downloadPdfTask.Result) { _logManager.Log(LogLevel.Error, $"Error downloading file {_pdfItem.FileName} from Form Recognizer"); return false; } else return true; } else { _logManager.Log(LogLevel.Error, $"Error downloading file {_pdfItem.FileName} from Form Recognizer within time limit"); return false; } } else { _logManager.Log(LogLevel.Error, $"Error sending file {_pdfItem.FileName} to Form Recognizer within time limit"); return false; } } catch (Exception ex) { _logManager.Log(LogLevel.Error, $"Error processing file {_pdfItem.FileName}: {ex.Message}"); return false; } });