Skip to content

Instantly share code, notes, and snippets.

@mjm918
Created July 4, 2022 07:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjm918/765facc65ab451b118a0987547095ef8 to your computer and use it in GitHub Desktop.
Save mjm918/765facc65ab451b118a0987547095ef8 to your computer and use it in GitHub Desktop.
Oppo/Vivo Android WebView font bug fixed react-native-html-to-pdf
dependencies {
implementation 'com.itextpdf:itext7-core:7.1.8'
implementation 'com.itextpdf:html2pdf:2.0.1'
}
public class PDFGenManager extends ReactContextBaseJavaModule {
private static final String TAG = "PDFGenManager";
private ReactApplicationContext context;
private File directory;
private String dirPath;
private PDFConverter convertor;
public PDFGenManager(@NonNull ReactApplicationContext reactContext) {
super(reactContext);
this.context = reactContext;
File storage = reactContext.getFilesDir();
File folder = new File(storage.getAbsoluteFile(), "/Downloads/PDFs/");
this.directory = new File(folder.getAbsolutePath());
if(!this.directory.exists()){
Log.i(TAG,"/Downloads/PDFs -- does not exists");
this.directory.mkdirs();
}
this.dirPath = directory.getPath().concat(File.separator);
}
@ReactMethod
public void convert(ReadableMap options, Callback success, Callback failed){
if (!options.hasKey("html") || options.getString("html") == null){
failed.invoke(this.onError("No `html` content found",1404));
return;
}
if (!options.hasKey("fileName") || options.getString("fileName") == null){
failed.invoke(this.onError("No `fileName` found",1405));
return;
}
final String fileName = options.getString("fileName");
String dest = this.dirPath.concat(fileName.concat(".pdf"));
String tmpHtmlDest = this.dirPath.concat(fileName.concat(".html"));
FileOutputStream outputStream = new FileOutputStream(tmpHtmlDest);
outputStream.write(options.getString("html").getBytes(StandardCharsets.UTF_8));
outputStream.flush();
outputStream.close();
ByteArrayOutputStream pdf = createPdf(tmpHtmlDest);
if (pdf != null){
scalePdf(dest, new ByteArrayInputStream(pdf.toByteArray()), 0.7071f);
File tmpFile = new File(tmpHtmlDest);
if (tmpFile.exists()){
tmpFile.delete();
}
success.invoke(onSuccess(dest));
} else {
Log.e(TAG,"ByteArrayOutputStream pdf -- is empty");
failed.invoke(onError("ByteArrayOutputStream pdf -- is empty",1098));
}
} catch (IOException e){
Log.e(TAG,e.getMessage());
failed.invoke(onError(e.getMessage(),1099));
}
}
private WritableMap onError(String message, int code){
WritableMap map = new WritableNativeMap();
map.putString("error",message);
map.putInt("code",code);
return map;
}
private WritableMap onSuccess(String path){
WritableMap map = new WritableNativeMap();
map.putString("filePath",path);
return map;
}
@NonNull
@Override
public String getName() {
return "PDFGenerator";
}
public static ByteArrayOutputStream createPdf(String htmlSrc) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
ConverterProperties converterProperties = new ConverterProperties();
converterProperties.setBaseUri(new File(htmlSrc).getParent());
PdfWriter writer = new PdfWriter(output);
PdfDocument pdfDocument = new PdfDocument(writer);
PdfMerger merger = new PdfMerger(pdfDocument);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfDocument temp = new PdfDocument(new PdfWriter(baos));
temp.setDefaultPageSize(PageSize.A3);
try{
HtmlConverter.convertToPdf(new FileInputStream(htmlSrc), temp, converterProperties);
temp = new PdfDocument(new PdfReader(new ByteArrayInputStream(baos.toByteArray())));
merger.merge(temp, 1, temp.getNumberOfPages());
temp.close();
pdfDocument.close();
return output;
} catch (IOException e){
Log.e(TAG,e.getMessage());
return null;
}
}
public void scalePdf(String dest, ByteArrayInputStream input, float scale) throws IOException {
PdfDocument srcDoc = new PdfDocument(new PdfReader(input));
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
ScaleDownEventHandler eventHandler = new ScaleDownEventHandler(scale);
int n = srcDoc.getNumberOfPages();
pdfDoc.addEventHandler(PdfDocumentEvent.START_PAGE, eventHandler);
PdfCanvas canvas;
PdfFormXObject page;
for (int p = 1; p <= n; p++) {
eventHandler.setPageDict(srcDoc.getPage(p).getPdfObject());
canvas = new PdfCanvas(pdfDoc.addNewPage());
page = srcDoc.getPage(p).copyAsFormXObject(pdfDoc);
canvas.addXObject(page, scale, 0f, 0f, scale, 0f, 0f);
}
pdfDoc.close();
srcDoc.close();
}
protected class ScaleDownEventHandler implements IEventHandler {
protected float scale = 1;
protected PdfDictionary pageDict;
public ScaleDownEventHandler(float scale) {
this.scale = scale;
}
public void setPageDict(PdfDictionary pageDict) {
this.pageDict = pageDict;
}
@Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfPage page = docEvent.getPage();
page.put(PdfName.Rotate, pageDict.getAsNumber(PdfName.Rotate));
scaleDown(page, pageDict, PdfName.MediaBox, scale);
scaleDown(page, pageDict, PdfName.CropBox, scale);
}
protected void scaleDown(PdfPage destPage, PdfDictionary pageDictSrc, PdfName box, float scale) {
PdfArray original = pageDictSrc.getAsArray(box);
if (original != null) {
float width = original.getAsNumber(2).floatValue() - original.getAsNumber(0).floatValue();
float height = original.getAsNumber(3).floatValue() - original.getAsNumber(1).floatValue();
PdfArray result = new PdfArray();
result.add(new PdfNumber(0));
result.add(new PdfNumber(0));
result.add(new PdfNumber(width * scale));
result.add(new PdfNumber(height * scale));
destPage.put(box, result);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment