pdfDocumentFromUri function

Future<PdfDocument> pdfDocumentFromUri(
  1. Uri uri, {
  2. PdfPasswordProvider? passwordProvider,
  3. bool firstAttemptByEmptyPassword = true,
  4. int? blockSize,
  5. PdfFileCache? cache,
  6. PdfDownloadProgressCallback? progressCallback,
  7. PdfDownloadReportCallback? reportCallback,
  8. bool useRangeAccess = true,
  9. Map<String, String>? headers,
})

Open PDF file from uri.

On web, unlike PdfDocument.openUri, this function uses HTTP's range request to download the file and uses PdfFileCache.

Implementation

Future<PdfDocument> pdfDocumentFromUri(
  Uri uri, {
  PdfPasswordProvider? passwordProvider,
  bool firstAttemptByEmptyPassword = true,
  int? blockSize,
  PdfFileCache? cache,
  PdfDownloadProgressCallback? progressCallback,
  PdfDownloadReportCallback? reportCallback,
  bool useRangeAccess = true,
  Map<String, String>? headers,
}) async {
  final startTime = reportCallback != null ? DateTime.now() : null;
  void report() {
    if (reportCallback != null && cache?.isInitialized == true) {
      reportCallback(
        cache?.cachedBytes ?? 0,
        cache?.fileSize ?? 0,
        DateTime.now().difference(startTime!),
      );
    }
  }

  progressCallback?.call(0);
  cache ??= await PdfFileCache.fromUri(uri);
  final httpClient = http.Client();
  try {
    if (!cache.isInitialized) {
      cache.setBlockSize(blockSize ?? PdfFileCache.defaultBlockSize);
      final result = await _downloadBlock(
        httpClient,
        uri,
        cache,
        progressCallback,
        0,
        useRangeAccess: useRangeAccess,
        headers: headers,
      );
      if (result.isFullDownload) {
        return await PdfDocument.openFile(
          cache.filePath,
          passwordProvider: passwordProvider,
          firstAttemptByEmptyPassword: firstAttemptByEmptyPassword,
        );
      }
    } else {
      // Check if the file is fresh (no-need-to-reload).
      if (cache.cacheControlState.cacheControl.mustRevalidate &&
          cache.cacheControlState.isFresh(now: DateTime.now())) {
        // cache is valid; no need to download.
      } else {
        final result = await _downloadBlock(
          httpClient,
          uri,
          cache,
          progressCallback,
          0,
          addCacheControlHeaders: true,
          useRangeAccess: useRangeAccess,
          headers: headers,
        );
        if (result.isFullDownload) {
          cache.close(); // close the cache file before opening it.
          httpClient.close();
          return await PdfDocument.openFile(
            cache.filePath,
            passwordProvider: passwordProvider,
            firstAttemptByEmptyPassword: firstAttemptByEmptyPassword,
          );
        }
      }
    }

    return await PdfDocument.openCustom(
      read: (buffer, position, size) async {
        final totalSize = size;
        final end = position + size;
        int bufferPosition = 0;
        for (int p = position; p < end;) {
          final blockId = p ~/ cache!.blockSize;
          final isAvailable = cache.isCached(blockId);
          if (!isAvailable) {
            await _downloadBlock(
              httpClient,
              uri,
              cache,
              progressCallback,
              blockId,
              headers: headers,
            );
          }
          final readEnd = min(p + size, (blockId + 1) * cache.blockSize);
          final sizeToRead = readEnd - p;
          await cache.read(buffer, bufferPosition, p, sizeToRead);
          p += sizeToRead;
          bufferPosition += sizeToRead;
          size -= sizeToRead;
        }
        return totalSize;
      },
      passwordProvider: passwordProvider,
      firstAttemptByEmptyPassword: firstAttemptByEmptyPassword,
      fileSize: cache.fileSize,
      sourceName: uri.toString(),
      onDispose: () {
        cache!.close();
        httpClient.close();
      },
    );
  } catch (e) {
    cache.close();
    httpClient.close();
    rethrow;
  } finally {
    report();
  }
}