diff --git a/Perl/.env.example b/Perl/.env.example new file mode 100644 index 00000000..82c65d4c --- /dev/null +++ b/Perl/.env.example @@ -0,0 +1,4 @@ +PDFREST_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +# Optional: Override API base URL (default https://api.pdfrest.com) +# PDFREST_URL=https://eu-api.pdfrest.com/ +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work diff --git a/Perl/.gitignore b/Perl/.gitignore new file mode 100644 index 00000000..80850866 --- /dev/null +++ b/Perl/.gitignore @@ -0,0 +1,44 @@ +# Created by https://www.toptal.com/developers/gitignore/api/perl +# Edit at https://www.toptal.com/developers/gitignore?templates=perl + +### Perl ### +!Build/ +.last_cover_stats +/META.yml +/META.json +/MYMETA.* +*.o +*.pm.tdy +*.bs + +# Devel::Cover +cover_db/ + +# Devel::NYTProf +nytprof.out + +# Dist::Zilla +/.build/ + +# Module::Build +_build/ +Build +Build.bat + +# Module::Install +inc/ + +# ExtUtils::MakeMaker +/blib/ +/_eumm/ +/*.gz +/Makefile +/Makefile.old +/MANIFEST.bak +/pm_to_blib +/*.zip + +# Carton +local/ + +# End of https://www.toptal.com/developers/gitignore/api/perl \ No newline at end of file diff --git a/Perl/AGENTS.md b/Perl/AGENTS.md new file mode 100644 index 00000000..acac095e --- /dev/null +++ b/Perl/AGENTS.md @@ -0,0 +1,100 @@ +# Repository Guidelines + +## Project Structure & Module Organization +- `Endpoint Examples/JSON Payload/`: Two-step samples (upload then operate), e.g., `markdown.pl`. +- `Endpoint Examples/Multipart Payload/`: Single multipart request samples, e.g., `rasterized-pdf.pl`. +- `Complex Flow Examples/`: Multi-step workflows that chain endpoints. +- `.env.example` → copy to `.env` and set `PDFREST_API_KEY`; optional `PDFREST_URL`. +- `README.md`: Setup and usage details for this language folder. + +## Build, Test, and Development Commands +- Install deps from `cpanfile` (recommended): + - `cpanm --installdeps .` +- macOS quick setup: `make install-macos` or run `scripts/setup-macos.sh` +- Run JSON sample: + - `perl "Endpoint Examples/JSON Payload/markdown.pl" /path/to/input.pdf` +- Run Multipart sample: + - `perl "Endpoint Examples/Multipart Payload/rasterized-pdf.pl" /path/to/input.pdf` +- Capture output to file: append `> response.json` + + +## Coding Style & Naming Conventions +- Indentation: 4 spaces; enable `use strict; use warnings; use utf8;` at top. +- Naming: `snake_case` for files/variables; script names mirror endpoints (e.g., `markdown.pl`). +- HTTP: prefer `LWP::UserAgent` + `HTTP::Request::Common`. + - Base URL: `$ENV{PDFREST_URL} // 'https://api.pdfrest.com'`. +- I/O: print API responses to STDOUT; send diagnostics to STDERR; exit non‑2xx with non‑zero status. + +### Environment Loading +- Use `Dotenv` to read `.env` into `%ENV` (do not hand‑roll parsing). +- Add dependency in `cpanfile`: `requires 'Dotenv';`. +- Load with a guarded call so missing files are fine: + - JSON/Multipart examples: `my $env_path = "$Bin/../../.env"; -e $env_path and Dotenv->load($env_path);` + - Complex Flow examples: `my $env_path = "$Bin/../.env"; -e $env_path and Dotenv->load($env_path);` +- Do not override pre‑existing environment variables; rely on library defaults (no explicit override). + +## Testing Guidelines +- No formal test suite required for samples. Validate by running against small, known inputs. +- Success: non‑zero exit on failures; JSON body printed to STDOUT on success. +- If adding tests, use `Test::More` under `t/` and run with `prove -lr t`. + +## Commit & Pull Request Guidelines +- Commits: imperative, scoped, and reference endpoint/path (e.g., "Add multipart markdown sample"). +- PRs: include what/why, run commands used for verification, expected response snippet, and linked issues. +- Avoid unrelated changes or large binaries. + +## Security & Configuration Tips +- Do not commit secrets. Provide `.env.example`; load `PDFREST_API_KEY` from environment. +- Optional region override: `PDFREST_URL=https://eu-api.pdfrest.com/` for EU/GDPR routing. +- Never print API keys; rely on concise error messages. Respect proxies via `HTTPS_PROXY` when needed. + +## Troubleshooting +- HTTPS support missing: install `LWP::Protocol::https` and `Mozilla::CA` (included in `cpanfile`). Re-run `cpanm --installdeps .`. +- SSL toolchain: some systems require OpenSSL dev libs (e.g., macOS: `brew install openssl`, Debian/Ubuntu: `apt-get install libssl-dev`) before `cpanm` can build `Net::SSLeay`/`IO::Socket::SSL`. + +--- + +## Audience And Tone (Internal) + +These Perl samples are customer‑facing and intended to help potential customers evaluate pdfRest quickly. Keep all code, comments, and documentation clear, minimal, and task‑focused. Avoid internal jargon and keep meta‑process notes out of `README.md` and the samples. + +Key points: +- Clarity: explain what the sample does in 1–2 bullets. +- Guidance: show how to set up `.env` and how to run the script. +- Region: mention optional `PDFREST_URL` with the EU endpoint for GDPR and proximity. +- Safety: never log secrets; print only response bodies and minimal diagnostics to `STDERR`. +- Errors: exit non‑zero on non‑2xx responses with a concise message. + +## Sample Header Convention (Internal) + +Add this standardized header comment at the top of every Perl sample. This header is customer‑visible; the convention itself is tracked here for us (don’t place this template in `README.md`). + +Template: + +``` +#! +# What this sample does: +# - +# +# Setup (.env): +# - Copy .env.example to .env +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +# +# Usage: +# perl "" /path/to/input.pdf +# +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json +``` + +Notes: +- Match the endpoint name and request style (JSON two‑step vs multipart single request) in the bullets. +- Keep the header concise; list optional parameters near where they are used in code. + +## README Scope (Internal) + +Keep `README.md` focused on user setup, running samples, and high‑level background. Avoid internal conventions or meta‑process content that could confuse customers. Place internal notes and templates in `AGENTS.md` (this file). diff --git a/Perl/Complex Flow Examples/merge-different-file-types.pl b/Perl/Complex Flow Examples/merge-different-file-types.pl new file mode 100644 index 00000000..8dc3e48f --- /dev/null +++ b/Perl/Complex Flow Examples/merge-different-file-types.pl @@ -0,0 +1,147 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use utf8; +use FindBin qw($Bin); +use File::Basename qw(basename); +use JSON::PP qw(decode_json); +use LWP::UserAgent; +use HTTP::Request; +use HTTP::Request::Common qw(POST); +use URI::Escape qw(uri_escape); +use Dotenv; + +#! +# What this sample does: +# - Merges multiple inputs (PDFs and non-PDFs) into a single PDF. +# - Non-PDFs are converted to PDF; PDFs are uploaded. Collected IDs are merged via /merged-pdf. +# +# Setup (.env): +# - Copy .env.example to .env (Perl folder root) +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +# +# Usage: +# perl "Complex Flow Examples/merge-different-file-types.pl" /path/to/file1 /path/to/file2 [/path/to/file3 ...] +# +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json + +binmode STDOUT, ':raw'; +binmode STDERR, ':encoding(UTF-8)'; + +# Load .env from the Perl folder root (one level up from this script) +my $env_path = "$Bin/../.env"; +-e $env_path and Dotenv->load($env_path); + +my $api_key = $ENV{PDFREST_API_KEY} // ''; +if (!$api_key || $api_key =~ /^\s*$/) { + print STDERR "Missing PDFREST_API_KEY in .env or environment\n"; + exit 1; +} + +my $api_base = $ENV{PDFREST_URL} // $ENV{PDFREST_API} // 'https://api.pdfrest.com'; +$api_base =~ s{/+$}{}; + +my @paths = @ARGV; +if (@paths < 2) { + print STDERR "Usage: perl merge-different-file-types.pl /path/to/file1 /path/to/file2 [/path/to/file3 ...]\n"; + exit 1; +} +for my $p (@paths) { if (!-f $p) { print STDERR "Not a file: $p\n"; exit 1; } } + +sub content_type_for { + my ($path) = @_; + my ($ext) = $path =~ /(\.[^.]+)$/; + $ext = lc($ext // ''); + return 'application/pdf' if $ext eq '.pdf'; + return 'image/png' if $ext eq '.png'; + return 'image/jpeg' if $ext eq '.jpg' || $ext eq '.jpeg'; + return 'image/gif' if $ext eq '.gif'; + return 'image/tiff' if $ext eq '.tif' || $ext eq '.tiff'; + return 'image/bmp' if $ext eq '.bmp'; + return 'image/webp' if $ext eq '.webp'; + return 'application/msword' if $ext eq '.doc'; + return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' if $ext eq '.docx'; + return 'application/vnd.ms-powerpoint' if $ext eq '.ppt'; + return 'application/vnd.openxmlformats-officedocument.presentationml.presentation' if $ext eq '.pptx'; + return 'application/vnd.ms-excel' if $ext eq '.xls'; + return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' if $ext eq '.xlsx'; + return 'text/plain' if $ext eq '.txt'; + return 'application/rtf' if $ext eq '.rtf'; + return 'text/html' if $ext eq '.html' || $ext eq '.htm'; + return 'application/octet-stream'; +} + +my $ua = LWP::UserAgent->new( timeout => 120 ); + +eval { + my @ids; + for my $i (0..$#paths) { + my $p = $paths[$i]; + my $ext = lc(($p =~ /(\.[^.]+)$/)[0] // ''); + if ($ext eq '.pdf') { + # Upload and capture id + open my $fh, '<:raw', $p or do { print STDERR "Unable to read $p: $!\n"; exit 1; }; + my $bytes; { local $/; $bytes = <$fh>; } + close $fh; + my $req = HTTP::Request->new('POST', "$api_base/upload"); + $req->header('api-key' => $api_key); + $req->header('content-filename' => basename($p)); + $req->header('Content-Type' => 'application/octet-stream'); + $req->content($bytes); + my $resp = $ua->request($req); + print STDERR $resp->decoded_content // ''; + if (!$resp->is_success) { print STDERR "\nUpload failed (input #" . ($i+1) . ") status " . $resp->code . "\n"; exit 1; } + my $json = decode_json($resp->decoded_content // '{}'); + my $id = $json->{files} && ref $json->{files} eq 'ARRAY' ? $json->{files}[0]{id} : undef; + if (!$id) { print STDERR "Unexpected upload response format for input #" . ($i+1) . "\n"; exit 1; } + push @ids, $id; + print STDERR "Uploaded PDF (#" . ($i+1) . "); id=$id\n"; + } else { + # Convert to PDF via /pdf and capture outputId + my $ct = content_type_for($p); + my $req = POST("$api_base/pdf", + 'Content_Type' => 'form-data', + 'Content' => [ file => [$p, basename($p), 'Content-Type' => $ct] ] + ); + $req->header('api-key' => $api_key); + my $resp = $ua->request($req); + print STDERR $resp->decoded_content // ''; + if (!$resp->is_success) { print STDERR "\nConversion failed (input #" . ($i+1) . ") status " . $resp->code . "\n"; exit 1; } + my $json = decode_json($resp->decoded_content // '{}'); + my $id = $json->{outputId}; + if (!$id) { print STDERR "Unexpected conversion response format for input #" . ($i+1) . "\n"; exit 1; } + push @ids, $id; + print STDERR "Converted non-PDF (#" . ($i+1) . "); outputId=$id\n"; + } + } + + # Build x-www-form-urlencoded with repeated arrays + my @parts; + for my $id (@ids) { + push @parts, 'id[]=' . uri_escape($id); + push @parts, 'pages[]=' . uri_escape('1-last'); + push @parts, 'type[]=id'; + } + my $body = join('&', @parts); + + my $merge_req = HTTP::Request->new('POST', "$api_base/merged-pdf"); + $merge_req->header('api-key' => $api_key); + $merge_req->header('Content-Type' => 'application/x-www-form-urlencoded'); + $merge_req->content($body); + my $merge_resp = $ua->request($merge_req); + print STDOUT $merge_resp->decoded_content // ''; + if (!$merge_resp->is_success) { print STDERR "\nMerge failed with status " . $merge_resp->code . "\n"; exit 1; } + 1; +} or do { + my $err = $@ || 'Unknown error'; + $err =~ s/\s+$//; + print STDERR "Error: $err\n"; + exit 1; +}; + +__END__ diff --git a/Perl/Endpoint Examples/JSON Payload/markdown.pl b/Perl/Endpoint Examples/JSON Payload/markdown.pl new file mode 100644 index 00000000..f6d6746f --- /dev/null +++ b/Perl/Endpoint Examples/JSON Payload/markdown.pl @@ -0,0 +1,108 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use utf8; +use FindBin qw($Bin); +use File::Basename qw(basename); +use JSON::PP qw(encode_json decode_json); +use LWP::UserAgent; +use HTTP::Request; +use HTTP::Request::Common qw(POST); +use Encode qw(encode); +use Dotenv; + +#! +# What this sample does: +# - Converts a PDF to Markdown using pdfRest. +# - Uses a JSON payload in two steps: upload to /upload, then call /markdown with the returned id. +# +# Setup (.env): +# - Copy .env.example to .env (Perl folder root) +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +# +# Usage: +# perl "Endpoint Examples/JSON Payload/markdown.pl" /path/to/input.pdf +# +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json + +binmode STDOUT, ':raw'; +binmode STDERR, ':encoding(UTF-8)'; + +# Load .env from the Perl folder root (two levels up from this script) +my $env_path = "$Bin/../../.env"; +-e $env_path and Dotenv->load($env_path); + +my $api_key = $ENV{PDFREST_API_KEY} // ''; +if (!$api_key || $api_key =~ /^\s*$/) { + print STDERR "Missing PDFREST_API_KEY in .env or environment\n"; + exit 1; +} + +my $api_base = $ENV{PDFREST_URL} // $ENV{PDFREST_API} // 'https://api.pdfrest.com'; +$api_base =~ s{/+$}{}; # trim trailing slashes + +my $pdf_path = shift @ARGV; +if (!$pdf_path || !-f $pdf_path) { + print STDERR "Usage: perl markdown.pl /path/to/file.pdf\n"; + exit 1; +} + +my $filename = basename($pdf_path); +open my $fh, '<:raw', $pdf_path or do { print STDERR "Unable to read $pdf_path: $!\n"; exit 1; }; +my $file_bytes; { local $/; $file_bytes = <$fh>; } +close $fh; + +my $ua = LWP::UserAgent->new( timeout => 60 ); + +eval { + # Step 1: Upload the file to receive a reusable id + my $upload_req = HTTP::Request->new('POST', "$api_base/upload"); + $upload_req->header('api-key' => $api_key); + $upload_req->header('content-filename' => $filename); + $upload_req->header('Content-Type' => 'application/octet-stream'); + $upload_req->content($file_bytes); + + my $upload_resp = $ua->request($upload_req); + print STDERR $upload_resp->decoded_content // ''; + if (!$upload_resp->is_success) { + print STDERR "\nUpload failed with status " . $upload_resp->code . "\n"; + exit 1; + } + + my $upload_json = decode_json($upload_resp->decoded_content // '{}'); + my $uploaded_id = $upload_json->{files} && ref $upload_json->{files} eq 'ARRAY' + ? $upload_json->{files}[0]{id} + : undef; + if (!$uploaded_id) { + print STDERR "Unexpected response format: missing files[0].id\n"; + exit 1; + } + print STDERR "Successfully uploaded with an id of: $uploaded_id\n"; + + # Step 2: Request Markdown output using the uploaded id + my $markdown_body = encode_json({ id => $uploaded_id, page_break_comments => 'on' }); + my $markdown_req = HTTP::Request->new('POST', "$api_base/markdown"); + $markdown_req->header('api-key' => $api_key); + $markdown_req->header('Content-Type' => 'application/json'); + $markdown_req->content($markdown_body); + + my $markdown_resp = $ua->request($markdown_req); + print STDOUT $markdown_resp->decoded_content // ''; + if (!$markdown_resp->is_success) { + print STDERR "\nMarkdown conversion failed with status " . $markdown_resp->code . "\n"; + exit 1; + } + 1; +} or do { + my $err = $@ || 'Unknown error'; + $err =~ s/\s+$//; + print STDERR "Error: $err\n"; + exit 1; +}; + +__END__ diff --git a/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl b/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl new file mode 100644 index 00000000..e5045407 --- /dev/null +++ b/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl @@ -0,0 +1,103 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use utf8; +use FindBin qw($Bin); +use File::Basename qw(basename); +use JSON::PP qw(encode_json decode_json); +use LWP::UserAgent; +use HTTP::Request; +use Dotenv; + +#! +# What this sample does: +# - Creates a rasterized version of a PDF using pdfRest. +# - Uses a JSON payload in two steps: upload to /upload, then call /rasterized-pdf with the returned id. +# +# Setup (.env): +# - Copy .env.example to .env (Perl folder root) +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +# +# Usage: +# perl "Endpoint Examples/JSON Payload/rasterized-pdf.pl" /path/to/input.pdf +# +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json + +binmode STDOUT, ':raw'; +binmode STDERR, ':encoding(UTF-8)'; + +# Load .env from the Perl folder root +my $env_path = "$Bin/../../.env"; +-e $env_path and Dotenv->load($env_path); + +my $api_key = $ENV{PDFREST_API_KEY} // ''; +if (!$api_key || $api_key =~ /^\s*$/) { + print STDERR "Missing PDFREST_API_KEY in .env or environment\n"; + exit 1; +} + +my $api_base = $ENV{PDFREST_URL} // $ENV{PDFREST_API} // 'https://api.pdfrest.com'; +$api_base =~ s{/+$}{}; + +my $pdf_path = shift @ARGV; +if (!$pdf_path || !-f $pdf_path) { + print STDERR "Usage: perl rasterized-pdf.pl /path/to/file.pdf\n"; + exit 1; +} + +my $filename = basename($pdf_path); +open my $fh, '<:raw', $pdf_path or do { print STDERR "Unable to read $pdf_path: $!\n"; exit 1; }; +my $file_bytes; { local $/; $file_bytes = <$fh>; } +close $fh; + +my $ua = LWP::UserAgent->new( timeout => 60 ); + +eval { + # 1) Upload the PDF + my $upload_req = HTTP::Request->new('POST', "$api_base/upload"); + $upload_req->header('api-key' => $api_key); + $upload_req->header('content-filename' => $filename); + $upload_req->header('Content-Type' => 'application/octet-stream'); + $upload_req->content($file_bytes); + my $upload_resp = $ua->request($upload_req); + print STDERR $upload_resp->decoded_content // ''; + if (!$upload_resp->is_success) { + print STDERR "\nUpload failed with status " . $upload_resp->code . "\n"; + exit 1; + } + my $upload_json = decode_json($upload_resp->decoded_content // '{}'); + my $uploaded_id = $upload_json->{files} && ref $upload_json->{files} eq 'ARRAY' + ? $upload_json->{files}[0]{id} + : undef; + if (!$uploaded_id) { + print STDERR "Unexpected response format: missing files[0].id\n"; + exit 1; + } + print STDERR "Successfully uploaded with an id of: $uploaded_id\n"; + + # 2) Call /rasterized-pdf with JSON body + my $body = encode_json({ id => $uploaded_id }); + my $ras_req = HTTP::Request->new('POST', "$api_base/rasterized-pdf"); + $ras_req->header('api-key' => $api_key); + $ras_req->header('Content-Type' => 'application/json'); + $ras_req->content($body); + my $ras_resp = $ua->request($ras_req); + print STDOUT $ras_resp->decoded_content // ''; + if (!$ras_resp->is_success) { + print STDERR "\nRasterization failed with status " . $ras_resp->code . "\n"; + exit 1; + } + 1; +} or do { + my $err = $@ || 'Unknown error'; + $err =~ s/\s+$//; + print STDERR "Error: $err\n"; + exit 1; +}; + +__END__ diff --git a/Perl/Endpoint Examples/Multipart Payload/markdown.pl b/Perl/Endpoint Examples/Multipart Payload/markdown.pl new file mode 100644 index 00000000..bbe2a81a --- /dev/null +++ b/Perl/Endpoint Examples/Multipart Payload/markdown.pl @@ -0,0 +1,81 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use utf8; +use FindBin qw($Bin); +use File::Basename qw(basename); +use LWP::UserAgent; +use HTTP::Request::Common qw(POST); +use Dotenv; + +#! +# What this sample does: +# - Converts a PDF to Markdown using pdfRest. +# - Sends a single multipart/form-data request directly to /markdown with the file. +# +# Setup (.env): +# - Copy .env.example to .env (Perl folder root) +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +# +# Usage: +# perl "Endpoint Examples/Multipart Payload/markdown.pl" /path/to/input.pdf +# +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json + +binmode STDOUT, ':raw'; +binmode STDERR, ':encoding(UTF-8)'; + +# Load .env from the Perl folder root +my $env_path = "$Bin/../../.env"; +-e $env_path and Dotenv->load($env_path); + +my $api_key = $ENV{PDFREST_API_KEY} // ''; +if (!$api_key || $api_key =~ /^\s*$/) { + print STDERR "Missing PDFREST_API_KEY in .env or environment\n"; + exit 1; +} + +my $api_base = $ENV{PDFREST_URL} // $ENV{PDFREST_API} // 'https://api.pdfrest.com'; +$api_base =~ s{/+$}{}; + +my $pdf_path = shift @ARGV; +if (!$pdf_path || !-f $pdf_path) { + print STDERR "Usage: perl markdown.pl /path/to/file.pdf\n"; + exit 1; +} + +my $filename = basename($pdf_path); +my $ua = LWP::UserAgent->new( timeout => 60 ); + +eval { + my $req = POST("$api_base/markdown", + 'Content_Type' => 'form-data', + 'Content' => [ + file => [$pdf_path, $filename, 'Content-Type' => 'application/pdf'], + output => 'pdfrest_markdown', + page_break_comments => 'on', + # Optional: page_range => '1-3', + ] + ); + $req->header('api-key' => $api_key); + + my $resp = $ua->request($req); + print STDOUT $resp->decoded_content // ''; + if (!$resp->is_success) { + print STDERR "\nMarkdown conversion failed with status " . $resp->code . "\n"; + exit 1; + } + 1; +} or do { + my $err = $@ || 'Unknown error'; + $err =~ s/\s+$//; + print STDERR "Error: $err\n"; + exit 1; +}; + +__END__ diff --git a/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl b/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl new file mode 100644 index 00000000..e0ad6152 --- /dev/null +++ b/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl @@ -0,0 +1,80 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use utf8; +use FindBin qw($Bin); +use File::Basename qw(basename); +use LWP::UserAgent; +use HTTP::Request::Common qw(POST); +use Dotenv; + +#! +# What this sample does: +# - Creates a rasterized version of a PDF using pdfRest. +# - Sends a single multipart/form-data request directly to /rasterized-pdf with the file. +# +# Setup (.env): +# - Copy .env.example to .env (Perl folder root) +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +# +# Usage: +# perl "Endpoint Examples/Multipart Payload/rasterized-pdf.pl" /path/to/input.pdf +# +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json + +binmode STDOUT, ':raw'; +binmode STDERR, ':encoding(UTF-8)'; + +# Load .env from the Perl folder root +my $env_path = "$Bin/../../.env"; +-e $env_path and Dotenv->load($env_path); + +my $api_key = $ENV{PDFREST_API_KEY} // ''; +if (!$api_key || $api_key =~ /^\s*$/) { + print STDERR "Missing PDFREST_API_KEY in .env or environment\n"; + exit 1; +} + +my $api_base = $ENV{PDFREST_URL} // $ENV{PDFREST_API} // 'https://api.pdfrest.com'; +$api_base =~ s{/+$}{}; + +my $pdf_path = shift @ARGV; +if (!$pdf_path || !-f $pdf_path) { + print STDERR "Usage: perl rasterized-pdf.pl /path/to/file.pdf\n"; + exit 1; +} + +my $filename = basename($pdf_path); +my $ua = LWP::UserAgent->new( timeout => 60 ); + +eval { + my $req = POST("$api_base/rasterized-pdf", + 'Content_Type' => 'form-data', + 'Content' => [ + file => [$pdf_path, $filename, 'Content-Type' => 'application/pdf'], + output => 'pdfrest_rasterize', + # Optional: dpi => '300', color_space => 'rgb', page_range => '1-3', + ] + ); + $req->header('api-key' => $api_key); + + my $resp = $ua->request($req); + print STDOUT $resp->decoded_content // ''; + if (!$resp->is_success) { + print STDERR "\nRasterization failed with status " . $resp->code . "\n"; + exit 1; + } + 1; +} or do { + my $err = $@ || 'Unknown error'; + $err =~ s/\s+$//; + print STDERR "Error: $err\n"; + exit 1; +}; + +__END__ diff --git a/Perl/README.md b/Perl/README.md new file mode 100644 index 00000000..2a3dffc7 --- /dev/null +++ b/Perl/README.md @@ -0,0 +1,53 @@ +# pdfRest Perl Samples + +A set of Perl scripts that demonstrate how to call the pdfRest API. Samples are organized by request style and include a multi‑step “Complex Flow” example. + +- JSON Payload: upload first, then call the endpoint by `id`. +- Multipart Payload: send the file and options in a single request. + +## Prerequisites +- Perl 5.26+ on macOS/Linux/WSL. +- A pdfRest API key (get one at https://pdfrest.com/getstarted/). +- cpanm (cpanminus) to install dependencies. + +### Install cpanm +- macOS (Homebrew): `brew install cpanminus` +- Debian/Ubuntu: `sudo apt-get install cpanminus` +- CPAN: `perl -MCPAN -e 'install App::cpanminus'` +- Curl (alternative): `curl -L https://cpanmin.us | perl - --sudo App::cpanminus` + +## Setup +1) Copy environment template and set your key +- `cp .env.example .env` +- Edit `.env` and set `PDFREST_API_KEY=your_api_key_here` +- Optional EU endpoint for GDPR/proximity: `PDFREST_URL=https://eu-api.pdfrest.com/` + +2) Install dependencies from `cpanfile` +- Standard: `cpanm --installdeps .` +- macOS (Homebrew OpenSSL + HTTPS stack): `make install-macos` or `scripts/setup-macos.sh` + - This installs `openssl@3` and builds `Net::SSLeay`, `IO::Socket::SSL`, etc. + +## EU/GDPR Endpoint +- Default base URL is `https://api.pdfrest.com` (US). +- For GDPR compliance and improved performance in Europe, set in `.env`: + - `PDFREST_URL=https://eu-api.pdfrest.com/` +- If `PDFREST_URL` is not set, the default US endpoint is used. +- More information: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work + +## Run the Samples +- JSON Markdown: `perl "Endpoint Examples/JSON Payload/markdown.pl" input.pdf` +- JSON Rasterize: `perl "Endpoint Examples/JSON Payload/rasterized-pdf.pl" input.pdf` +- Multipart Markdown: `perl "Endpoint Examples/Multipart Payload/markdown.pl" input.pdf` +- Multipart Rasterize: `perl "Endpoint Examples/Multipart Payload/rasterized-pdf.pl" input.pdf` +- Complex Flow Merge: `perl "Complex Flow Examples/merge-different-file-types.pl" file1.png file2.pptx file3.pdf` +- Save output: append `> response.json` + +## Troubleshooting +- HTTPS modules missing: `cpanm --installdeps .` (includes `LWP::Protocol::https`, `IO::Socket::SSL`, `Mozilla::CA`). +- Net::SSLeay fails to build: install OpenSSL dev tools. + - macOS: `xcode-select --install && brew install openssl@3 pkg-config` then `make install-macos`. + - Debian/Ubuntu: `sudo apt-get install -y build-essential libssl-dev pkg-config` then `cpanm --reinstall Net::SSLeay IO::Socket::SSL`. +- Verify TLS: `perl -MIO::Socket::SSL -e 'print $IO::Socket::SSL::VERSION, qq(\n)'` and `perl -MLWP::Protocol::https -e 'print qq(https OK\n)'`. + +Notes +- Scripts read `.env` from the Perl folder root and print API responses to stdout; diagnostics go to stderr and non‑zero exit on errors. diff --git a/Perl/cpanfile b/Perl/cpanfile new file mode 100644 index 00000000..3f512600 --- /dev/null +++ b/Perl/cpanfile @@ -0,0 +1,11 @@ +requires 'LWP::UserAgent'; +requires 'HTTP::Request::Common'; +requires 'JSON::PP'; +requires 'Try::Tiny'; +requires 'LWP::Protocol::https'; +# Recommended for certificate bundle +requires 'Mozilla::CA'; +requires 'IO::Socket::SSL'; +requires 'Net::SSLeay'; +requires 'URI'; +requires 'Dotenv'; diff --git a/Perl/scripts/setup-macos.sh b/Perl/scripts/setup-macos.sh new file mode 100755 index 00000000..b0599496 --- /dev/null +++ b/Perl/scripts/setup-macos.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Installing prerequisites (Xcode tools, Homebrew OpenSSL, pkg-config)..." +if ! xcode-select -p >/dev/null 2>&1; then + xcode-select --install || true +fi + +if ! command -v brew >/dev/null 2>&1; then + echo "Homebrew is required. Install from https://brew.sh and re-run." >&2 + exit 1 +fi + +brew install openssl@3 pkg-config || true + +OPENSSL_PREFIX="$(brew --prefix openssl@3)" +export PKG_CONFIG_PATH="$OPENSSL_PREFIX/lib/pkgconfig" +export CPATH="$OPENSSL_PREFIX/include" +export LIBRARY_PATH="$OPENSSL_PREFIX/lib" + +echo "Building Perl SSL modules against OpenSSL at $OPENSSL_PREFIX..." +cpanm --verbose --notest --reinstall --configure-args="--openssl-prefix=$OPENSSL_PREFIX" Net::SSLeay +cpanm IO::Socket::SSL LWP::Protocol::https Mozilla::CA + +echo "Installing application dependencies from cpanfile..." +cpanm --installdeps . + +echo "Verifying HTTPS support..." +perl -MIO::Socket::SSL -e 'print $IO::Socket::SSL::VERSION, qq(\n)' +perl -MLWP::Protocol::https -e 'print qq(https OK\n)' + +echo "Done. You can now run:" +echo " perl \"Endpoint Examples/JSON Payload/markdown.pl\" /path/to/input.pdf" diff --git a/VB.NET/.env.example b/VB.NET/.env.example new file mode 100644 index 00000000..77fcddd0 --- /dev/null +++ b/VB.NET/.env.example @@ -0,0 +1,6 @@ +# Set your pdfRest API key +PDFREST_API_KEY=your_api_key_here + +# Optional: override the API base URL (e.g., for EU region) +# PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work \ No newline at end of file diff --git a/VB.NET/.gitignore b/VB.NET/.gitignore new file mode 100644 index 00000000..831821e4 --- /dev/null +++ b/VB.NET/.gitignore @@ -0,0 +1,79 @@ +# Created by https://www.toptal.com/developers/gitignore/api/dotnetcore,visualbasic +# Edit at https://www.toptal.com/developers/gitignore?templates=dotnetcore,visualbasic + +### DotnetCore ### +# .NET Core build folders +bin/ +obj/ + +# Common node modules locations +/node_modules +/wwwroot/node_modules + +### VisualBasic ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +.DS_Store +.Trashes +*.vbw +*.csi +*.exp +*.lib +*.lvw +*.dca +*.scc +*.tmp +*.exe +*.bat +*.bak +*.zip +*.old +*.enc +*.key +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# End of https://www.toptal.com/developers/gitignore/api/dotnetcore,visualbasic \ No newline at end of file diff --git a/VB.NET/AGENTS.md b/VB.NET/AGENTS.md new file mode 100644 index 00000000..114de461 --- /dev/null +++ b/VB.NET/AGENTS.md @@ -0,0 +1,112 @@ +# Repository Guidelines + +## Project Structure & Module Organization +- `VBNetSamples.vbproj`: Single root console project compiling all VB samples. +- `Program.vb`: Dispatcher routing `dotnet run -- ` to a specific sample. +- `Endpoint Examples/JSON Payload/`: Two-step samples (upload then operate), e.g., `markdown.vb`. +- `Endpoint Examples/Multipart Payload/`: Single multipart request samples, e.g., `rasterized-pdf.vb`. +- `Complex Flow Examples/`: Multi-step workflows chaining several endpoints. +- `.env.example` → copy to `.env` and set `PDFREST_API_KEY` (loaded by DotNetEnv at startup). +- `README.md`: High-level setup and usage for VB.NET samples. + +## Build, Test, and Development Commands +- Install .NET SDK (8.0+): verify with `dotnet --version`. +- Restore/build (from VB.NET folder): `dotnet restore && dotnet build`. +- Run a sample via dispatcher: `dotnet run -- [args]`. + - Example: `dotnet run -- markdown /path/to/input.pdf`. +- Dependencies: + - `.env` loading is included via `DotNetEnv`. + - Optional JSON helper: `dotnet add package Newtonsoft.Json` (only if a sample uses it). +- File-focused testing: keep each sample self-contained (accept input path as first arg; minimal edits). + +## Coding Style & Naming Conventions +- VB style: 4-space indentation, `PascalCase` for types/methods, `camelCase` for locals/parameters. +- File naming: match pdfRest endpoint with hyphenated lowercase, e.g., `markdown.vb`, `rasterized-pdf.vb`. +- Sample structure: each sample exposes `Public Async Function Execute(args() As String) As Task` and lives under a namespace mirroring its folder. Use underscores for folder segments that contain spaces: + - JSON two-step: `Namespace VBNetSamples.Endpoint_Examples.JSON_Payload` + - Multipart: `Namespace VBNetSamples.Endpoint_Examples.Multipart_Payload` + - Complex flows: `Namespace VBNetSamples.Complex_Flow_Examples` + - Note: This satisfies IDE checks like “Namespace does not correspond to file location”. +- Dispatcher: `Program.vb` contains `Sub Main` and routes commands to `...Execute(args)`; do not add additional `Main` methods in samples. +- Env config: read `PDFREST_API_KEY` and optional `PDFREST_URL`; `.env` is auto-loaded by `DotNetEnv`. +- HTTP: use `HttpClient` with explicit `Accept`/`Content-Type`; set `Api-Key` per request; use `MultipartFormDataContent`; default base URL `https://api.pdfrest.com` with `PDFREST_URL` override. +- Errors: check `response.IsSuccessStatusCode`; on failure, write a concise error to `Console.Error` and exit non-zero. + +## Testing Guidelines +- No formal test suite required. Validate by running samples against known inputs. +- Success criteria: exit non-zero on failures; print API JSON response to stdout on success. +- New samples: accept input path as first argument when practical; document optional params inline near usage. + +## Commit & Pull Request Guidelines +- Commits: imperative mood and focused scope (e.g., "Add multipart markdown VB sample"). +- Describe what changed and why; reference endpoint and path. +- PRs: include clear description, run commands used for verification, expected response snippet, and any notes on options. +- Link related issues; avoid unrelated changes in the same PR. + +## Security & Configuration Tips +- Keep secrets out of VCS: do not commit `.env`; include a `.env.example` with placeholder keys if the folder uses `.env`. +- Support proxies via standard env vars (e.g., `HTTPS_PROXY`) when applicable. +- Never log API keys; print response bodies and minimal diagnostics only (send diagnostics to `Console.Error`). +- API base override: set `PDFREST_URL` to change regions. For EU GDPR compliance and improved performance in Europe, you may use `https://eu-api.pdfrest.com/`. More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work + +--- + +## Audience And Tone (Internal) + +These samples are customer-facing and intended to help potential customers evaluate pdfRest quickly. Keep all code, comments, and documentation clear, minimal, and task-focused. Avoid internal jargon and advanced implementation details in customer-visible files. Do not surface internal process notes in `README.md` or the samples. + +Key points: +- Clarity: explain what the sample does in 1–2 bullets. +- Guidance: show how to set the API key and how to run. +- Region: mention optional `PDFREST_URL` with the EU endpoint for GDPR and proximity. +- Safety: never log secrets; print only response bodies and minimal diagnostics to stderr. +- Errors: exit non‑zero on non‑2xx with a concise message. + +## Sample Header Convention (Internal) + +Add this standardized header comment at the top of every VB.NET sample. This header is customer-visible but the convention itself is for us to remember here (do not duplicate these instructions in README). + +Template: + +''' +' What this sample does: +' - +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run -- /path/to/input.pdf +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run -- ... > response.json +''' + +Notes: +- Match the endpoint name and request style (JSON two‑step vs multipart single request) in the bullets. +- Keep the header concise; avoid adding options unless essential. +- If a sample accepts optional parameters, mention them inline in code near where they are used. + +## README Scope (Internal) + +Keep `README.md` focused on user setup, running samples, and high‑level background. Avoid internal conventions or meta‑process content that could confuse customers. Place internal notes and templates in `AGENTS.md` (this file). + +--- + +## VB.NET Implementation Notes (Internal) +- Dispatcher entry point: `Program.vb` exposes `Sub Main` (wrapping an async method) and selects a sample based on the first CLI argument. Only one entry point exists. +- Add a new sample: + - Create a `.vb` file under the appropriate folder. + - Namespace as noted above; expose `Public Async Function Execute(args() As String) As Task`. + - Update `Program.vb` `Select Case` to map a command (e.g., `png`) to the new module’s `Execute`. +- JSON parsing: prefer `System.Text.Json`; if using `Newtonsoft.Json`, add the NuGet package and import `Newtonsoft.Json.Linq` for simple extraction. +- Multipart uploads: `New MultipartFormDataContent()` with `ByteArrayContent` or `StreamContent`. Set `Content-Type` and filename as needed. +- Headers: set `Api-Key` per request; always send `Accept: application/json`. +- Base URL: default `https://api.pdfrest.com`; support `PDFREST_URL` override. +- Env loader: `.env` is loaded automatically via `DotNetEnv` at startup. +- Errors: prefer `If Not response.IsSuccessStatusCode Then ... Environment.Exit(1)`. diff --git a/VB.NET/Complex Flow Examples/merge-different-file-types.vb b/VB.NET/Complex Flow Examples/merge-different-file-types.vb new file mode 100644 index 00000000..ad8797d6 --- /dev/null +++ b/VB.NET/Complex Flow Examples/merge-different-file-types.vb @@ -0,0 +1,174 @@ +''' +' What this sample does: +' - Merges multiple inputs (PDFs and non-PDFs) into a single PDF. +' - Non-PDF files are first converted to PDF; PDFs are uploaded as-is. All resulting IDs are then merged. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run -- merge-different-file-types /path/to/file1 /path/to/file2 [...] +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run -- merge-different-file-types ... > response.json +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.Collections.Generic +Imports System.IO +Imports System.Net.Http +Imports System.Net.Http.Headers +Imports System.Text +Imports System.Text.Json +Imports System.Threading.Tasks + +Namespace VBNetSamples.Complex_Flow_Examples + Module MergeDifferentFileTypes + Public Async Function Execute(args As String()) As Task + If args Is Nothing OrElse args.Length < 2 Then + Console.Error.WriteLine("Usage: dotnet run -- merge-different-file-types /path/to/file1 /path/to/file2 [/path/to/file3 ...]") + Environment.Exit(1) + End If + + Dim allExist = Array.TrueForAll(args, Function(p) File.Exists(p)) + If Not allExist Then + Console.Error.WriteLine("One or more input files do not exist.") + Environment.Exit(1) + End If + + Dim apiKey As String = Environment.GetEnvironmentVariable("PDFREST_API_KEY") + If String.IsNullOrWhiteSpace(apiKey) Then + Console.Error.WriteLine("Missing environment variable PDFREST_API_KEY.") + Environment.Exit(1) + End If + + Dim baseUrl As String = Environment.GetEnvironmentVariable("PDFREST_URL") + If String.IsNullOrWhiteSpace(baseUrl) Then baseUrl = "https://api.pdfrest.com" + + Dim baseUri As Uri + Try + baseUri = New Uri(baseUrl) + Catch ex As Exception + Console.Error.WriteLine($"Invalid PDFREST_URL: {baseUrl}") + Environment.Exit(1) + Return + End Try + + Using httpClient As New HttpClient() + httpClient.BaseAddress = baseUri + + Dim collectedIds As New List(Of String)() + + For i = 0 To args.Length - 1 + Dim p As String = args(i) + Dim ext As String = Path.GetExtension(p).ToLowerInvariant() + If ext = ".pdf" Then + ' Upload PDFs to get an id + Dim uploadReq As New HttpRequestMessage(HttpMethod.Post, "upload") + uploadReq.Headers.TryAddWithoutValidation("Api-Key", apiKey) + uploadReq.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + + Dim pdfBytes As Byte() = File.ReadAllBytes(p) + Dim uploadContent As New ByteArrayContent(pdfBytes) + uploadContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream") + uploadContent.Headers.TryAddWithoutValidation("Content-Filename", Path.GetFileName(p)) + uploadReq.Content = uploadContent + + Dim uploadResp = Await httpClient.SendAsync(uploadReq) + Dim uploadBody = Await uploadResp.Content.ReadAsStringAsync() + If Not uploadResp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Upload failed for input #{i + 1}: {CInt(uploadResp.StatusCode)} {uploadResp.ReasonPhrase}") + Console.Error.WriteLine(uploadBody) + Environment.Exit(1) + End If + + Dim id As String = Nothing + Using doc = JsonDocument.Parse(uploadBody) + id = doc.RootElement.GetProperty("files")(0).GetProperty("id").GetString() + End Using + collectedIds.Add(id) + Else + ' Convert non-PDF to PDF to get an outputId + Dim multipart As New MultipartFormDataContent() + Dim fileBytes As Byte() = File.ReadAllBytes(p) + Dim fileContent As New ByteArrayContent(fileBytes) + fileContent.Headers.ContentType = New MediaTypeHeaderValue(ContentTypeFor(p)) + multipart.Add(fileContent, "file", Path.GetFileName(p)) + + Dim convReq As New HttpRequestMessage(HttpMethod.Post, "pdf") + convReq.Headers.TryAddWithoutValidation("Api-Key", apiKey) + convReq.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + convReq.Content = multipart + + Dim convResp = Await httpClient.SendAsync(convReq) + Dim convBody = Await convResp.Content.ReadAsStringAsync() + If Not convResp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Conversion failed for input #{i + 1}: {CInt(convResp.StatusCode)} {convResp.ReasonPhrase}") + Console.Error.WriteLine(convBody) + Environment.Exit(1) + End If + + Using doc = JsonDocument.Parse(convBody) + Dim outputId = doc.RootElement.GetProperty("outputId").GetString() + collectedIds.Add(outputId) + End Using + End If + Next + + ' Build x-www-form-urlencoded body with arrays + Dim pairs As New List(Of KeyValuePair(Of String, String))() + For Each id In collectedIds + pairs.Add(New KeyValuePair(Of String, String)("id[]", id)) + pairs.Add(New KeyValuePair(Of String, String)("pages[]", "1-last")) + pairs.Add(New KeyValuePair(Of String, String)("type[]", "id")) + Next + + Dim mergeReq As New HttpRequestMessage(HttpMethod.Post, "merged-pdf") + mergeReq.Headers.TryAddWithoutValidation("Api-Key", apiKey) + mergeReq.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + mergeReq.Content = New FormUrlEncodedContent(pairs) + + Dim mergeResp = Await httpClient.SendAsync(mergeReq) + Dim mergeBody = Await mergeResp.Content.ReadAsStringAsync() + If Not mergeResp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Merge failed: {CInt(mergeResp.StatusCode)} {mergeResp.ReasonPhrase}") + Console.Error.WriteLine(mergeBody) + Environment.Exit(1) + End If + + Console.WriteLine(mergeBody) + End Using + End Function + + Private Function ContentTypeFor(filePath As String) As String + Dim ext = System.IO.Path.GetExtension(filePath).ToLowerInvariant() + Select Case ext + Case ".pdf" : Return "application/pdf" + Case ".png" : Return "image/png" + Case ".jpg", ".jpeg" : Return "image/jpeg" + Case ".gif" : Return "image/gif" + Case ".tif", ".tiff" : Return "image/tiff" + Case ".bmp" : Return "image/bmp" + Case ".webp" : Return "image/webp" + Case ".doc" : Return "application/msword" + Case ".docx" : Return "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + Case ".ppt" : Return "application/vnd.ms-powerpoint" + Case ".pptx" : Return "application/vnd.openxmlformats-officedocument.presentationml.presentation" + Case ".xls" : Return "application/vnd.ms-excel" + Case ".xlsx" : Return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + Case ".txt" : Return "text/plain" + Case ".rtf" : Return "application/rtf" + Case ".html", ".htm" : Return "text/html" + Case Else : Return "application/octet-stream" + End Select + End Function + End Module +End Namespace diff --git a/VB.NET/Endpoint Examples/JSON Payload/markdown.vb b/VB.NET/Endpoint Examples/JSON Payload/markdown.vb new file mode 100644 index 00000000..c18b0eed --- /dev/null +++ b/VB.NET/Endpoint Examples/JSON Payload/markdown.vb @@ -0,0 +1,126 @@ +''' +' What this sample does: +' - Converts a PDF to Markdown using pdfRest. +' - Uses a JSON payload in two steps: first uploads, then calls /markdown with the uploaded id. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run -- markdown /path/to/input.pdf +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run -- markdown /path/to/input.pdf > response.json +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.Collections.Generic +Imports System.IO +Imports System.Net.Http +Imports System.Net.Http.Headers +Imports System.Text +Imports System.Text.Json +Imports System.Threading.Tasks + +Namespace VBNetSamples.Endpoint_Examples.JSON_Payload + Module Markdown + Public Async Function Execute(args As String()) As Task + If args Is Nothing OrElse args.Length < 1 Then + Console.Error.WriteLine("Usage: dotnet run -- markdown /path/to/input.pdf") + Environment.Exit(1) + End If + + Dim inputPath As String = args(0) + If Not File.Exists(inputPath) Then + Console.Error.WriteLine($"Input file not found: {inputPath}") + Environment.Exit(1) + End If + + Dim apiKey As String = Environment.GetEnvironmentVariable("PDFREST_API_KEY") + If String.IsNullOrWhiteSpace(apiKey) Then + Console.Error.WriteLine("Missing environment variable PDFREST_API_KEY.") + Environment.Exit(1) + End If + + Dim baseUrl As String = Environment.GetEnvironmentVariable("PDFREST_URL") + If String.IsNullOrWhiteSpace(baseUrl) Then baseUrl = "https://api.pdfrest.com" + + Dim baseUri As Uri + Try + baseUri = New Uri(baseUrl) + Catch ex As Exception + Console.Error.WriteLine($"Invalid PDFREST_URL: {baseUrl}") + Environment.Exit(1) + Return + End Try + + Using httpClient As New HttpClient() + httpClient.BaseAddress = baseUri + + ' 1) Upload + Dim uploadRequest As New HttpRequestMessage(HttpMethod.Post, "upload") + uploadRequest.Headers.TryAddWithoutValidation("Api-Key", apiKey) + uploadRequest.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + + Dim fileBytes As Byte() = File.ReadAllBytes(inputPath) + Dim uploadContent As New ByteArrayContent(fileBytes) + uploadContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream") + uploadContent.Headers.TryAddWithoutValidation("Content-Filename", Path.GetFileName(inputPath)) + uploadRequest.Content = uploadContent + + Dim uploadResponse As HttpResponseMessage = Await httpClient.SendAsync(uploadRequest) + Dim uploadBody As String = Await uploadResponse.Content.ReadAsStringAsync() + + If Not uploadResponse.IsSuccessStatusCode Then + Console.Error.WriteLine($"Upload failed: {CInt(uploadResponse.StatusCode)} {uploadResponse.ReasonPhrase}") + Console.Error.WriteLine(uploadBody) + Environment.Exit(1) + End If + + ' Optional: print upload JSON + Console.WriteLine(uploadBody) + + Dim uploadedId As String = Nothing + Try + Using doc As JsonDocument = JsonDocument.Parse(uploadBody) + uploadedId = doc.RootElement.GetProperty("files")(0).GetProperty("id").GetString() + End Using + Catch ex As Exception + Console.Error.WriteLine("Failed to parse upload response JSON for file id.") + Console.Error.WriteLine(ex.Message) + Environment.Exit(1) + End Try + + ' 2) Markdown via JSON payload + Dim markdownRequest As New HttpRequestMessage(HttpMethod.Post, "markdown") + markdownRequest.Headers.TryAddWithoutValidation("Api-Key", apiKey) + markdownRequest.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + + Dim payload As New Dictionary(Of String, String) From { + {"id", uploadedId} + } + Dim payloadJson As String = JsonSerializer.Serialize(payload) + markdownRequest.Content = New StringContent(payloadJson, Encoding.UTF8, "application/json") + + Dim markdownResponse As HttpResponseMessage = Await httpClient.SendAsync(markdownRequest) + Dim markdownBody As String = Await markdownResponse.Content.ReadAsStringAsync() + + If Not markdownResponse.IsSuccessStatusCode Then + Console.Error.WriteLine($"Markdown request failed: {CInt(markdownResponse.StatusCode)} {markdownResponse.ReasonPhrase}") + Console.Error.WriteLine(markdownBody) + Environment.Exit(1) + End If + + Console.WriteLine(markdownBody) + End Using + End Function + End Module +End Namespace diff --git a/VB.NET/Endpoint Examples/JSON Payload/rasterized-pdf.vb b/VB.NET/Endpoint Examples/JSON Payload/rasterized-pdf.vb new file mode 100644 index 00000000..a2c1cede --- /dev/null +++ b/VB.NET/Endpoint Examples/JSON Payload/rasterized-pdf.vb @@ -0,0 +1,124 @@ +''' +' What this sample does: +' - Creates a rasterized version of a PDF using pdfRest. +' - Uses a JSON payload in two steps: first uploads, then calls /rasterized-pdf with the uploaded id. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run -- rasterized-pdf /path/to/input.pdf +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run -- rasterized-pdf /path/to/input.pdf > response.json +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.Collections.Generic +Imports System.IO +Imports System.Net.Http +Imports System.Net.Http.Headers +Imports System.Text +Imports System.Text.Json +Imports System.Threading.Tasks + +Namespace VBNetSamples.Endpoint_Examples.JSON_Payload + Module RasterizedPdf + Public Async Function Execute(args As String()) As Task + If args Is Nothing OrElse args.Length < 1 Then + Console.Error.WriteLine("Usage: dotnet run -- rasterized-pdf /path/to/input.pdf") + Environment.Exit(1) + End If + + Dim inputPath As String = args(0) + If Not File.Exists(inputPath) Then + Console.Error.WriteLine($"Input file not found: {inputPath}") + Environment.Exit(1) + End If + + Dim apiKey As String = Environment.GetEnvironmentVariable("PDFREST_API_KEY") + If String.IsNullOrWhiteSpace(apiKey) Then + Console.Error.WriteLine("Missing environment variable PDFREST_API_KEY.") + Environment.Exit(1) + End If + + Dim baseUrl As String = Environment.GetEnvironmentVariable("PDFREST_URL") + If String.IsNullOrWhiteSpace(baseUrl) Then baseUrl = "https://api.pdfrest.com" + + Dim baseUri As Uri + Try + baseUri = New Uri(baseUrl) + Catch ex As Exception + Console.Error.WriteLine($"Invalid PDFREST_URL: {baseUrl}") + Environment.Exit(1) + Return + End Try + + Using httpClient As New HttpClient() + httpClient.BaseAddress = baseUri + + ' 1) Upload step + Dim uploadRequest As New HttpRequestMessage(HttpMethod.Post, "upload") + uploadRequest.Headers.TryAddWithoutValidation("Api-Key", apiKey) + uploadRequest.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + + Dim fileBytes As Byte() = File.ReadAllBytes(inputPath) + Dim uploadContent As New ByteArrayContent(fileBytes) + uploadContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream") + uploadContent.Headers.TryAddWithoutValidation("Content-Filename", Path.GetFileName(inputPath)) + uploadRequest.Content = uploadContent + + Dim uploadResponse As HttpResponseMessage = Await httpClient.SendAsync(uploadRequest) + Dim uploadBody As String = Await uploadResponse.Content.ReadAsStringAsync() + + If Not uploadResponse.IsSuccessStatusCode Then + Console.Error.WriteLine($"Upload failed: {CInt(uploadResponse.StatusCode)} {uploadResponse.ReasonPhrase}") + Console.Error.WriteLine(uploadBody) + Environment.Exit(1) + End If + + ' Optional: print upload JSON + Console.WriteLine(uploadBody) + + Dim uploadedId As String = Nothing + Try + Using doc As JsonDocument = JsonDocument.Parse(uploadBody) + uploadedId = doc.RootElement.GetProperty("files")(0).GetProperty("id").GetString() + End Using + Catch ex As Exception + Console.Error.WriteLine("Failed to parse upload response JSON for file id.") + Console.Error.WriteLine(ex.Message) + Environment.Exit(1) + End Try + + ' 2) Rasterized PDF request (JSON) + Dim rasterReq As New HttpRequestMessage(HttpMethod.Post, "rasterized-pdf") + rasterReq.Headers.TryAddWithoutValidation("Api-Key", apiKey) + rasterReq.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + + Dim payload As New Dictionary(Of String, String) From {{"id", uploadedId}} + Dim payloadJson As String = JsonSerializer.Serialize(payload) + rasterReq.Content = New StringContent(payloadJson, Encoding.UTF8, "application/json") + + Dim rasterResp As HttpResponseMessage = Await httpClient.SendAsync(rasterReq) + Dim rasterBody As String = Await rasterResp.Content.ReadAsStringAsync() + + If Not rasterResp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Rasterized-pdf request failed: {CInt(rasterResp.StatusCode)} {rasterResp.ReasonPhrase}") + Console.Error.WriteLine(rasterBody) + Environment.Exit(1) + End If + + Console.WriteLine(rasterBody) + End Using + End Function + End Module +End Namespace diff --git a/VB.NET/Endpoint Examples/Multipart Payload/markdown.vb b/VB.NET/Endpoint Examples/Multipart Payload/markdown.vb new file mode 100644 index 00000000..46cdadd8 --- /dev/null +++ b/VB.NET/Endpoint Examples/Multipart Payload/markdown.vb @@ -0,0 +1,94 @@ +''' +' What this sample does: +' - Converts a PDF to Markdown using pdfRest. +' - Sends a single multipart/form-data request directly to /markdown with the file. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run -- markdown-multipart /path/to/input.pdf +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run -- markdown-multipart /path/to/input.pdf > response.json +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.IO +Imports System.Net.Http +Imports System.Net.Http.Headers +Imports System.Text +Imports System.Threading.Tasks + +Namespace VBNetSamples.Endpoint_Examples.Multipart_Payload + Module Markdown + Public Async Function Execute(args As String()) As Task + If args Is Nothing OrElse args.Length < 1 Then + Console.Error.WriteLine("Usage: dotnet run -- markdown-multipart /path/to/input.pdf") + Environment.Exit(1) + End If + + Dim inputPath As String = args(0) + If Not File.Exists(inputPath) Then + Console.Error.WriteLine($"Input file not found: {inputPath}") + Environment.Exit(1) + End If + + Dim apiKey As String = Environment.GetEnvironmentVariable("PDFREST_API_KEY") + If String.IsNullOrWhiteSpace(apiKey) Then + Console.Error.WriteLine("Missing environment variable PDFREST_API_KEY.") + Environment.Exit(1) + End If + + Dim baseUrl As String = Environment.GetEnvironmentVariable("PDFREST_URL") + If String.IsNullOrWhiteSpace(baseUrl) Then baseUrl = "https://api.pdfrest.com" + + Dim baseUri As Uri + Try + baseUri = New Uri(baseUrl) + Catch ex As Exception + Console.Error.WriteLine($"Invalid PDFREST_URL: {baseUrl}") + Environment.Exit(1) + Return + End Try + + Using httpClient As New HttpClient() + httpClient.BaseAddress = baseUri + + Dim multipart As New MultipartFormDataContent() + Dim fileBytes As Byte() = File.ReadAllBytes(inputPath) + Dim fileContent As New ByteArrayContent(fileBytes) + fileContent.Headers.ContentType = New MediaTypeHeaderValue("application/pdf") + multipart.Add(fileContent, "file", Path.GetFileName(inputPath)) + + ' Optional parameters + multipart.Add(New StringContent("pdfrest_markdown", Encoding.UTF8), "output") + multipart.Add(New StringContent("on", Encoding.UTF8), "page_break_comments") + ' e.g., page range: multipart.Add(New StringContent("1-3", Encoding.UTF8), "page_range") + + Dim req As New HttpRequestMessage(HttpMethod.Post, "markdown") + req.Headers.TryAddWithoutValidation("Api-Key", apiKey) + req.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + req.Content = multipart + + Dim resp As HttpResponseMessage = Await httpClient.SendAsync(req) + Dim body As String = Await resp.Content.ReadAsStringAsync() + If Not resp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Markdown (multipart) failed: {CInt(resp.StatusCode)} {resp.ReasonPhrase}") + Console.Error.WriteLine(body) + Environment.Exit(1) + End If + + Console.WriteLine(body) + End Using + End Function + End Module +End Namespace diff --git a/VB.NET/Endpoint Examples/Multipart Payload/rasterized-pdf.vb b/VB.NET/Endpoint Examples/Multipart Payload/rasterized-pdf.vb new file mode 100644 index 00000000..4bbd997f --- /dev/null +++ b/VB.NET/Endpoint Examples/Multipart Payload/rasterized-pdf.vb @@ -0,0 +1,95 @@ +''' +' What this sample does: +' - Creates a rasterized version of a PDF using pdfRest. +' - Sends a single multipart/form-data request directly to /rasterized-pdf with the file. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run -- rasterized-pdf-multipart /path/to/input.pdf +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run -- rasterized-pdf-multipart /path/to/input.pdf > response.json +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.IO +Imports System.Net.Http +Imports System.Net.Http.Headers +Imports System.Text +Imports System.Threading.Tasks + +Namespace VBNetSamples.Endpoint_Examples.Multipart_Payload + Module RasterizedPdf + Public Async Function Execute(args As String()) As Task + If args Is Nothing OrElse args.Length < 1 Then + Console.Error.WriteLine("Usage: dotnet run -- rasterized-pdf-multipart /path/to/input.pdf") + Environment.Exit(1) + End If + + Dim inputPath As String = args(0) + If Not File.Exists(inputPath) Then + Console.Error.WriteLine($"Input file not found: {inputPath}") + Environment.Exit(1) + End If + + Dim apiKey As String = Environment.GetEnvironmentVariable("PDFREST_API_KEY") + If String.IsNullOrWhiteSpace(apiKey) Then + Console.Error.WriteLine("Missing environment variable PDFREST_API_KEY.") + Environment.Exit(1) + End If + + Dim baseUrl As String = Environment.GetEnvironmentVariable("PDFREST_URL") + If String.IsNullOrWhiteSpace(baseUrl) Then baseUrl = "https://api.pdfrest.com" + + Dim baseUri As Uri + Try + baseUri = New Uri(baseUrl) + Catch ex As Exception + Console.Error.WriteLine($"Invalid PDFREST_URL: {baseUrl}") + Environment.Exit(1) + Return + End Try + + Using httpClient As New HttpClient() + httpClient.BaseAddress = baseUri + + Dim multipart As New MultipartFormDataContent() + Dim fileBytes As Byte() = File.ReadAllBytes(inputPath) + Dim fileContent As New ByteArrayContent(fileBytes) + fileContent.Headers.ContentType = New MediaTypeHeaderValue("application/pdf") + multipart.Add(fileContent, "file", Path.GetFileName(inputPath)) + + multipart.Add(New StringContent("pdfrest_rasterize", Encoding.UTF8), "output") + ' Optional settings: + ' multipart.Add(New StringContent("300", Encoding.UTF8), "dpi") + ' multipart.Add(New StringContent("rgb", Encoding.UTF8), "color_space") + ' multipart.Add(New StringContent("1-3", Encoding.UTF8), "page_range") + + Dim req As New HttpRequestMessage(HttpMethod.Post, "rasterized-pdf") + req.Headers.TryAddWithoutValidation("Api-Key", apiKey) + req.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + req.Content = multipart + + Dim resp As HttpResponseMessage = Await httpClient.SendAsync(req) + Dim body As String = Await resp.Content.ReadAsStringAsync() + If Not resp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Rasterized-pdf (multipart) failed: {CInt(resp.StatusCode)} {resp.ReasonPhrase}") + Console.Error.WriteLine(body) + Environment.Exit(1) + End If + + Console.WriteLine(body) + End Using + End Function + End Module +End Namespace diff --git a/VB.NET/Program.vb b/VB.NET/Program.vb new file mode 100644 index 00000000..99734dbf --- /dev/null +++ b/VB.NET/Program.vb @@ -0,0 +1,87 @@ +''' +' What this sample does: +' - Provides a command dispatcher for VB.NET samples in this folder. +' - Routes `dotnet run -- ` to the corresponding sample module. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage: +' dotnet run -- [args] +' e.g., dotnet run -- markdown /path/to/input.pdf +' +' Output: +' - Each command prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.Linq +Imports System.Threading.Tasks +Imports DotNetEnv + +Module Program + Public Sub Main(args As String()) + MainAsync(args).GetAwaiter().GetResult() + End Sub + + Private Async Function MainAsync(args As String()) As Task + ' Load environment variables from .env if present (via DotNetEnv) + Env.Load() + If args Is Nothing OrElse args.Length = 0 Then + PrintUsage() + Environment.Exit(1) + End If + + Dim cmd As String = args(0).Trim().ToLowerInvariant() + Dim rest As String() + If args.Length > 1 Then + rest = args.Skip(1).ToArray() + Else + rest = Array.Empty(Of String)() + End If + + Select Case cmd + Case "markdown", "markdown-json" + Await VBNetSamples.Endpoint_Examples.JSON_Payload.Markdown.Execute(rest) + Case "rasterized-pdf", "rasterize-json" + Await VBNetSamples.Endpoint_Examples.JSON_Payload.RasterizedPdf.Execute(rest) + Case "markdown-multipart" + Await VBNetSamples.Endpoint_Examples.Multipart_Payload.Markdown.Execute(rest) + Case "rasterized-pdf-multipart", "rasterize-multipart" + Await VBNetSamples.Endpoint_Examples.Multipart_Payload.RasterizedPdf.Execute(rest) + Case "merge-different-file-types", "merge" + Await VBNetSamples.Complex_Flow_Examples.MergeDifferentFileTypes.Execute(rest) + Case Else + Console.Error.WriteLine($"Unknown command: {cmd}") + PrintUsage() + Environment.Exit(1) + End Select + End Function + + ' DotNetEnv handles .env loading; no manual parser needed. + + Private Sub PrintUsage() + Console.Error.WriteLine("Usage: dotnet run -- [args]") + Console.Error.WriteLine("") + Console.Error.WriteLine("Commands:") + Console.Error.WriteLine(" markdown | markdown-json Upload then convert to Markdown (JSON two-step)") + Console.Error.WriteLine(" rasterized-pdf | rasterize-json Upload then rasterize PDF (JSON two-step)") + Console.Error.WriteLine(" markdown-multipart Convert to Markdown (single multipart request)") + Console.Error.WriteLine(" rasterized-pdf-multipart Rasterize PDF (single multipart request)") + Console.Error.WriteLine(" merge-different-file-types|merge Merge PDFs and non-PDFs into one PDF") + Console.Error.WriteLine("") + Console.Error.WriteLine("Examples:") + Console.Error.WriteLine(" dotnet run -- markdown /path/to/input.pdf") + Console.Error.WriteLine(" dotnet run -- rasterized-pdf /path/to/input.pdf") + Console.Error.WriteLine(" dotnet run -- markdown-multipart /path/to/input.pdf") + Console.Error.WriteLine(" dotnet run -- rasterized-pdf-multipart /path/to/input.pdf") + Console.Error.WriteLine(" dotnet run -- merge-different-file-types file1.pdf file2.docx image.png") + End Sub +End Module diff --git a/VB.NET/README.md b/VB.NET/README.md new file mode 100644 index 00000000..3f895ced --- /dev/null +++ b/VB.NET/README.md @@ -0,0 +1,71 @@ +# pdfRest VB.NET Samples + +These VB.NET samples demonstrate how to call pdfRest APIs using HttpClient. A single console project (`VBNetSamples.vbproj`) acts as a dispatcher so you can run any sample with a simple command. + +## Prerequisites +- .NET SDK 8.0 or newer (check with `dotnet --version`). +- A pdfRest API key. +- Internet access to reach `https://api.pdfrest.com` (or the EU endpoint below). + +## Quick Start +1) From this `VB.NET/` folder, copy the environment template and set your API key: +- `cp .env.example .env` +- Edit `.env` and set `PDFREST_API_KEY=your_api_key_here` + +2) Optional: EU/GDPR endpoint for European data residency and performance: +- In `.env`, set `PDFREST_URL=https://eu-api.pdfrest.com` +- More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work + +3) Restore and build the project (from this folder): +- `dotnet restore` +- `dotnet build` + +4) Run a sample (examples below). The dispatcher pattern is: +- `dotnet run -- [args]` + +## How It’s Organized +- `VBNetSamples.vbproj`: single console app that compiles all VB samples in this folder. +- `Program.vb`: a small dispatcher that routes `` to a specific sample’s `Execute` method. +- `Endpoint Examples/JSON Payload/`: two‑step samples (upload, then operate with a JSON body). +- `Endpoint Examples/Multipart Payload/`: single multipart/form-data request per operation. +- `Complex Flow Examples/`: multi-step workflows combining endpoints. +- `.env`: holds configuration (`PDFREST_API_KEY`, optional `PDFREST_URL`). Loaded automatically via DotNetEnv. + +## Available Samples +JSON two‑step (upload → operate via JSON): +- `markdown` — Convert PDF to Markdown + - Run: `dotnet run -- markdown /path/to/input.pdf` +- `rasterized-pdf` — Rasterize a PDF + - Run: `dotnet run -- rasterized-pdf /path/to/input.pdf` + +Multipart single request (send file directly): +- `markdown-multipart` — Convert PDF to Markdown + - Run: `dotnet run -- markdown-multipart /path/to/input.pdf` +- `rasterized-pdf-multipart` — Rasterize a PDF + - Run: `dotnet run -- rasterized-pdf-multipart /path/to/input.pdf` + +Complex flow: +- `merge-different-file-types` — Merge multiple inputs (PDFs and non‑PDFs) + - Run: `dotnet run -- merge-different-file-types file1.pdf file2.docx image.png` + +## Output & Error Handling +- Successful calls print the API’s JSON response to stdout. +- Failures write a concise message to stderr and exit with a non‑zero code. +- Tip: redirect output to a file, e.g., `... > response.json`. + +## Troubleshooting +- Missing API key: + - Ensure `.env` exists with `PDFREST_API_KEY` set, or export it in your shell before running. +- EU endpoint: + - If using the EU endpoint, verify `PDFREST_URL=https://eu-api.pdfrest.com` in `.env`. +- .NET version: + - Check with `dotnet --version`. Use .NET 8.0 or newer. +- Clean build: + - `rm -rf bin obj && dotnet build` +- Proxy environments: + - If your network requires a proxy, set standard environment variables like `HTTPS_PROXY`. + +## Notes +- These are focused samples to help you evaluate pdfRest quickly. +- Do not commit secrets. Keep `.env` out of version control. +- For more APIs, options, and regions, see the pdfRest documentation and pricing page. diff --git a/VB.NET/VBNetSamples.vbproj b/VB.NET/VBNetSamples.vbproj new file mode 100644 index 00000000..5241f19f --- /dev/null +++ b/VB.NET/VBNetSamples.vbproj @@ -0,0 +1,22 @@ + + + Exe + VBNetSamples + net8.0 + On + On + On + VBNetSamples.Program + false + + + + + + + + + + + +