1172 lines
25 KiB
C
1172 lines
25 KiB
C
/*
|
|
* Copyright (c) 2020-2022, yzrh <yzrh@noema.org>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "cnki.h"
|
|
#include "iconv.h"
|
|
#include "zlib.h"
|
|
#include "jpeg.h"
|
|
#include "jp2.h"
|
|
#include "pdf.h"
|
|
#include "pdf_cnki.h"
|
|
|
|
static long
|
|
_pdf_dump(cnki_t **param, pdf_object_t **pdf)
|
|
{
|
|
if ((*param)->stat > 1)
|
|
printf("Writing header\n");
|
|
|
|
long cur = 0;
|
|
|
|
if ((*param)->stat > 0)
|
|
cur = ftell((*param)->fp_o);
|
|
|
|
if (pdf_dump_header(pdf, &(*param)->fp_o) != 0) {
|
|
fprintf(stderr, "Header not written\n");
|
|
return -1;
|
|
} else {
|
|
if ((*param)->stat > 0)
|
|
printf("Header %ld byte(s) written\n",
|
|
ftell((*param)->fp_o) - cur);
|
|
}
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Writing object(s)\n");
|
|
|
|
pdf_dump_obj(pdf, &(*param)->fp_o);
|
|
|
|
if ((*param)->stat > 1) {
|
|
printf("\t%8s\t%8s\t%8s\t%12s\t%12s\t%12s\n",
|
|
"address",
|
|
"size",
|
|
"id",
|
|
"object",
|
|
"dictionary",
|
|
"stream");
|
|
|
|
pdf_object_t *ptr = (*pdf)->next;
|
|
while (ptr != NULL) {
|
|
printf("\t%08x\t%8d\t%8d\t%12d\t%12d\t%12d\n",
|
|
ptr->address,
|
|
ptr->size,
|
|
ptr->id,
|
|
ptr->object_size,
|
|
ptr->dictionary_size,
|
|
ptr->stream_size);
|
|
ptr = ptr->next;
|
|
}
|
|
}
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("%d object(s) %ld byte(s) written\n",
|
|
pdf_get_count(pdf),
|
|
ftell((*param)->fp_o));
|
|
|
|
long xref = ftell((*param)->fp_o);
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Writing cross-reference table\n");
|
|
|
|
if (pdf_dump_xref(pdf, &(*param)->fp_o) != 0) {
|
|
if ((*param)->stat > 0)
|
|
printf("Cross-reference table not written\n");
|
|
} else {
|
|
if ((*param)->stat > 0)
|
|
printf("Cross-reference table %ld byte(s) written\n",
|
|
ftell((*param)->fp_o) - xref);
|
|
}
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Writing trailer\n");
|
|
|
|
if ((*param)->stat > 0)
|
|
cur = ftell((*param)->fp_o);
|
|
|
|
if (pdf_dump_trailer(pdf, &(*param)->fp_o, xref) != 0) {
|
|
if ((*param)->stat > 0)
|
|
printf("Trailer not written\n");
|
|
} else {
|
|
if ((*param)->stat > 0)
|
|
printf("Trailer %ld byte(s) written\n",
|
|
ftell((*param)->fp_o) - cur);
|
|
}
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Total %ld byte(s) written\n",
|
|
ftell((*param)->fp_o));
|
|
|
|
return ftell((*param)->fp_o);
|
|
}
|
|
|
|
static int
|
|
_pdf_cnki_outline(cnki_t **param, pdf_object_t **pdf)
|
|
{
|
|
int ret = -1;
|
|
int *ids = NULL;
|
|
|
|
if ((*param)->file_stat->outline > 0) {
|
|
if ((*param)->stat > 1)
|
|
printf("Generating outline object(s)\n\t%8s\n", "id");
|
|
|
|
pdf_get_free_ids(pdf, &ids, (*param)->file_stat->outline + 1);
|
|
int outline = pdf_cnki_outline(pdf, &(*param)->object_outline, &ids);
|
|
|
|
if ((*param)->stat > 1)
|
|
for (int i = 0; i < (*param)->file_stat->outline + 1; i++)
|
|
printf("\t%8d\n", ids[i]);
|
|
|
|
if ((*param)->stat > 0) {
|
|
if (outline != 0)
|
|
printf("No outline information\n");
|
|
else
|
|
printf("Generated %d outline object(s)\n",
|
|
(*param)->file_stat->outline + 1);
|
|
}
|
|
|
|
ret = ids[0];
|
|
free(ids);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
_pdf_obj_sort(cnki_t **param, pdf_object_t **pdf)
|
|
{
|
|
int ret;
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Sorting object(s)\n");
|
|
|
|
ret = pdf_obj_sort(pdf);
|
|
|
|
if ((*param)->stat > 0) {
|
|
if (ret == 0)
|
|
printf("Sorted object(s)\n");
|
|
else
|
|
printf("Object(s) not sorted\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
cnki_pdf(cnki_t **param)
|
|
{
|
|
if (*param == NULL)
|
|
return 1;
|
|
|
|
pdf_object_t *pdf = NULL;
|
|
|
|
if (pdf_obj_create(&pdf) != 0)
|
|
return 1;
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Begin processing PDF\n");
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Loading object(s)\n");
|
|
|
|
if (pdf_load(&pdf, &(*param)->fp_i, (*param)->size_buf) != 0)
|
|
return 1;
|
|
|
|
if ((*param)->stat > 1) {
|
|
printf("\t%8s\t%8s\t%8s\t%12s\t%12s\t%12s\n",
|
|
"address",
|
|
"size",
|
|
"id",
|
|
"object",
|
|
"dictionary",
|
|
"stream");
|
|
|
|
pdf_object_t *ptr = pdf->next;
|
|
while (ptr != NULL) {
|
|
printf("\t%08x\t%8d\t%8d\t%12d\t%12d\t%12d\n",
|
|
ptr->address,
|
|
ptr->size,
|
|
ptr->id,
|
|
ptr->object_size,
|
|
ptr->dictionary_size,
|
|
ptr->stream_size);
|
|
ptr = ptr->next;
|
|
}
|
|
}
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Loaded %d object(s)\n",
|
|
pdf_get_count(&pdf));
|
|
|
|
int dictionary_size;
|
|
char *dictionary;
|
|
|
|
char buf[64];
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Searching for parent object(s)\n");
|
|
|
|
int *parent = NULL;
|
|
pdf_get_parent_id(&pdf, &parent);
|
|
|
|
if (parent[0] == 0)
|
|
return 1;
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Discovered %d parent object(s)\n", parent[0]);
|
|
|
|
int8_t *parent_missing = malloc(parent[0] * sizeof(int8_t));
|
|
|
|
if (parent_missing == NULL)
|
|
return 1;
|
|
|
|
int *kid;
|
|
|
|
for (int i = 1; i <= parent[0]; i++) {
|
|
if ((*param)->stat > 1)
|
|
printf("Searching for object %d\n", parent[i]);
|
|
|
|
kid = NULL;
|
|
pdf_get_kid_id(&pdf, parent[i], &kid);
|
|
|
|
if (kid[0] != 0) {
|
|
if ((*param)->stat > 0)
|
|
printf("Object %d is missing\n", parent[i]);
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Generating object\n");
|
|
|
|
dictionary_size = 64 + 16 * kid[0];
|
|
dictionary = malloc(dictionary_size);
|
|
|
|
if (dictionary == NULL) {
|
|
free(parent);
|
|
free(parent_missing);
|
|
return 1;
|
|
}
|
|
|
|
memset(dictionary, 0, dictionary_size);
|
|
|
|
snprintf(buf, 64,
|
|
"<<\n/Type /Pages\n/Kids [");
|
|
strcat(dictionary, buf);
|
|
|
|
for (int j = 1; j <= kid[0]; j++) {
|
|
snprintf(buf, 64,
|
|
"%d 0 R",
|
|
kid[j]);
|
|
strcat(dictionary, buf);
|
|
|
|
if (j < kid[0])
|
|
strcat(dictionary, " ");
|
|
}
|
|
|
|
snprintf(buf, 64,
|
|
"]\n/Count %d\n>>",
|
|
pdf_get_kid_count(&pdf, parent[i]));
|
|
strcat(dictionary, buf);
|
|
|
|
pdf_obj_prepend(&pdf, parent[i], NULL, dictionary, NULL, 0);
|
|
|
|
parent_missing[i - 1] = 1;
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Generated object for %d child(ren)\n",
|
|
kid[0]);
|
|
|
|
free(dictionary);
|
|
} else {
|
|
parent_missing[i - 1] = 0;
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Object %d exists\n", parent[i]);
|
|
}
|
|
|
|
free(kid);
|
|
}
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Searching for root object\n");
|
|
|
|
dictionary_size = 128;
|
|
dictionary = malloc(dictionary_size);
|
|
|
|
if (dictionary == NULL) {
|
|
free(parent);
|
|
free(parent_missing);
|
|
return 1;
|
|
}
|
|
|
|
memset(dictionary, 0, dictionary_size);
|
|
|
|
int root = 0;
|
|
|
|
int root_kid = 0;
|
|
for (int i = 0; i < parent[0]; i++)
|
|
if (parent_missing[i] == 1)
|
|
root_kid++;
|
|
|
|
if (root_kid > 1) {
|
|
root = pdf_get_free_id(&pdf);
|
|
} else {
|
|
if (root_kid == 0) {
|
|
for (int i = 1; i <= parent[0]; i++)
|
|
if (root == 0 || root < parent[i])
|
|
root = parent[i];
|
|
} else {
|
|
for (int i = 0; i < parent[0]; i++)
|
|
if (parent_missing[i] == 1)
|
|
root = i;
|
|
}
|
|
|
|
if (root == 0)
|
|
root = pdf_get_free_id(&pdf);
|
|
else if ((*param)->stat > 0)
|
|
printf("Root object is %d.\n", root);
|
|
}
|
|
|
|
if (pdf_get_obj(&pdf, root, NULL) != 0) {
|
|
if ((*param)->stat > 0)
|
|
printf("Root object is missing\n");
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Generating root object\n");
|
|
|
|
snprintf(buf, 64,
|
|
"<<\n/Type /Pages\n/Kids ");
|
|
strcat(dictionary, buf);
|
|
|
|
if (parent[0] > 1)
|
|
strcat(dictionary, "[");
|
|
|
|
for (int i = 0, j = 0; i < parent[0]; i++) {
|
|
if (parent_missing[i] == 1) {
|
|
snprintf(buf, 64, "%d 0 R", parent[i + 1]);
|
|
strcat(dictionary, buf);
|
|
|
|
if (++j < root_kid)
|
|
strcat(dictionary, " ");
|
|
}
|
|
}
|
|
|
|
if (parent[0] > 1)
|
|
strcat(dictionary, "]");
|
|
|
|
strcat(dictionary, "\n");
|
|
|
|
snprintf(buf, 64, "/Count %d\n", (*param)->file_stat->page);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, ">>");
|
|
|
|
pdf_obj_prepend(&pdf, root, NULL, dictionary, NULL, 0);
|
|
|
|
memset(dictionary, 0, dictionary_size);
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Generated root object %d.\n",
|
|
root);
|
|
}
|
|
|
|
free(parent);
|
|
free(parent_missing);
|
|
|
|
int outline = _pdf_cnki_outline(param, &pdf);
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Searching for catalog object\n");
|
|
|
|
int catalog = pdf_get_catalog_id(&pdf);
|
|
|
|
if (catalog != 0) {
|
|
if ((*param)->stat > 0)
|
|
printf("Catalog object is %d.\n", catalog);
|
|
} else {
|
|
if ((*param)->stat > 0)
|
|
printf("Catalog object is missing\n");
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Generating catalog object\n");
|
|
|
|
snprintf(buf, 64,
|
|
"<<\n/Type /Catalog\n/Pages %d 0 R\n",
|
|
root);
|
|
strcat(dictionary, buf);
|
|
|
|
if (outline != -1) {
|
|
snprintf(buf, 64,
|
|
"/Outlines %d 0 R\n/PageMode /UseOutlines\n",
|
|
outline);
|
|
strcat(dictionary, buf);
|
|
}
|
|
|
|
strcat(dictionary, ">>");
|
|
|
|
pdf_obj_append(&pdf, 0, NULL, dictionary, NULL, 0);
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Generated catalog object\n");
|
|
}
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Searching for xref object\n");
|
|
|
|
int xref = pdf_get_xref_id(&pdf);
|
|
|
|
if (xref != 0) {
|
|
if ((*param)->stat > 0)
|
|
printf("Xref object is %d.\n", xref);
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Deleting xref object\n");
|
|
|
|
pdf_object_t *tmp;
|
|
|
|
pdf_get_obj(&pdf, xref, &tmp);
|
|
pdf_obj_del(&pdf, xref);
|
|
|
|
tmp->next = NULL;
|
|
pdf_obj_destroy(&tmp);
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Deleted xref object\n");
|
|
} else {
|
|
if ((*param)->stat > 0)
|
|
printf("Xref object is missing\n");
|
|
}
|
|
|
|
free(dictionary);
|
|
|
|
_pdf_obj_sort(param, &pdf);
|
|
|
|
_pdf_dump(param, &pdf);
|
|
|
|
pdf_obj_destroy(&pdf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cnki_pdf_hn(cnki_t **param)
|
|
{
|
|
if (*param == NULL)
|
|
return 1;
|
|
|
|
pdf_object_t *pdf = NULL;
|
|
|
|
if (pdf_obj_create(&pdf) != 0)
|
|
return 1;
|
|
|
|
int font = pdf_get_free_id(&pdf);
|
|
pdf_obj_append(&pdf, font, NULL, "<<\n/Type /Font\n/Subtype /TrueType\n/BaseFont /NotoSansCJKSC\n>>", NULL, 0);
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Generating PDF object(s)\n");
|
|
|
|
int dictionary_size;
|
|
char *dictionary;
|
|
|
|
char buf[64];
|
|
|
|
int cnt = 0;
|
|
int *root_kid = malloc((*param)->file_stat->page * sizeof(int));
|
|
|
|
if (root_kid == NULL)
|
|
return 1;
|
|
|
|
memset(root_kid, 0, (*param)->file_stat->page);
|
|
|
|
object_hn_t *ptr = (*param)->object_hn;
|
|
while (ptr != NULL) {
|
|
/*
|
|
* External object (ptr->image_length) +
|
|
* resource object +
|
|
* content object +
|
|
* page object
|
|
*/
|
|
int *ids = NULL;
|
|
pdf_get_free_ids(&pdf, &ids, ptr->image_length + 3);
|
|
|
|
int bitmap_size;
|
|
char *bitmap;
|
|
|
|
int stream_size;
|
|
char *stream;
|
|
|
|
int *dim;
|
|
|
|
if (ptr->image_length > 0) {
|
|
dim = malloc(2 * ptr->image_length * sizeof(int));
|
|
|
|
if (dim == NULL) {
|
|
free(root_kid);
|
|
free(ids);
|
|
return 1;
|
|
}
|
|
|
|
dictionary_size = 256;
|
|
dictionary = malloc(dictionary_size);
|
|
|
|
if (dictionary == NULL) {
|
|
free(root_kid);
|
|
free(ids);
|
|
free(dim);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int ret;
|
|
int info[3];
|
|
|
|
for (int i = 0; i < ptr->image_length; i++) {
|
|
memset(dictionary, 0, dictionary_size);
|
|
|
|
strcat(dictionary, "<<\n/Type /XObject\n"
|
|
"/Subtype /Image\n");
|
|
|
|
if ((*param)->stat > 2)
|
|
printf("\tProcessing image, page %04d item %d format %d... ",
|
|
ptr->page, i, ptr->image_data[i].format);
|
|
|
|
switch (ptr->image_data[i].format) {
|
|
case JBIG:
|
|
ret = cnki_jbig(&bitmap,
|
|
&bitmap_size,
|
|
&info[0],
|
|
&info[1],
|
|
ptr->image_data[i].image,
|
|
ptr->image_data[i].size);
|
|
|
|
if (ret != 0) {
|
|
dim[i * 2] = 0;
|
|
dim[i * 2 + 1] = 0;
|
|
break;
|
|
}
|
|
|
|
if (strdeflate(&stream, &stream_size,
|
|
bitmap, bitmap_size) != 0) {
|
|
free(root_kid);
|
|
free(ids);
|
|
free(dim);
|
|
free(dictionary);
|
|
return 1;
|
|
}
|
|
|
|
free(bitmap);
|
|
|
|
snprintf(buf, 64, "/Width %d\n/Height %d\n",
|
|
info[0], info[1]);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, "/ColorSpace /DeviceGray\n"
|
|
"/BitsPerComponent 1\n");
|
|
strcat(dictionary, "/Decode [1.0 0.0]\n");
|
|
|
|
snprintf(buf, 64, "/Length %d\n",
|
|
stream_size);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, "/Filter /FlateDecode\n");
|
|
|
|
dim[i * 2] = info[0];
|
|
dim[i * 2 + 1] = info[1];
|
|
break;
|
|
case DCT_0:
|
|
case DCT_1:
|
|
ret = strinfo_jpeg_dim(&info[0],
|
|
&info[1],
|
|
&info[2],
|
|
ptr->image_data[i].image,
|
|
ptr->image_data[i].size);
|
|
|
|
if (ret != 0) {
|
|
dim[i * 2] = 0;
|
|
dim[i * 2 + 1] = 0;
|
|
break;
|
|
}
|
|
|
|
stream_size = ptr->image_data[i].size;
|
|
stream = malloc(stream_size);
|
|
if (stream == NULL) {
|
|
free(root_kid);
|
|
free(ids);
|
|
free(dim);
|
|
free(dictionary);
|
|
return 1;
|
|
}
|
|
memcpy(stream, ptr->image_data[i].image, stream_size);
|
|
|
|
snprintf(buf, 64, "/Width %d\n/Height %d\n",
|
|
info[0], info[1]);
|
|
strcat(dictionary, buf);
|
|
|
|
if (info[2] == 1)
|
|
strcat(dictionary, "/ColorSpace /DeviceGray\n");
|
|
else if (info[2] == 3)
|
|
strcat(dictionary, "/ColorSpace /DeviceRGB\n");
|
|
else
|
|
strcat(dictionary, "/ColorSpace /DeviceCMYK\n");
|
|
|
|
strcat(dictionary, "/BitsPerComponent 8\n");
|
|
|
|
snprintf(buf, 64, "/Length %d\n",
|
|
stream_size);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, "/Filter /DCTDecode\n");
|
|
|
|
dim[i * 2] = info[0];
|
|
dim[i * 2 + 1] = info[1];
|
|
break;
|
|
case JBIG2:
|
|
ret = cnki_jbig2(&bitmap,
|
|
&bitmap_size,
|
|
&info[0],
|
|
&info[1],
|
|
ptr->image_data[i].image,
|
|
ptr->image_data[i].size);
|
|
|
|
if (ret != 0) {
|
|
dim[i * 2] = 0;
|
|
dim[i * 2 + 1] = 0;
|
|
break;
|
|
}
|
|
|
|
if (strdeflate(&stream, &stream_size,
|
|
bitmap, bitmap_size) != 0) {
|
|
free(root_kid);
|
|
free(ids);
|
|
free(dim);
|
|
free(dictionary);
|
|
return 1;
|
|
}
|
|
|
|
free(bitmap);
|
|
|
|
snprintf(buf, 64, "/Width %d\n/Height %d\n",
|
|
info[0], info[1]);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, "/ColorSpace /DeviceGray\n"
|
|
"/BitsPerComponent 1\n");
|
|
strcat(dictionary, "/Decode [1.0 0.0]\n");
|
|
|
|
snprintf(buf, 64, "/Length %d\n",
|
|
stream_size);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, "/Filter /FlateDecode\n");
|
|
|
|
dim[i * 2] = info[0];
|
|
dim[i * 2 + 1] = info[1];
|
|
break;
|
|
case JPX:
|
|
ret = strinfo_jp2_dim(&info[0],
|
|
&info[1],
|
|
ptr->image_data[i].image,
|
|
ptr->image_data[i].size);
|
|
|
|
if (ret != 0) {
|
|
dim[i * 2] = 0;
|
|
dim[i * 2 + 1] = 0;
|
|
break;
|
|
}
|
|
|
|
stream_size = ptr->image_data[i].size;
|
|
stream = malloc(stream_size);
|
|
if (stream == NULL) {
|
|
free(root_kid);
|
|
free(ids);
|
|
free(dim);
|
|
free(dictionary);
|
|
return 1;
|
|
}
|
|
memcpy(stream, ptr->image_data[i].image, stream_size);
|
|
|
|
snprintf(buf, 64, "/Width %d\n/Height %d\n",
|
|
info[0], info[1]);
|
|
strcat(dictionary, buf);
|
|
|
|
snprintf(buf, 64, "/Length %d\n",
|
|
stream_size);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, "/Filter /JPXDecode\n");
|
|
|
|
dim[i * 2] = info[0];
|
|
dim[i * 2 + 1] = info[1];
|
|
break;
|
|
default:
|
|
ret = -1;
|
|
dim[i * 2] = -1;
|
|
dim[i * 2 + 1] = -1;
|
|
break;
|
|
}
|
|
|
|
strcat(dictionary, ">>");
|
|
|
|
if (ret == 0) {
|
|
if ((*param)->stat > 2)
|
|
printf("%6d byte(s), width %4d, height %4d.\n",
|
|
stream_size, info[0], info[1]);
|
|
|
|
pdf_obj_append(&pdf, ids[i],
|
|
NULL, dictionary, stream, stream_size);
|
|
|
|
free(stream);
|
|
} else if (ret == 1) {
|
|
if ((*param)->stat > 2)
|
|
printf("Not extracted.\n");
|
|
|
|
pdf_obj_append(&pdf, ids[i], "null", NULL, NULL, 0);
|
|
} else {
|
|
if ((*param)->stat > 2)
|
|
printf("Unsupported format.\n");
|
|
|
|
pdf_obj_append(&pdf, ids[i], "null", NULL, NULL, 0);
|
|
}
|
|
}
|
|
|
|
if (ptr->image_length > 0)
|
|
free(dictionary);
|
|
|
|
dictionary_size = 128 + 2 * ptr->text_size + 128 * ptr->image_length;
|
|
dictionary = malloc(dictionary_size);
|
|
|
|
if (dictionary == NULL) {
|
|
free(root_kid);
|
|
free(ids);
|
|
free(dim);
|
|
return 1;
|
|
}
|
|
|
|
memset(dictionary, 0, dictionary_size);
|
|
|
|
strcat(dictionary, "<<\n");
|
|
|
|
if (ptr->text_size > 0) {
|
|
snprintf(buf, 64, "/Font <</F0 %d 0 R>>\n", font);
|
|
strcat(dictionary, buf);
|
|
}
|
|
|
|
if (ptr->image_length > 0) {
|
|
strcat(dictionary, "/XObject <<");
|
|
|
|
for (int i = 0; i < ptr->image_length; i++) {
|
|
snprintf(buf, 64, "/Im%d %d 0 R", i, ids[i]);
|
|
strcat(dictionary, buf);
|
|
|
|
if (i < ptr->image_length - 1)
|
|
strcat(dictionary, " ");
|
|
}
|
|
|
|
strcat(dictionary, ">>\n");
|
|
}
|
|
|
|
strcat(dictionary, ">>");
|
|
|
|
pdf_obj_append(&pdf, ids[ptr->image_length], NULL, dictionary, NULL, 0);
|
|
|
|
memset(dictionary, 0, dictionary_size);
|
|
|
|
int conv_size;
|
|
char *conv_dst;
|
|
char conv_src[2];
|
|
char conv_hex[3];
|
|
|
|
if (ptr->text_size > 0) {
|
|
if (strncmp(ptr->text + 8, "COMPRESSTEXT", 12) == 0 ||
|
|
strncmp(ptr->text, "COMPRESSTEXT", 12) == 0) {
|
|
cnki_zlib(&stream, &stream_size, ptr->text, ptr->text_size);
|
|
|
|
free(ptr->text);
|
|
|
|
ptr->text_size = stream_size;
|
|
ptr->text = stream;
|
|
}
|
|
|
|
strcat(dictionary, "BT\n");
|
|
|
|
strcat(dictionary, "/F0 10 Tf\n");
|
|
|
|
for (int i = 0, j = 0; i < ptr->text_size - 1;) {
|
|
switch (((unsigned char) ptr->text[i + 1] << 8) + (unsigned char) ptr->text[i]) {
|
|
case 0x8001:
|
|
if (ptr->address_next > ptr->address)
|
|
strcat(dictionary, "T*\n");
|
|
case 0x8070:
|
|
if (ptr->address_next > ptr->address) {
|
|
i += 4;
|
|
|
|
for (;;) {
|
|
if (i + 3 >= ptr->text_size ||
|
|
(unsigned char) ptr->text[i + 1] == 0x80)
|
|
break;
|
|
|
|
conv_src[0] = ptr->text[i + 3];
|
|
conv_src[1] = ptr->text[i + 2];
|
|
|
|
//snprintf(buf, 64, "%f %f Td\n");
|
|
//strcat(dictionary, buf);
|
|
|
|
conv_size = 6;
|
|
|
|
if (strconv(&conv_dst, "UTF-16BE",
|
|
conv_src, "GB18030", &conv_size) == 0) {
|
|
if (conv_size - 2 > 0) {
|
|
strcat(dictionary, "<feff");
|
|
for (int k = 0; k < conv_size - 2; k++) {
|
|
snprintf(conv_hex, 3,
|
|
"%02x", (unsigned char) conv_dst[k]);
|
|
strcat(dictionary, conv_hex);
|
|
}
|
|
strcat(dictionary, "> Tj\n");
|
|
}
|
|
free(conv_dst);
|
|
}
|
|
|
|
i += 4;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (i + 7 >= ptr->text_size) {
|
|
i += 2;
|
|
break;
|
|
}
|
|
|
|
conv_src[0] = ptr->text[i + 7];
|
|
conv_src[1] = ptr->text[i + 6];
|
|
|
|
//snprintf(buf, 64, "%f %f Td\n");
|
|
//strcat(dictionary, buf);
|
|
|
|
conv_size = 6;
|
|
|
|
if (strconv(&conv_dst, "UTF-16BE",
|
|
conv_src, "GB18030", &conv_size) == 0) {
|
|
if (conv_size - 2 > 0) {
|
|
strcat(dictionary, "<feff");
|
|
for (int k = 0; k < conv_size - 2; k++) {
|
|
snprintf(conv_hex, 3,
|
|
"%02x", (unsigned char) conv_dst[k]);
|
|
strcat(dictionary, conv_hex);
|
|
}
|
|
strcat(dictionary, "> Tj\n");
|
|
}
|
|
free(conv_dst);
|
|
}
|
|
|
|
i += 8;
|
|
break;
|
|
case 0x800a:
|
|
if (i + 27 >= ptr->text_size || j >= ptr->image_length) {
|
|
i += 2;
|
|
|
|
if (j >= ptr->image_length)
|
|
i += 26;
|
|
break;
|
|
}
|
|
|
|
if (ptr->image_length > 0) {
|
|
ptr->image_data[j].x += (unsigned char) ptr->text[i + 5] << 8;
|
|
ptr->image_data[j].x += (unsigned char) ptr->text[i + 4];
|
|
|
|
ptr->image_data[j].y += (unsigned char) ptr->text[i + 7] << 8;
|
|
ptr->image_data[j].y += (unsigned char) ptr->text[i + 6];
|
|
|
|
ptr->image_data[j].w += (unsigned char) ptr->text[i + 9] << 8;
|
|
ptr->image_data[j].w += (unsigned char) ptr->text[i + 8];
|
|
|
|
ptr->image_data[j].h += (unsigned char) ptr->text[i + 11] << 8;
|
|
ptr->image_data[j].h += (unsigned char) ptr->text[i + 10];
|
|
|
|
if ((*param)->stat > 2)
|
|
printf("\tItem %d: origin (%4d, %4d), width %4d, height %4d\n",
|
|
j,
|
|
ptr->image_data[j].x,
|
|
ptr->image_data[j].y,
|
|
ptr->image_data[j].w,
|
|
ptr->image_data[j].h);
|
|
}
|
|
|
|
i += 28;
|
|
|
|
if (j == 0 || ptr->image_data[j].x > 0 || ptr->image_data[j].y > 0)
|
|
j++;
|
|
break;
|
|
default:
|
|
i += 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcat(dictionary, "ET");
|
|
|
|
if (ptr->image_length > 0)
|
|
strcat(dictionary, "\n");
|
|
}
|
|
|
|
if (ptr->image_length > 0) {
|
|
char resize_str[64];
|
|
double resize_x = 1;
|
|
double resize_y = 1;
|
|
|
|
if (ptr->image_data[0].x == 0 && ptr->image_data[0].y == 0 && dim[0] > 0 && dim[1] > 0) {
|
|
/* Scale within bound of A4 paper */
|
|
resize_x = 2381.102 / dim[0];
|
|
resize_y = 3367.559 / dim[1];
|
|
|
|
if (resize_y < resize_x)
|
|
snprintf(resize_str, 64, "%f 0 0 %f 0 0 cm\n",
|
|
resize_y, resize_y);
|
|
else
|
|
snprintf(resize_str, 64, "%f 0 0 %f 0 0 cm\n",
|
|
resize_x, resize_x);
|
|
} else {
|
|
memset(resize_str, 0, 64);
|
|
}
|
|
|
|
for (int i = 0; i < ptr->image_length; i++) {
|
|
if (dim[i * 2] <= 0 || dim[i * 2 + 1] <= 0)
|
|
continue;
|
|
|
|
strcat(dictionary, "q\n");
|
|
|
|
strcat(dictionary, "0.25 0 0 0.25 0 0 cm\n");
|
|
|
|
/* Rotate image */
|
|
if (ptr->image_data[i].format == JBIG || ptr->image_data[i].format == DCT_1) {
|
|
snprintf(buf, 64, "1 0 0 1 0 %d cm\n",
|
|
dim[i * 2 + 1]);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, "1 0 0 -1 0 0 cm\n");
|
|
}
|
|
|
|
/* Translate figure */
|
|
if (ptr->image_data[i].x > 0 || ptr->image_data[i].y > 0) {
|
|
double origin_x = ptr->image_data[i].x * dim[i * 2] / ptr->image_data[i].w;
|
|
double origin_y = ptr->image_data[i].y * dim[i * 2 + 1] / ptr->image_data[i].h;
|
|
|
|
if (ptr->image_data[i].format == JBIG || ptr->image_data[i].format == DCT_1)
|
|
origin_y = -3367.559 + origin_y + dim[i * 2 + 1];
|
|
else
|
|
origin_y = 3367.559 - origin_y - dim[i * 2 + 1];
|
|
|
|
snprintf(buf, 64, "1 0 0 1 %f %f cm\n", origin_x, origin_y);
|
|
strcat(dictionary, buf);
|
|
}
|
|
|
|
snprintf(buf, 64, "%d 0 0 %d 0 0 cm\n",
|
|
dim[i * 2], dim[i * 2 + 1]);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, resize_str);
|
|
|
|
snprintf(buf, 64, "/Im%d Do\n", i);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, "Q");
|
|
|
|
if (i < ptr->image_length - 1)
|
|
strcat(dictionary, "\n");
|
|
}
|
|
|
|
free(dim);
|
|
}
|
|
|
|
if (strlen(dictionary) > 0) {
|
|
if (strdeflate(&stream, &stream_size, dictionary, strlen(dictionary)) != 0) {
|
|
free(root_kid);
|
|
free(ids);
|
|
free(dictionary);
|
|
return 1;
|
|
}
|
|
|
|
memset(dictionary, 0, dictionary_size);
|
|
|
|
strcat(dictionary, "<<\n");
|
|
|
|
snprintf(buf, 64, "/Length %d\n", stream_size);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, "/Filter /FlateDecode\n");
|
|
|
|
strcat(dictionary, ">>");
|
|
|
|
pdf_obj_append(&pdf, ids[ptr->image_length + 1],
|
|
NULL, dictionary, stream, stream_size);
|
|
|
|
free(stream);
|
|
} else {
|
|
pdf_obj_append(&pdf, ids[ptr->image_length + 1],
|
|
"null", NULL, NULL, 0);
|
|
}
|
|
|
|
memset(dictionary, 0, dictionary_size);
|
|
|
|
strcat(dictionary, "<<\n/Type /Page\n");
|
|
|
|
/* A4 paper */
|
|
strcat(dictionary, "/MediaBox [0 0 595.2756 841.8898]\n");
|
|
|
|
snprintf(buf, 64, "/Resources %d 0 R\n", ids[ptr->image_length]);
|
|
strcat(dictionary, buf);
|
|
|
|
snprintf(buf, 64, "/Contents %d 0 R\n", ids[ptr->image_length + 1]);
|
|
strcat(dictionary, buf);
|
|
|
|
/* Add /Parent when we know root */
|
|
pdf_obj_append(&pdf, ids[ptr->image_length + 2], NULL, dictionary, NULL, 0);
|
|
|
|
root_kid[cnt++] = ids[ptr->image_length + 2];
|
|
|
|
free(ids);
|
|
free(dictionary);
|
|
|
|
ptr = ptr->next;
|
|
}
|
|
|
|
if ((*param)->stat > 1) {
|
|
printf("\t%8s\t%12s\t%12s\t%12s\n",
|
|
"id",
|
|
"object",
|
|
"dictionary",
|
|
"stream");
|
|
|
|
pdf_object_t *ptr = pdf->next;
|
|
while (ptr != NULL) {
|
|
printf("\t%8d\t%12d\t%12d\t%12d\n",
|
|
ptr->id,
|
|
ptr->object_size,
|
|
ptr->dictionary_size,
|
|
ptr->stream_size);
|
|
ptr = ptr->next;
|
|
}
|
|
}
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Generated %d object(s)\n",
|
|
pdf_get_count(&pdf));
|
|
|
|
int outline = _pdf_cnki_outline(param, &pdf);
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Generating root object\n");
|
|
|
|
dictionary_size = 64 + 64 * (*param)->file_stat->page;
|
|
dictionary = malloc(dictionary_size);
|
|
|
|
if (dictionary == NULL) {
|
|
free(root_kid);
|
|
return 1;
|
|
}
|
|
|
|
memset(dictionary, 0, dictionary_size);
|
|
|
|
int root = pdf_get_free_id(&pdf);
|
|
|
|
snprintf(buf, 64, "<<\n/Type /Pages\n/Kids ");
|
|
strcat(dictionary, buf);
|
|
|
|
if ((*param)->file_stat->page > 1)
|
|
strcat(dictionary, "[");
|
|
|
|
for (int i = 0; i < (*param)->file_stat->page; i++) {
|
|
snprintf(buf, 64, "%d 0 R", root_kid[i]);
|
|
strcat(dictionary, buf);
|
|
if (i < (*param)->file_stat->page - 1)
|
|
strcat(dictionary, " ");
|
|
}
|
|
|
|
if ((*param)->file_stat->page > 1)
|
|
strcat(dictionary, "]");
|
|
|
|
strcat(dictionary, "\n");
|
|
|
|
snprintf(buf, 64, "/Count %d\n", (*param)->file_stat->page);
|
|
strcat(dictionary, buf);
|
|
|
|
strcat(dictionary, ">>");
|
|
|
|
pdf_obj_prepend(&pdf, root, NULL, dictionary, NULL, 0);
|
|
|
|
free(dictionary);
|
|
|
|
dictionary_size = 256;
|
|
dictionary = malloc(dictionary_size);
|
|
|
|
if (dictionary == NULL) {
|
|
free(root_kid);
|
|
return 1;
|
|
}
|
|
|
|
pdf_object_t *tmp = NULL;
|
|
|
|
/* Add /Parent to page object */
|
|
for (int i = 0; i < (*param)->file_stat->page; i++) {
|
|
if (pdf_get_obj(&pdf, root_kid[i], &tmp) != 0) {
|
|
free(dictionary);
|
|
free(root_kid);
|
|
return 1;
|
|
}
|
|
|
|
memset(dictionary, 0, dictionary_size);
|
|
|
|
memcpy(dictionary, tmp->dictionary, tmp->dictionary_size);
|
|
|
|
snprintf(buf, 64, "/Parent %d 0 R\n>>", root);
|
|
strcat(dictionary, buf);
|
|
|
|
if (pdf_obj_replace(&pdf, root_kid[i], NULL, dictionary, NULL, 0) != 0) {
|
|
free(dictionary);
|
|
free(root_kid);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
free(root_kid);
|
|
|
|
memset(dictionary, 0, dictionary_size);
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Generated root object %d.\n",
|
|
root);
|
|
|
|
if ((*param)->stat > 1)
|
|
printf("Generating catalog object\n");
|
|
|
|
snprintf(buf, 64,
|
|
"<<\n/Type /Catalog\n/Pages %d 0 R\n",
|
|
root);
|
|
strcat(dictionary, buf);
|
|
|
|
if (outline != -1) {
|
|
snprintf(buf, 64,
|
|
"/Outlines %d 0 R\n/PageMode /UseOutlines\n",
|
|
outline);
|
|
strcat(dictionary, buf);
|
|
}
|
|
|
|
strcat(dictionary, ">>");
|
|
|
|
pdf_obj_append(&pdf, 0, NULL, dictionary, NULL, 0);
|
|
|
|
free(dictionary);
|
|
|
|
if ((*param)->stat > 0)
|
|
printf("Generated catalog object\n");
|
|
|
|
_pdf_obj_sort(param, &pdf);
|
|
|
|
_pdf_dump(param, &pdf);
|
|
|
|
pdf_obj_destroy(&pdf);
|
|
|
|
return 0;
|
|
}
|