Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use a completion-driven queue, not a tight for loop. iclems/iOS-htmltopdf renders each URL or HTML string asynchronously in a UIWebView. Start one conversion, retain its NDHTMLtoPDF object, and begin the next file only from the previous job’s success or error callback. Give every input and output a unique path, and pass the page size and margins explicitly.

This approach avoids the overlapping-work crash reported for loop-based implementations, keeps failures from stalling the batch, and makes pagination problems reproducible.

What the library converts

iclems/iOS-htmltopdf provides URL-based PDF creation and HTML-string overloads. A URL conversion receives a source URL, destination path, paper size, margins, and either delegate or block callbacks. In-memory HTML uses createPDFWithHTML; its baseURL: variants provide the origin needed to resolve relative CSS, images, and fonts.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The documented A4 example is CGSizeMake(595.2,841.8). Margins are supplied as UIEdgeInsets. Keep both values explicit for every item in a batch.

#1 Best Overall
Sale
Brother DS-640 Compact Mobile Document Scanner, (Model: DS640)
  • FAST SPEEDS - Scans color and black and white documents a blazing speed up to 16ppm (1). Color scanning won’t slow you down as the color scan speed is the same as the black and white scan speed.
  • ULTRA COMPACT – At less than 1 foot in length and only about 1. 5lbs in weight you can fit this device virtually anywhere (a bag, a purse, even a pocket).
  • READY WHENEVER YOU ARE – The DS-640 mobile scanner is powered via an included micro USB 3. 0 cable allowing you to use it even where there is no outlet available. Plug it into you PC or laptop and you are ready to scan.
  • WORKS YOUR WAY – Use the Brother free iPrint&Scan desktop app for scanning to multiple “Scan-to” destinations like PC, Network, cloud services, Email and OCR. (2) Supports Windows, Mac and Linux and TWAIN/WIA for PC/ICA for Mac/SANE drivers. (3)
  • OPTIMIZE IMAGES AND TEXT – Automatic color detection/adjustment, image rotation (PC only), bleed through prevention/background removal, text enhancement, color drop to enhance scans. Software suite includes document management and OCR software. (4)

Prepare a safe batch

Use unique names

Derive each PDF path from an identifier rather than reusing one temporary filename. For example, invoice-0001.pdf, invoice-0002.pdf, and so on. Decide whether an existing file should be overwritten or skipped, and log that decision.

Retain the converter

The README warns that NDHTMLtoPDF works asynchronously and should be retained in a property such as PDFCreator. A local variable that goes out of scope can leave the operation without a live owner.

Keep the queue serial

A serial queue is the most predictable pattern for UIWebView-backed conversion. It limits memory pressure, prevents two jobs from competing for shared state, and gives each completion callback a clear next action. The Stack Overflow report associated with this workflow describes crashes when a tight loop starts overlapping block work; treat that as a concurrency warning, not as a drop-in implementation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Objective-C: convert files one at a time

The following structure assumes pendingHTMLFiles contains file-system paths and that documentsDirectory is already set. Adapt the exact initializer spelling to the library version you have installed; the project documents both delegate and block signatures.

- (void)convertNextHTML {
    if (self.pendingHTMLFiles.count == 0) {
        NSLog(@"Batch complete. Successes: %lu, failures: %lu",
              (unsigned long)self.completedFiles.count,
              (unsigned long)self.failedFiles.count);
        return;
    }

    NSString *htmlPath = self.pendingHTMLFiles.firstObject;
    [self.pendingHTMLFiles removeObjectAtIndex:0];

    NSURL *htmlURL = [NSURL fileURLWithPath:htmlPath];
    NSString *stem = htmlPath.lastPathComponent.stringByDeletingPathExtension;
    NSString *pdfName = [stem stringByAppendingPathExtension:@"pdf"];
    NSString *pdfPath = [self.documentsDirectory
                         stringByAppendingPathComponent:pdfName];

    CGSize paper = CGSizeMake(595.2, 841.8); // documented A4 example
    UIEdgeInsets margins = UIEdgeInsetsMake(10, 5, 10, 5);

    self.PDFCreator = [NDHTMLtoPDF createPDFWithURL:htmlURL
        pathForPDF:pdfPath
        pageSize:paper
        margins:margins
        successBlock:^(NDHTMLtoPDF *job) {
            [self.completedFiles addObject:htmlPath];
            [self convertNextHTML];
        }
        errorBlock:^(NDHTMLtoPDF *job) {
            [self.failedFiles addObject:htmlPath];
            NSLog(@"PDF failed for %@", htmlPath);
            [self convertNextHTML];
        }];
}

Initialize mutable arrays, the pending list, and the documents directory before calling convertNextHTML. Call the method on the main thread if required by the version of the library, because the renderer is based on UIWebView. In production, store an error description and the selected paper and margin values with each failed item.

Why both callbacks must advance the queue

If only the success block starts the next item, one malformed document can halt the entire batch. The error block should record the failure and call the same queue-advancing method. This gives you a complete result list instead of an apparently frozen export.

Rank #2
Scanner Bin - The Clever Document Scanning Solution
  • Flatbed scanners simply cannot compete with your smartphone and a Scanner Bin. Improved resolution and color rendering compared to popular flatbed scanners. Compare to 1200 DPI. Takes a fraction of the time to scan at a fraction of the cost. Not to mention that flatbed scanners end up adding a lot of hazardous e-waste to your local landfill.
  • Solve the common issues with smartphone scanning. Provides a contrasting background for consistent edge-detection and auto-cropping. Controls the lighting and provides stability and proper positioning while you scan with your smartphone.
  • Scan photographs, receipts, letters, notes, artwork, fragile documents, etc. Also used as an aid for the blind or visually impaired or as a document camera for remote learning. When you aren't scanning, turn on its side to use as a desk-side bin to toss in the items you want to scan later.
  • This version is the lowest cost option for a scanner solution. It is also simplified for set up and use, and therefore is recommended for those who are blind, visually impaired or have movement disorders.
  • Use with popular FREE APPS for document scanning like Adobe Scan, Scanbot, Evernote Scannable, CamScanner, and Prizmo Go

Convert HTML held in memory

When your app generates HTML strings rather than reading files, use the documented createPDFWithHTML overload. Pass baseURL: whenever markup contains relative references such as css/print.css, images/logo.png, or web fonts.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
NSString *html = [self htmlForInvoice:invoice];
NSURL *baseURL = [NSURL fileURLWithPath:self.templateDirectory
                            isDirectory:YES];
NSString *pdfPath = [self.documentsDirectory
                     stringByAppendingPathComponent:@"invoice-0001.pdf"];

self.PDFCreator = [NDHTMLtoPDF createPDFWithHTML:html
    baseURL:baseURL
    pathForPDF:pdfPath
    pageSize:CGSizeMake(595.2, 841.8)
    margins:UIEdgeInsetsMake(10, 5, 10, 5)
    successBlock:^(NDHTMLtoPDF *job) {
        // Persist success, then dequeue the next HTML string.
    }
    errorBlock:^(NDHTMLtoPDF *job) {
        // Persist failure, then dequeue the next HTML string.
    }];

Use a distinct base URL for each template set if relative assets live in different directories. If all resources are embedded as data URLs or absolute file URLs, a base URL may not be necessary, but supplying the correct context is safer.

Pagination: when one document becomes two pages

A project issue reports an HTML document expected to fit on one page producing two pages, even when the PDF appears to have unused space. Check the layout before treating that result as a converter defect.

  • Remove or account for the browser’s default body margin.
  • Inspect fixed heights and widths on wrappers, tables, and image containers.
  • Check image dimensions; a natural-size image can extend the effective content box.
  • Look for line wrapping caused by the selected paper width, font availability, or long unbreakable strings.
  • Subtract the supplied UIEdgeInsets margins from the paper dimensions when estimating printable height.
  • Confirm that CSS used for screen layout is not adding extra blocks, floats, or page-breaking behavior.

For every item, log the HTML identifier, paper CGSize, margins, and destination path. That record lets you reproduce a second-page result instead of guessing which document used different settings.

Batch reliability and operational choices

Serial versus overlapping jobs

Serial processing is the recommended default for this library because each conversion owns a web view and asynchronous state. Launching many jobs at once can increase memory use and recreate the reported loop crash. The available material does not establish a throughput number or timing benchmark, so size a queue from your own documents and device tests.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Failure handling

Never delete the source before its success callback. Write failures to a retry list with the source path and error context. A retry should receive a new destination policy: either remove a known partial file first or deliberately overwrite it.

Rank #3
Sale
ScanSnap iX1300 Wireless or USB Double-Sided Color Document Scanner, White
  • FITS SMALL SPACES AND STAYS OUT OF THE WAY. Innovative space-saving design to free up desk space, even when it's being used
  • SCAN DOCUMENTS, PHOTOS, CARDS, AND MORE. Handles most document types, including thick items and plastic cards. Exclusive QUICK MENU lets you quickly scan-drag-drop to your favorite computer apps
  • GREAT IMAGES EVERY TIME, NO EXPERIENCE REQUIRED. A single touch starts fast, up to 30ppm duplex scanning with automatic de-skew, color optimization, and blank page removal for outstanding results without driver setup
  • SCAN WHERE YOU WANT, WHEN YOU WANT. Connect with USB or Wi-Fi. Send to Mac, PC, mobile devices, and cloud services. Scan to Chromebook using the mobile app. Can be used without a computer
  • PHOTO AND DOCUMENT ORGANIZATION MADE EFFORTLESS. ScanSnap Home all-in-one software brings together all your favorite functions. Easily manage, edit, and use scanned data from documents, receipts, business cards, photos, and more

Offline assets

Local HTML and local resources can be rendered without a hosted conversion service, provided the web view can resolve every reference. Remote assets introduce network availability and authentication concerns; use absolute URLs, local copies, or a correct baseURL: as appropriate.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common errors and fixes

The app crashes when processing a list

Cause: a tight loop starts multiple asynchronous conversions, or the converter is not retained. Fix: retain the active NDHTMLtoPDF, remove one item from the queue, and invoke the next conversion only inside both completion paths.

Images, CSS, or fonts are missing

Cause: relative URLs have no resolvable origin. Fix: use the HTML overload with an appropriate baseURL:, verify the directory exists, and check filename case on case-sensitive storage.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The wrong PDF is overwritten

Cause: every job uses the same output path or an unexpanded template name. Fix: create a collision-resistant name from the item identifier, verify the expanded path in logs, and choose overwrite or skip behavior explicitly.

The queue stops partway through

Cause: the next call exists only in the success block. Fix: record the error and call convertNextHTML from the error block as well.

A supposedly single-page document spills onto page two

Cause: CSS box sizes, default margins, image dimensions, wrapping, or the explicit PDF margins exceed the printable area. Fix: inspect those values, reduce unintended spacing, and keep paper and margin settings identical while debugging.

Rank #4
Sale
Epson Workforce ES-50 Compact & Lightweight Mobile Document Scanner
  • PORTABLE SCANNER FOR USE ON-THE-GO — The fastest and lightest mobile single-sheet-fed compact document scanner in its class¹
  • QUICK DOCUMENT SCANNING ― This Epson ultra-fast scanner scans a single page as quickly as 5.5 seconds²; Windows and Mac compatible
  • VERSATILE PAPER HANDLING ― Portable scanner scans documents up to 8.5 x 72 in; Also easily digitizes receipts and ID cards to make accounting, bookkeeping, and organizing simpler
  • INTUITIVE, HIGH-SPEED SOFTWARE — Epson ScanSmart Software³ is a smart tool allowing you to easily scan, review, and save; Stay organized easily with the help of this Epson scanner
  • EASY SETUP — USB-powered connect to your computer for quick and simple scanning; No batteries or external power supply required to operate portable document scanner; Standard Connectivity: USB 2.0

Do-it-yourself checklist

  1. Collect source paths or HTML strings and assign a stable identifier to each.
  2. Choose a paper size and UIEdgeInsets margins.
  3. Generate a unique destination path for every item.
  4. Provide baseURL: for relative resources.
  5. Retain the NDHTMLtoPDF instance.
  6. Start one job and advance only from success or error.
  7. Record successes, failures, settings, and partial-file cleanup decisions.
  8. Review page count and asset loading on representative documents before a large export.

Or skip the browser setup

If your goal is simply to capture web pages or produce PDFs from URLs, ScreenshotNeo provides a hosted screenshot API and MCP server. A single GET request can return PNG, JPEG, WebP, or PDF, while the service accepts the cookie or consent banner as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo documentation for PDF paper size, margins, page ranges, async jobs, bulk capture, signed webhooks, and the other capture options. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed as clean shots; response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.

When on-device conversion is the better fit

Keep iOS-htmltopdf when documents must render from local data, work offline, or remain inside your app’s storage boundary. Choose a hosted endpoint when you need URL capture without maintaining web-view setup, want automated cleanup of consent UI, or need an MCP workflow for AI agents. For either approach, validate pagination and asset loading with your own HTML; no independent throughput or compatibility benchmark is established for this exact multi-file workflow.

Frequently Asked Questions

Can I start all conversions with a dispatch group?

A dispatch group can coordinate asynchronous work, but launching many UIWebView conversions concurrently is the pattern associated with the reported crash. A serial completion-driven queue is easier to control; use a group only if you have separately verified safe concurrency for your library version and device targets.

Do I need a baseURL for absolute image URLs?

Not usually. The base URL is specifically useful for relative CSS, images, and fonts. Supplying the correct base URL remains a safe default for template-based HTML.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Does the documented A4 size use points?

The README expresses A4 as CGSizeMake(595.2,841.8). Pass that CGSize directly, and keep the same units when reasoning about margins and printable height.

Are performance timings available for this batch pattern?

No published independent timing or throughput statistic is established for this exact workflow. Measure representative documents on the iOS devices and HTML versions you support.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.