Skip to content

Instantly share code, notes, and snippets.

@pdfcrowd
Last active March 16, 2023 08:20
Show Gist options
  • Save pdfcrowd/9269baacf8c0e84ef2a9d884742e1d38 to your computer and use it in GitHub Desktop.
Save pdfcrowd/9269baacf8c0e84ef2a9d884742e1d38 to your computer and use it in GitHub Desktop.
This code shows how to convert HTML to PDF in C using the Pdfcrowd API. You can find the tutorial here: https://pdfcrowd.com/blog/convert-html-to-pdf-in-c/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#define API_ENDPOINT "https://api.pdfcrowd.com/convert/latest/"
#define USERNAME "demo"
#define API_KEY "ce544b6ea52a5621fb9d55f8b542d14d"
/* structure for conversion options */
typedef struct {
const char *name;
const char *value;
} FormField;
/* structure for conversion files */
typedef struct {
const char *name;
const char *filename;
const char *mime_type;
const char *data;
size_t data_len;
} FormFile;
/* structure for conversion response */
typedef struct {
char *buffer;
size_t size;
} ResponseBody;
/* write callback to hold the response in a memory buffer */
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *data)
{
size_t realsize = size * nmemb;
ResponseBody* mem = (ResponseBody*) data;
mem->buffer = realloc(mem->buffer, mem->size + realsize + 1);
if (mem->buffer == NULL) {
fprintf(stderr, "Not enough buffer\n");
return 0;
}
memcpy(&(mem->buffer[mem->size]), ptr, realsize);
mem->size += realsize;
mem->buffer[mem->size] = 0;
return realsize;
}
/* conversion function as a multipart post to Pdfcrowd API servers */
long convert(FormField *fields, int num_fields, FormFile *files, int num_files, const char* output_filename) {
/* define local variables used */
int i;
curl_mime *mime;
curl_mimepart *part;
struct curl_slist *headers = NULL;
ResponseBody response_body = { 0 };
CURLcode res;
/* result -1 means error, otherwise it containse HTTP status code */
/* result 200 means success */
/* result greater than 200 means the conversion error, details: https://pdfcrowd.com/api/status-codes/ */
long result = -1;
/* initialize CURL library */
CURL *curl = curl_easy_init();
if (!curl) {
fprintf(stderr, "Failed to initialize libcurl\n");
return result;
}
/* set conversion entry point */
curl_easy_setopt(curl, CURLOPT_URL, API_ENDPOINT);
/* set Pdfcrowd username and API key */
curl_easy_setopt(curl, CURLOPT_USERPWD, USERNAME ":" API_KEY);
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
/* set HTTP multipart post data */
curl_easy_setopt(curl, CURLOPT_POST, 1L);
headers = curl_slist_append(headers, "Content-Type: multipart/form-data");
headers = curl_slist_append(headers, "boundary=----------ThIs_Is_tHe_bOUnDary_$");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
mime = curl_mime_init(curl);
for (i = 0; i < num_fields; i++) {
part = curl_mime_addpart(mime);
curl_mime_name(part, fields[i].name);
curl_mime_data(part, fields[i].value, CURL_ZERO_TERMINATED);
}
for (i = 0; i < num_files; i++) {
part = curl_mime_addpart(mime);
curl_mime_name(part, files[i].name);
curl_mime_filename(part, files[i].filename);
curl_mime_type(part, files[i].mime_type);
curl_mime_data(part, files[i].data, files[i].data_len);
}
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
/* set the callback for writting the response into a memory buffer */
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*) &response_body);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
/* perform the conversion */
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "Failed to perform multipart post: %s\n", curl_easy_strerror(res));
} else {
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &result);
if (result != 200) {
/* print details about the Pdfcrowd error */
fprintf(stderr, "Pdfcrowd Error Code: %ld\n", result);
if (response_body.buffer != NULL) {
fprintf(stderr, "Pdfcrowd Error Details: ");
fwrite(response_body.buffer, 1, response_body.size, stderr);
fprintf(stderr, "\n");
}
} else {
/* success, write the result to the output file */
FILE *fp = fopen(output_filename, "wb");
if (!fp) {
fprintf(stderr, "Error opening output file: %s\n", output_filename);
} else {
if(!fwrite(response_body.buffer, response_body.size, 1, fp)) {
fprintf(stderr, "Error writting to file: %s\n", output_filename);
result = -1;
}
fclose(fp);
}
}
}
/* do final cleanup */
curl_easy_cleanup(curl);
curl_mime_free(mime);
curl_slist_free_all(headers);
curl_global_cleanup();
return result;
}
int read_file(const char* filename, FormFile* target) {
FILE* fp = fopen(filename, "rb");
long size;
char* buffer;
size_t bytesRead;
/* determine the file size */
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
/* allocate memory for the file contents */
buffer = (char*) malloc(size);
if (buffer == NULL) {
fprintf(stderr, "Error: could not allocate memory\n");
fclose(fp);
return 1;
}
/* read the file into memory */
bytesRead = fread(buffer, 1, size, fp);
if (bytesRead != (size_t) size) {
fprintf(stderr, "Error: could not read file\n");
free(buffer);
fclose(fp);
return 1;
}
fclose(fp);
target->name = "file";
target->filename = filename;
target->mime_type = "application/octet-stream";
target->data = buffer;
target->data_len = size;
return 0;
}
long convert_url_example() {
FormField* fields = malloc(sizeof(FormField) * 4);
fields[0].name = "input_format";
fields[0].value = "html";
fields[1].name = "output_format";
fields[1].value = "pdf";
fields[2].name = "page_size";
fields[2].value = "letter";
fields[3].name = "url";
fields[3].value = "https://example.com/";
return convert(fields, 4, NULL, 0, "example_url.pdf");
}
long convert_text_example() {
FormField* fields = malloc(sizeof(FormField) * 4);
fields[0].name = "input_format";
fields[0].value = "html";
fields[1].name = "output_format";
fields[1].value = "pdf";
fields[2].name = "page_size";
fields[2].value = "letter";
fields[3].name = "text";
fields[3].value = "<h1>Hello from Pdfcrowd</h1>";
return convert(fields, 4, NULL, 0, "example_text.pdf");
}
long convert_file_example() {
FormFile* files;
FormField* fields = malloc(sizeof(FormField) * 3);
fields[0].name = "input_format";
fields[0].value = "html";
fields[1].name = "output_format";
fields[1].value = "pdf";
fields[2].name = "page_size";
fields[2].value = "letter";
files = malloc(sizeof(FormFile));
if(read_file("your-file.html", &files[0])) {
fprintf(stderr, "Error reading file\n");
return -1;
}
return convert(fields, 3, files, 1, "example_file.pdf");
}
int main() {
if(convert_url_example() != 200) {
fprintf(stderr, "url test failed\n");
return -1;
}
if(convert_text_example() != 200) {
fprintf(stderr, "text test failed\n");
return -1;
}
if(convert_file_example() != 200) {
fprintf(stderr, "file test failed\n");
return -1;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment