2014-11-09 3 views
15

У меня возникли проблемы с работой PDF-печати на Android. То, что я пытаюсь сделать, это отобразить некоторый HTML в WebView, затем нарисовать содержимое WebView на холсте PDF и, наконец, записать PDF в файл. Проблема, с которой я сталкиваюсь, заключается в том, что когда я рисую на холст PDF, содержимое обрезается, хотя остается много холста. Я попытался изменить размер холста, используя .clipRect(Rect rect, Op op), и этот вид работал, но не так хорошо, как мне бы хотелось.Android - рисование на холсте PDF от WebView

Я также не знаю, как я могу надежно перевести измерения HTML-изображений в PDF PostScript 1/72-дюймовые измерения.

Вот код, я использую:

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    WebView wv = (WebView) this.findViewById(R.id.webView1); 

    wv.loadUrl("file:///android_asset/temp.html");   
} 

public void button1onClick(View v) 
{ 
    //Create PDF document 
    PdfDocument doc = new PdfDocument(); 

    //Create A4 sized PDF page 
    PageInfo pageInfo = new PageInfo.Builder(595,842,1).create(); 

    Page page = doc.startPage(pageInfo); 

    WebView wv = (WebView) this.findViewById(R.id.webView1); 

    page.getCanvas().setDensity(200); 

    //Draw the webview to the canvas 
    wv.draw(page.getCanvas()); 

    doc.finishPage(page); 

    try 
    { 
     //Create the PDF file 
     File root = Environment.getExternalStorageDirectory();   
     File file = new File(root,"webview.pdf"); 
     FileOutputStream out = new FileOutputStream(file); 
     doc.writeTo(out); 
     out.close(); 
     doc.close(); 

     //Open the PDF 
     Intent intent = new Intent(Intent.ACTION_VIEW); 
     intent.setDataAndType(Uri.fromFile(file), "application/pdf"); 
     intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); 
     startActivity(intent);   
    } 
    catch(Exception e) 
    { 
     throw new RuntimeException("Error generating file", e); 
    } 
} 

В основном программа просто загружает файл temp.html в WebView и делает мне кнопку, что я могу использовать для создания PDF.

temp.html файл выглядит следующим образом:

<html> 
<head> 
    <style> 
     div.border 
     { 
      width:600px; 
      height:800px; 
      border:1px solid black; 
     } 
    </style> 
</head> 
<body> 
    <div class="border"></div> 
</body> 

И вот результат с добавленным вручную черной рамкой, чтобы показать масштаб:

enter image description here

Я действительно оцените некоторые советы о том, как надежно конвертировать HTML в PDF на Android без использования библиотек, требующих лицензии для коммерческого использования.

+0

попробуйте использовать https://developer.android.com/reference/android/print/pdf/ PrintedPdfDocument.html. Я не уверен, хотя –

ответ

1

В основном для меня все сводится к Hyper-Link и внешней поддержке .css (каскадные таблицы стилей) для (X) HTML-файлов в PDF (классы).

 div border is not supported on android in anyway I have found in free to use code. 

div цвет да, ну и что. PdfDocument. (API 19 или выше). может быть лучше lib itextg (API16 может быть меньше) (подмножество itext опускает рамки андроида без разрешенных классов). (использует класс XMLWorkerHelper) (граница div = нет), но td == yes yippi! (пограничный элемент поддерживается в формате pdf). Время для itextg, может быть. Соответствие: http://demo.itextsupport.com/xmlworker/itextdoc/CSS-conformance-list.htm Pretty pathetic. Продолжить ... Не уверен, что вы хотите, если это просто граница, я могу сделать это на элементе td. Довольно уверен, что вы хотите больше. Продолжить ... Я могу сделать внешний .css файл, прочитанный с поддерживаемыми элементами (см. Ссылку), довольно круто. (летающая тарелка ... не летает для меня "JAVA Library" НЕ поддерживается андроидом).

Так что такого рода вещи:

public boolean createPDF(String htmlText, String absoluteFilePath) throws DocumentException, CssResolverException 
    { 
     try 
     { 
      // step 1 new doc 
      Document document = new Document(); 

      // step 2 create PdfWriter 

      PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(absoluteFilePath)); 

      writer.setInitialLeading(12.5f); 

      // step 3 open doc 
      document.open(); 
      document.add(new Chunk("")); // 

      HtmlPipelineContext htmlContext = new HtmlPipelineContext(null); 

      htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory()); 
      CSSResolver cssResolver = null; 
     if(true) 
     { 
      // step 4 CSS 
      cssResolver = new StyleAttrCSSResolver(); 
      java.io.InputStream csspathtest = null; 
      try { 
       csspathtest = getResources().getAssets().open("itextweb.css"); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      CssFile cssfiletest = XMLWorkerHelper.getCSS(csspathtest); 
      cssResolver.addCss(cssfiletest); 
      Log.i("cssfiletest",cssfiletest.toString()); 
      } 
     else 
     { 
      cssResolver = XMLWorkerHelper.getInstance().getDefaultCssResolver(false); 
      cssResolver.addCss("td {border-right: white .1px solid;}", true); 
      cssResolver.addCss("div {border: green 2px solid;}", true); 
     }   

      Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(htmlContext, new PdfWriterPipeline(document, writer))); 

      XMLWorker worker1 = new XMLWorker(pipeline, true); 
      XMLParser p = new XMLParser(worker1); 
      ByteArrayInputStream inputRawHTML = new ByteArrayInputStream(htmlText.getBytes()); 

      Tidy tidy = new Tidy(); // obtain a new Tidy instance 
      tidy.setXHTML(true); // set desired config options using tidy setters 
      ByteArrayOutputStream output = new ByteArrayOutputStream(); 
//   tidy.setCharEncoding(Configuration.UTF8); 
      tidy.parse(inputRawHTML, output); 
      String preparedText = output.toString("UTF-8"); 

      Log.i("CHECKING", "JTidy Out: " + preparedText); 

      ByteArrayInputStream inputPREP = new ByteArrayInputStream(preparedText.getBytes()); 

      // step 5 parse html 
      p.parse(inputPREP); 

Таким образом, некоторые изображения:

для HTML:

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html > 
<head> 
    <title>My first web page</title> 

    <LINK REL=StyleSheet HREF="itextweb.css" TYPE="text/css" MEDIA=screen> 
</head> 
<body> 
<!-- The <div> tag enables you to group sections of HTML elements together and format them with CSS.--> 
    <div> 
    <p>helloworld with green border if style worked</p> 
    </div> 

     <div> 
     <h1>helloworld with green border if style worked</h1> 
    </div> 
<div style="border: 3px yellow solid"> 
<p>"SHOULD be red text if p style worked, else yellow border from div style" </p> 
other text div yellow inline border 
</div> 
<div style="color: red">red text if div style worked</div> 


    <h2>unsorted list</h2> 
    <ul> 
     <li>To learn HTML</li> 
     <li>To show off</li> 
    </ul> 
<table> 
    <tr> 
     <td>Row 1, cell 1</td> 
     <td>Row 1, cell 2</td> 
     <td>Row 1, cell 3</td> 
    </tr> 
</table> 
<textarea rows="5" cols="20">A big load of text</textarea> 
<a href="http://www.htmldog.com">blue HTML Dog link</a> 
</body> 
</html> 

input html in browseroutput pdf file> Примечание элементы TD имеют границ!

+1

Если это то, что вы хотите, напишите мне для получения дополнительной информации, в противном случае удачи, сложной проблемы (не поддерживаемой, пока что ни в чем не найденной), вы были весьма специфичны для DIV и границы. –

2

Основная информация: Не изменяйте плотность (она должна быть установлена ​​на вашем устройстве, возможно, на среднем 160 dpi) вместо этого используйте масштаб. Если вам просто нужны растровые изображения вашей HTML-страницы в вашем PDF-файле (без функции гиперссылки), это работает. Это то, что ваш код генерации, с помощью следующего кода:

//Create PDF document 

     PdfDocument doc = new PdfDocument(); 

     //Create A4 sized PDF page 
     int my_width = 595; 
     int my_height = 842; 

     PageInfo pageInfo = new PageInfo.Builder(my_width,my_height,1).create(); 
//  PageInfo pageInfo = new PageInfo.Builder(650,850,1).create(); 

     Page page = doc.startPage(pageInfo); 

     WebView wv = (WebView) this.findViewById(R.id.webView1); 

     Canvas canvas = page.getCanvas(); 
     WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); 
     final DisplayMetrics displayMetrics = new DisplayMetrics(); 
     wm.getDefaultDisplay().getMetrics(displayMetrics); 
     int height = displayMetrics.heightPixels; 
     int width = displayMetrics.widthPixels; 
     float density = displayMetrics.density; 
     int wvWidth = wv.getWidth(); 
     int wvHeight= wv.getHeight(); 
     float wvScaleX= wv.getScaleX(); 
     float wvScaleY= wv.getScaleY(); 

//  canvas.setDensity(100);//200 Bitmap.DENSITY_NONE 
     int cdensity = canvas.getDensity(); 
     float scaleWidth = (float)width/(float)my_width; 
     float scaleHeight = (float)height/(float)my_height; 
     canvas.scale(scaleWidth, scaleHeight); 
     Log.e("button1onClick","canvas width:" + canvas.getHeight() + " canvas height:" + canvas.getWidth()); 
     Log.e("button1onClick","metrics width:" + width + " metrics height:" + height + "metrics density:" + density); 
     Log.e("button1onClick"," wvWidth:" + wvWidth + " wvHeight:" + wvHeight); 
     Log.e("button1onClick"," scaleWidth: " + scaleWidth + 
       " scaleHeight:" + scaleHeight +" cdensity:" + cdensity); 
     Paint paint = new Paint(); 
//  paint.setStyle(Style.FILL); 
     paint.setColor(Color.RED); 
     paint.setStyle(Paint.Style.STROKE); 
     paint.setStrokeWidth(1); 

     //Draw the webview to the canvas 
     wv.draw(canvas); 
     canvas.scale(1f, 1f); 
     canvas.drawRect(0, 0, canvas.getWidth()-1, canvas.getHeight()-1, paint); 
     canvas.drawText("Direct drawn Red Rectangle to fill page canvas 0, 0," + 
       canvas.getWidth() + "," + canvas.getHeight(), 100, 100, paint); 

     doc.finishPage(page); 

webview.pdf

Это хорошо работает (Hyper-ссылки не работают, конечно). Более сложный пример: more complex example

1

Здесь он становится интересным. насчет тех трудно закодированных значений для холста: -

PageInfo pageInfo = new PageInfo.Builder(595,842,1).create(); 

Вам нужна ширина и высота в WebView СОДЕРЖАНИЕ, после вы загрузили свой HTML. ДА, но нет getContentWidth метод (только значение порта просмотра), AND getContentHeight() неточно!

Ответ: подклассу WebView:

/* 
    Jon Goodwin 
*/ 
package com.example.html2pdf;//your package 

import android.content.Context; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.webkit.WebView; 

class CustomWebView extends WebView 
{ 
    public int rawContentWidth = 0;       //unneeded 
    public int rawContentHeight = 0;       //unneeded 
    Context mContext   = null;      //unneeded 

    public CustomWebView(Context context)      //unused constructor 
    { 
     super(context); 
     mContext = this.getContext(); 
    } 

    public CustomWebView(Context context, AttributeSet attrs) //inflate constructor 
    { 
     super(context,attrs); 
     mContext = context; 
    } 

    public int getContentWidth() 
    { 
     int ret = super.computeHorizontalScrollRange();//working after load of page 
     rawContentWidth = ret; 
     return ret; 
    } 

    public int getContentHeight() 
    { 
     int ret = super.computeVerticalScrollRange(); //working after load of page 
     rawContentHeight = ret; 
     return ret; 
    } 

    public void onPageFinished(WebView page, String url) 
    { 
     //never gets called, don't know why, but getContentHeight & getContentWidth function after load of page 
     rawContentWidth = ((CustomWebView) page).getContentWidth(); 
     rawContentHeight = ((CustomWebView) page).getContentHeight(); 

     Log.e("CustomWebView:onPageFinished","ContentWidth: " + ((CustomWebView) page).getContentWidth()); 
     Log.e("CustomWebView:onPageFinished","ContentHeight: " + ((CustomWebView) page).getContentHeight()); 
    } 

//========= 
}//class 
//========= 

В моем модифицированном коде (в другой ответ) изменения:

private CustomWebView wv; 
    wv = (CustomWebView) this.findViewById(R.id.webView1); 

    int my_width = wv.getContentWidth(); 
    int my_height = wv.getContentHeight(); 

и изменить запись класса макета из WebView в ком. example.html2pdf.CustomWebView.

то вам хорошо идти!

0

У меня была та же проблема.

Я решил использовать этот простой трюк.

Только комплект MediaSize до PrintAttributes.MediaSize.ISO_A1.

Недостатком этого решения является формат pdf: даже один-страничный-pdf с простым текстом имеет примерно 5 МБ.

Работа фрагмент кода (генерирует PDF из вида и экспортировать его в файл):

@TargetApi(19) 
private void generatePdf() { 
    PrintAttributes.Builder builder = new PrintAttributes.Builder(); 
    builder.setColorMode(PrintAttributes.COLOR_MODE_COLOR); 
    builder.setMediaSize(PrintAttributes.MediaSize.ISO_A1); // or ISO_A0 
    builder.setMinMargins(PrintAttributes.Margins.NO_MARGINS); 
    builder.setResolution(new PrintAttributes.Resolution("1", "label", 300, 300)); 
    PrintedPdfDocument document = new PrintedPdfDocument(this, builder.build()); 
    PdfDocument.Page page = document.startPage(1); 
    View content = yourView; 
    content.draw(page.getCanvas()); 
    document.finishPage(page); 
    try { 
     File file = new File(getExternalFilesDir(null).getAbsolutePath(), "document.pdf"); 
     document.writeTo(new FileOutputStream(file)); 
    } catch (IOException e) { 
     Log.e("cannot generate pdf", e); 
    } 
    document.close(); 
} 
Смежные вопросы