How to Refry a PDF with Java

Refry a PDF with Java through a PDF to PostScript to PDF workflow using pdfRest resource IDs.
Share this page

This Java walkthrough uses an OkHttp multipart request from a JVM application. It completes a PDF -> PostScript -> PDF roundtrip by passing a resource ID from /postscript into /pdf. The complete sample is included below so Java developers can see the file handling, request construction, and response path together.

Why Refry a PDF with Java?

PDF refrying converts a PDF to PostScript and then converts the PostScript into a new PDF. Some document-production, print, and prepress workflows use that roundtrip when a legacy downstream system requires rebuilt page content or a PostScript-based intermediate.

Java makes the two service dependencies explicit and easy to integrate into a managed application: the first request returns a PostScript resource, and the second request consumes that resource to produce the final PDF. No intermediate file has to be downloaded between the calls, while a job record can retain the original input ID, intermediate ID, and final PDF ID for controlled diagnostics.

Because refrying trades away PDF-specific constructs, retain the source PDF and use the generated file only where the downstream requirement accepts the roundtrip’s consequences.

Java Code Example for PDF Refrying

import io.github.cdimascio.dotenv.Dotenv;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.json.JSONObject;

/*
 * Refry a PDF by converting it to PostScript and back to PDF.
 *
 * PDF refrying is the common name for a PDF -> PostScript -> PDF roundtrip.
 * Some print, prepress, and legacy production workflows use it to rebuild,
 * flatten, or normalize page content for downstream systems. The process is
 * intentionally lossy and may remove tags, forms, layers, annotations,
 * transparency, metadata, and editability. Use this workflow when a downstream
 * system requires rebuilt page content or a PostScript-based interchange file.
 *
 * The PostScript-to-PDF step uses a custom .joboptions profile in this sample.
 * A .joboptions file contains Adobe Distiller-compatible conversion settings;
 * it is optional, and default settings are used when omitted. pdfRest applies
 * the profile with Datalogics PDF Converter SDK. Datalogics maintains the SDK
 * in partnership with Adobe, using the same Adobe technology that powers
 * Distiller.
 *
 * Run: java RefryPdf   [outputPdf]
 */
public class RefryPdf {
  private static final String DEFAULT_API_URL = "https://api.pdfrest.com";
  private static final String DEFAULT_API_KEY = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
  private static final OkHttpClient CLIENT =
      new OkHttpClient.Builder().readTimeout(120, TimeUnit.SECONDS).build();

  public static void main(String[] args) throws IOException {
    File inputFile = new File(args.length > 0 ? args[0] : "/path/to/sample.pdf");
    File jobOptionsFile = new File(args.length > 1 ? args[1] : "/path/to/custom.joboptions");
    Path outputPath = args.length > 2 ? Path.of(args[2]) : Path.of("refried.pdf");

    Dotenv dotenv = Dotenv.configure().ignoreIfMalformed().ignoreIfMissing().load();
    String apiUrl = dotenv.get("PDFREST_URL", DEFAULT_API_URL).replaceAll("/$", "");
    String apiKey = dotenv.get("PDFREST_API_KEY", DEFAULT_API_KEY);

    JSONObject postscript =
        postMultipart(
            apiUrl,
            apiKey,
            "postscript",
            new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart(
                    "file",
                    inputFile.getName(),
                    RequestBody.create(inputFile, MediaType.parse("application/pdf")))
                .addFormDataPart("ps_level", "3")
                .addFormDataPart("page_range", "all")
                .addFormDataPart("binary_output", "true")
                .addFormDataPart("scale", "1")
                .addFormDataPart("rotate", "false")
                .addFormDataPart("shrink_to_fit", "true")
                .addFormDataPart("print_annotations", "true")
                .addFormDataPart("output", "refry_intermediate")
                .build());

    JSONObject finalPdf =
        postMultipart(
            apiUrl,
            apiKey,
            "pdf",
            new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("id", postscript.getString("outputId"))
                .addFormDataPart(
                    "job_options",
                    jobOptionsFile.getName(),
                    RequestBody.create(jobOptionsFile, MediaType.parse("application/octet-stream")))
                .addFormDataPart("output", "refried")
                .build());

    Request downloadRequest =
        new Request.Builder()
            .url(apiUrl + "/resource/" + finalPdf.getString("outputId") + "?format=file")
            .header("Api-Key", apiKey)
            .build();
    try (Response response = CLIENT.newCall(downloadRequest).execute()) {
      if (!response.isSuccessful() || response.body() == null) {
        throw new IOException("resource download failed: " + response.code());
      }
      Files.write(outputPath, response.body().bytes());
    }

    System.out.println(finalPdf.toString(2));
    System.out.println("Created " + outputPath.toAbsolutePath());
  }

  private static JSONObject postMultipart(
      String apiUrl, String apiKey, String endpoint, RequestBody body) throws IOException {
    Request request =
        new Request.Builder()
            .url(apiUrl + "/" + endpoint)
            .header("Api-Key", apiKey)
            .header("Accept", "application/json")
            .post(body)
            .build();
    try (Response response = CLIENT.newCall(request).execute()) {
      String text = response.body() == null ? "" : response.body().string();
      System.out.println(endpoint + ": " + response.code());
      if (!response.isSuccessful()) {
        throw new IOException(endpoint + " failed: " + text);
      }
      return new JSONObject(text);
    }
  }
}

Source: View the sample on GitHub

Breaking Down the Code

Configure the service and input

public class RefryPdf {
  private static final String DEFAULT_API_URL = "https://api.pdfrest.com";
  private static final String DEFAULT_API_KEY = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
  private static final OkHttpClient CLIENT =
      new OkHttpClient.Builder().readTimeout(120, TimeUnit.SECONDS).build();

  public static void main(String[] args) throws IOException {

For this PDF Refrying example, Java coordinates the two dependent API calls. The Java samples use OkHttp for multipart HTTP requests and dotenv support for repository configuration. The sample project supplies those dependencies; applications that copy the class elsewhere need equivalent dependencies and secure runtime configuration. The sample’s placeholder path and API key make the moving pieces visible; replace them with a real local path and protected runtime credential before using the request.

Pass the Intermediate Resource to the Next Step

"pdf",
            new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("id", postscript.getString("outputId"))
                .addFormDataPart(
                    "job_options",
                    jobOptionsFile.getName(),
                    RequestBody.create(jobOptionsFile, MediaType.parse("application/octet-stream")))
                .addFormDataPart("output", "refried")
                .build());

In the Java workflow, outputId from /postscript becomes the id passed to /pdf. The second request also supplies a custom .joboptions file so the return conversion has an explicit Adobe Distiller-compatible profile, even though default settings are available when the profile is omitted.

Build the multipart request

apiKey,
            "postscript",
            new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart(
                    "file",
                    inputFile.getName(),
                    RequestBody.create(inputFile, MediaType.parse("application/pdf")))
                .addFormDataPart("ps_level", "3")
                .addFormDataPart("page_range", "all")
                .addFormDataPart("binary_output", "true")

For the PDF Refrying form, okHttp’s MultipartBody.Builder constructs the form and assigns its boundary. Each file part carries a filename and media type, while conversion options are ordinary text parts.

Read the output resource

.url(apiUrl + "/resource/" + finalPdf.getString("outputId") + "?format=file")
            .header("Api-Key", apiKey)
            .build();
    try (Response response = CLIENT.newCall(downloadRequest).execute()) {
      if (!response.isSuccessful() || response.body() == null) {
        throw new IOException("resource download failed: " + response.code());
      }
      Files.write(outputPath, response.body().bytes());
    }

    System.out.println(finalPdf.toString(2));
    System.out.println("Created " + outputPath.toAbsolutePath());

After the PDF Refrying call, the response block checks the HTTP status before printing its body. On success, the JSON contains the output resource ID and URL; on failure, the printed body gives the API error detail needed for diagnosis.

Beyond the Tutorial

You completed the two-stage refry process in Java and saved the final PDF after both calls succeeded. The intermediate response ID is the important handoff between conversion stages, not merely a status value to print and discard.

Try representative pdf refrying inputs in API Lab. For the authoritative request fields, accepted values, and response contract, consult the pdfRest API Reference Guide. The same request pattern can then be adapted to your Java application’s error handling, retention policy, and delivery workflow.

Generate a self-service API Key now!
Create your FREE API Key to start processing PDFs in seconds, only possible with pdfRest.