|
| 1 | +''' |
| 2 | +' What this sample does: |
| 3 | +' - Merges multiple inputs (PDFs and non-PDFs) into a single PDF. |
| 4 | +' - Non-PDF files are first converted to PDF; PDFs are uploaded as-is. All resulting IDs are then merged. |
| 5 | +' |
| 6 | +' Setup (environment): |
| 7 | +' - Copy .env.example to .env |
| 8 | +' - Set PDFREST_API_KEY=your_api_key_here |
| 9 | +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: |
| 10 | +' PDFREST_URL=https://eu-api.pdfrest.com |
| 11 | +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work |
| 12 | +' |
| 13 | +' Usage (via dispatcher): |
| 14 | +' dotnet run --project VBNetSamples.vbproj -- merge-different-file-types /path/to/file1 /path/to/file2 [...] |
| 15 | +' |
| 16 | +' Output: |
| 17 | +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. |
| 18 | +' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- merge-different-file-types ... > response.json |
| 19 | +''' |
| 20 | + |
| 21 | +Option Strict On |
| 22 | +Option Explicit On |
| 23 | + |
| 24 | +Imports System |
| 25 | +Imports System.Collections.Generic |
| 26 | +Imports System.IO |
| 27 | +Imports System.Net.Http |
| 28 | +Imports System.Net.Http.Headers |
| 29 | +Imports System.Text |
| 30 | +Imports System.Text.Json |
| 31 | +Imports System.Threading.Tasks |
| 32 | + |
| 33 | +Namespace VBNetSamples.Complex_Flow_Examples |
| 34 | + Module MergeDifferentFileTypes |
| 35 | + Public Async Function Execute(args As String()) As Task |
| 36 | + If args Is Nothing OrElse args.Length < 2 Then |
| 37 | + Console.Error.WriteLine("Usage: dotnet run -- merge-different-file-types /path/to/file1 /path/to/file2 [/path/to/file3 ...]") |
| 38 | + Environment.Exit(1) |
| 39 | + End If |
| 40 | + |
| 41 | + Dim allExist = Array.TrueForAll(args, Function(p) File.Exists(p)) |
| 42 | + If Not allExist Then |
| 43 | + Console.Error.WriteLine("One or more input files do not exist.") |
| 44 | + Environment.Exit(1) |
| 45 | + End If |
| 46 | + |
| 47 | + Dim apiKey As String = Environment.GetEnvironmentVariable("PDFREST_API_KEY") |
| 48 | + If String.IsNullOrWhiteSpace(apiKey) Then |
| 49 | + Console.Error.WriteLine("Missing environment variable PDFREST_API_KEY.") |
| 50 | + Environment.Exit(1) |
| 51 | + End If |
| 52 | + |
| 53 | + Dim baseUrl As String = Environment.GetEnvironmentVariable("PDFREST_URL") |
| 54 | + If String.IsNullOrWhiteSpace(baseUrl) Then baseUrl = "https://api.pdfrest.com" |
| 55 | + |
| 56 | + Dim baseUri As Uri |
| 57 | + Try |
| 58 | + baseUri = New Uri(baseUrl) |
| 59 | + Catch ex As Exception |
| 60 | + Console.Error.WriteLine($"Invalid PDFREST_URL: {baseUrl}") |
| 61 | + Environment.Exit(1) |
| 62 | + Return |
| 63 | + End Try |
| 64 | + |
| 65 | + Using httpClient As New HttpClient() |
| 66 | + httpClient.BaseAddress = baseUri |
| 67 | + |
| 68 | + Dim collectedIds As New List(Of String)() |
| 69 | + |
| 70 | + For i = 0 To args.Length - 1 |
| 71 | + Dim p As String = args(i) |
| 72 | + Dim ext As String = Path.GetExtension(p).ToLowerInvariant() |
| 73 | + If ext = ".pdf" Then |
| 74 | + ' Upload PDFs to get an id |
| 75 | + Dim uploadReq As New HttpRequestMessage(HttpMethod.Post, "upload") |
| 76 | + uploadReq.Headers.TryAddWithoutValidation("Api-Key", apiKey) |
| 77 | + uploadReq.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) |
| 78 | + |
| 79 | + Dim pdfBytes As Byte() = File.ReadAllBytes(p) |
| 80 | + Dim uploadContent As New ByteArrayContent(pdfBytes) |
| 81 | + uploadContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream") |
| 82 | + uploadContent.Headers.TryAddWithoutValidation("Content-Filename", Path.GetFileName(p)) |
| 83 | + uploadReq.Content = uploadContent |
| 84 | + |
| 85 | + Dim uploadResp = Await httpClient.SendAsync(uploadReq) |
| 86 | + Dim uploadBody = Await uploadResp.Content.ReadAsStringAsync() |
| 87 | + If Not uploadResp.IsSuccessStatusCode Then |
| 88 | + Console.Error.WriteLine($"Upload failed for input #{i + 1}: {CInt(uploadResp.StatusCode)} {uploadResp.ReasonPhrase}") |
| 89 | + Console.Error.WriteLine(uploadBody) |
| 90 | + Environment.Exit(1) |
| 91 | + End If |
| 92 | + |
| 93 | + Dim id As String = Nothing |
| 94 | + Using doc = JsonDocument.Parse(uploadBody) |
| 95 | + id = doc.RootElement.GetProperty("files")(0).GetProperty("id").GetString() |
| 96 | + End Using |
| 97 | + collectedIds.Add(id) |
| 98 | + Else |
| 99 | + ' Convert non-PDF to PDF to get an outputId |
| 100 | + Dim multipart As New MultipartFormDataContent() |
| 101 | + Dim fileBytes As Byte() = File.ReadAllBytes(p) |
| 102 | + Dim fileContent As New ByteArrayContent(fileBytes) |
| 103 | + fileContent.Headers.ContentType = New MediaTypeHeaderValue(ContentTypeFor(p)) |
| 104 | + multipart.Add(fileContent, "file", Path.GetFileName(p)) |
| 105 | + |
| 106 | + Dim convReq As New HttpRequestMessage(HttpMethod.Post, "pdf") |
| 107 | + convReq.Headers.TryAddWithoutValidation("Api-Key", apiKey) |
| 108 | + convReq.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) |
| 109 | + convReq.Content = multipart |
| 110 | + |
| 111 | + Dim convResp = Await httpClient.SendAsync(convReq) |
| 112 | + Dim convBody = Await convResp.Content.ReadAsStringAsync() |
| 113 | + If Not convResp.IsSuccessStatusCode Then |
| 114 | + Console.Error.WriteLine($"Conversion failed for input #{i + 1}: {CInt(convResp.StatusCode)} {convResp.ReasonPhrase}") |
| 115 | + Console.Error.WriteLine(convBody) |
| 116 | + Environment.Exit(1) |
| 117 | + End If |
| 118 | + |
| 119 | + Using doc = JsonDocument.Parse(convBody) |
| 120 | + Dim outputId = doc.RootElement.GetProperty("outputId").GetString() |
| 121 | + collectedIds.Add(outputId) |
| 122 | + End Using |
| 123 | + End If |
| 124 | + Next |
| 125 | + |
| 126 | + ' Build x-www-form-urlencoded body with arrays |
| 127 | + Dim pairs As New List(Of KeyValuePair(Of String, String))() |
| 128 | + For Each id In collectedIds |
| 129 | + pairs.Add(New KeyValuePair(Of String, String)("id[]", id)) |
| 130 | + pairs.Add(New KeyValuePair(Of String, String)("pages[]", "1-last")) |
| 131 | + pairs.Add(New KeyValuePair(Of String, String)("type[]", "id")) |
| 132 | + Next |
| 133 | + |
| 134 | + Dim mergeReq As New HttpRequestMessage(HttpMethod.Post, "merged-pdf") |
| 135 | + mergeReq.Headers.TryAddWithoutValidation("Api-Key", apiKey) |
| 136 | + mergeReq.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) |
| 137 | + mergeReq.Content = New FormUrlEncodedContent(pairs) |
| 138 | + |
| 139 | + Dim mergeResp = Await httpClient.SendAsync(mergeReq) |
| 140 | + Dim mergeBody = Await mergeResp.Content.ReadAsStringAsync() |
| 141 | + If Not mergeResp.IsSuccessStatusCode Then |
| 142 | + Console.Error.WriteLine($"Merge failed: {CInt(mergeResp.StatusCode)} {mergeResp.ReasonPhrase}") |
| 143 | + Console.Error.WriteLine(mergeBody) |
| 144 | + Environment.Exit(1) |
| 145 | + End If |
| 146 | + |
| 147 | + Console.WriteLine(mergeBody) |
| 148 | + End Using |
| 149 | + End Function |
| 150 | + |
| 151 | + Private Function ContentTypeFor(filePath As String) As String |
| 152 | + Dim ext = System.IO.Path.GetExtension(filePath).ToLowerInvariant() |
| 153 | + Select Case ext |
| 154 | + Case ".pdf" : Return "application/pdf" |
| 155 | + Case ".png" : Return "image/png" |
| 156 | + Case ".jpg", ".jpeg" : Return "image/jpeg" |
| 157 | + Case ".gif" : Return "image/gif" |
| 158 | + Case ".tif", ".tiff" : Return "image/tiff" |
| 159 | + Case ".bmp" : Return "image/bmp" |
| 160 | + Case ".webp" : Return "image/webp" |
| 161 | + Case ".doc" : Return "application/msword" |
| 162 | + Case ".docx" : Return "application/vnd.openxmlformats-officedocument.wordprocessingml.document" |
| 163 | + Case ".ppt" : Return "application/vnd.ms-powerpoint" |
| 164 | + Case ".pptx" : Return "application/vnd.openxmlformats-officedocument.presentationml.presentation" |
| 165 | + Case ".xls" : Return "application/vnd.ms-excel" |
| 166 | + Case ".xlsx" : Return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" |
| 167 | + Case ".txt" : Return "text/plain" |
| 168 | + Case ".rtf" : Return "application/rtf" |
| 169 | + Case ".html", ".htm" : Return "text/html" |
| 170 | + Case Else : Return "application/octet-stream" |
| 171 | + End Select |
| 172 | + End Function |
| 173 | + End Module |
| 174 | +End Namespace |
0 commit comments