HTML zu Jpeg konvertieren

  • Antworten:8
  • Bentwortet
Barbaric Chicken
  • Forum-Beiträge: 66

27.11.2013, 12:13:39 via Website

Hallo,

folgendes:

Ich habe eine Liste mit Einträgen. Diese Einträge haben ein eigenes Layout (Blauer header mit Titel usw).

Jetzt soll es möglich sein, diese Liste auszudrucken. Dafür wollte ich zuerst ein html file von der Liste erstellen (Damit formatierung usw bestehen bleibt) und dieses dann zu PDF umwandeln.
Jetzt ist Android mit PDF nicht soo freundlich, vor allem wenn das Budget ca. 0€ beträgt, also dachte ich, ich könnte es ja auch in ein JPEG umwandeln, ist eigentlich egal.

Ich habe über google schon einige Ansätze gefunden die im Grunde immer so aussahen:
1WebView wv = new WebView(this);
2wv.loadData("<html><body><p>Hello World</p></body></html>");
3Picture p = wv.capturePicture();

Mal komplizierte mal weniger Kompliziert.

Wenn ich das versuche erhalte ich aber an der Stelle, an der ich das Picture zur Bitmap Klasse umwandeln will ein Problem weil p breite und höhe von 0 hat und man mit der Größe kein Bitmap erstellen kann.
Wenn ich die WebView meiner View adde und den String lade, dann funktioniert das auch er wird dargestellt.

Ich vermute die Größe von 0 kommt daher, da die WebView, dadurch das sie nicht zur View geadded werden soll, keine eigene Größe hat und somit auch nicht darstellt! Nur wie bekomme ich es dann hin?

Viele Grüße


Edit:
Hier mal noch mein Code:_
1WebView webView = new WebView(getActivity());
2 webView.loadData(generateHTMLString(), "text/html", "UTF-8");
3 Picture p = webView.capturePicture();
4 PictureDrawable drawable = new PictureDrawable(p);
5 Bitmap bmp = Bitmap.createBitmap(400, 200, Config.ARGB_8888);
6 Canvas c = new Canvas(bmp);
7 c.drawPicture(drawable.getPicture());
8
9 File bitmapFile = new File(getActivity().getExternalFilesDir(null)+"/test.jpeg");
10 try {
11 bitmapFile.createNewFile();
12 OutputStream out = new FileOutputStream(bitmapFile);
13 bmp.compress(Bitmap.CompressFormat.JPEG,100,out);
14 out.close();
15 Toast.makeText(getActivity(), "DONE :)", Toast.LENGTH_LONG).show();
16 } catch (IOException e) {
17 // TODO Auto-generated catch block
18 e.printStackTrace();
19 }

Edit²:
Ich bin übrigens auch für ganz andere Lösungsansätze offen, also statt html zu pdf oder jpeg...keine Ahnung Blank text in eine table und dann als png oder so xD

— geändert am 27.11.2013, 15:53:35

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

27.11.2013, 20:43:17 via App

Gibt es nicht online html to pdf oder html to picture?
Dann könntest du nämlich einfach ein post aud die seite machen und bekämst das bild zurück.
Ps.. zu normale drucker beutzen das postscript format
Vlt. kannst du die html auch gleich in dieses umwandeln

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Barbaric Chicken
  • Forum-Beiträge: 66

28.11.2013, 11:12:20 via Website

Hallo,

Danke für deine Antwort.

Sicher gibt es online html to pdf aber ich wollte eine lokale Lösung, da die App später hauptsächlich von unterwegs bedient wird und man sich nicht immer auf eine gute Verbindung verlassen kann.

Postscript kommt nicht in Frage, da die selbe Datei auch per E-Mail und von anderen unterstützenden Anwendungen teilbar sein soll. So brauche ich dann nur eine Datei zu erzeugen.

Seit API Level 19 (KitKat 4.4) gibt es unter Android das Printer Framework. Mit dessen Hilfe ist es auch möglich PDF zu erzeugen. (Eher dürftig aber es geht). stackoverflow.com/questions/2499960/how-to-create-pdfs-in-android-sdk

Also versuche ich mich Momentan daran.(Für den Moment reicht der Support nur für 4.4 Geräte)
Nun habe ich mir ein Layoutfile erstellt, dass bis auf eine Kleinigkeit meiner Tabellenreihe entspricht.
Ich inflate das Layout als View und setze alle Werte bei den Childelementen. Am Ende zeichne ich dann die View per draw auf die erste Seite des PDF's. Wenn ich das PDF dann öffnen möchte kommt immer die Datei sei beschädigt und daher nicht öffbar.

Ich habe auch versucht die WebView in das PDF zu zeichnen. Das geht, nur leider stimmen die Maße einfach nicht Oo.
Zum Beispiel: Ich habe im html angegeben, dass der Rahmen 250 Pixel breit ist. Im PDF nimmt ein Rahmen dann aber die komplette (DIN A4) Seite ein... das kann ja nicht sein. Auflösung habe ich auf 300 dpi gestellt.
Die Datei wird aber auch in der WebView schon seltsam angezeigt, weil auch hier die eigentlich 250 Pixel breiten Fenster gut 3/4 meiner WebView einnehmen bei einer Display Breite von 768 Pixeln. Ich vermute die WebView zoomt irgendwie ran es lässt sich aber nichts einstellen, was das beheben würde. Habe da schon einiges probiert.

Hier mal der Code vielleicht weiß einer Rat. Ansonsten wäre dieses Framework nämlich ein willkommener Gast :)

Versuch, mit View:
1View v = getLayoutInflater().inflate(R.layout.pdf_table, null);
2 TextView name = (TextView)v.findViewById(R.id.nameValue);
3 TextView formeclair = (TextView)v.findViewById(R.id.formeclairValue);
4 TextView dosageu = (TextView)v.findViewById(R.id.dosageuValue);
5 TextView dosageup1 = (TextView)v.findViewById(R.id.dosageup1Value);
6 TextView taking = (TextView)v.findViewById(R.id.takingValue);
7 TextView duration = (TextView)v.findViewById(R.id.durationValue);
8 TextView enddate = (TextView)v.findViewById(R.id.enddateValue);
9
10 ArrayList<TakingMedicament>tm = TakingMedicamentsDB.getAllTakingMedicaments();
11 name.setText(tm.get(0).getName());
12 formeclair.setText(tm.get(0).getFormeclair());
13 dosageu.setText(tm.get(0).getDosageu());
14 dosageup1.setText(tm.get(0).getDosageup1());
15 taking.setText(tm.get(0).getTaking());
16 duration.setText(tm.get(0).getDuration());
17 enddate.setText(tm.get(0).getEnddate());
18
19 PrintAttributes.Builder attrsBuilder = new PrintAttributes.Builder();
20 attrsBuilder.setResolution(new PrintAttributes.Resolution("1", "Test", 300, 300));
21 attrsBuilder.setMediaSize(PrintAttributes.MediaSize.ISO_A4);
22 attrsBuilder.setMinMargins(new PrintAttributes.Margins(0,0,0,0));
23 PrintedPdfDocument document = new PrintedPdfDocument(CreatePDFActivity.this, attrsBuilder.build());
24 Page page = document.startPage(0);
25
26 Canvas canvas = page.getCanvas();
27 v.draw(canvas);
28
29 document.finishPage(page);
30 File pdf = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)+"/test.pdf");
31 if(pdf.exists())
32 pdf.delete();
33
34 try {
35 pdf.createNewFile();
36 document.writeTo(new FileOutputStream(pdf));
37 } catch (IOException e) {
38 // TODO Auto-generated catch block
39 e.printStackTrace();
40 }
41
42 document.close();

Versuch mit WebView:
1WebView aWebView = new WebView(getActivity());
2 aWebView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
3
4 aWebView.setPictureListener(new WebView.PictureListener()
5 {
6
7 @Override
8 @Deprecated
9 public void onNewPicture(WebView view, Picture picture)
10 {
11 if(picture != null)
12 {
13 PrintAttributes.Builder attrsBuilder = new PrintAttributes.Builder();
14 attrsBuilder.setResolution(new PrintAttributes.Resolution("1", "Test", 300, 300));
15 attrsBuilder.setMediaSize(PrintAttributes.MediaSize.ISO_A4);
16 attrsBuilder.setMinMargins(new PrintAttributes.Margins(0,0,0,0));
17 PrintedPdfDocument document = new PrintedPdfDocument(getActivity(), attrsBuilder.build());
18 Page page = document.startPage(0);
19
20 Canvas canvas = page.getCanvas();
21 view.draw(canvas);
22
23 document.finishPage(page);
24 File pdf = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)+"/test.pdf");
25 if(pdf.exists())
26 pdf.delete();
27
28 try {
29 pdf.createNewFile();
30 document.writeTo(new FileOutputStream(pdf));
31 } catch (IOException e) {
32 // TODO Auto-generated catch block
33 e.printStackTrace();
34 }
35
36 document.close();
37
38 }
39
40 }
41 });
42 aWebView.loadData(generateHTMLString(), "text/html", "UTF-8");

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

28.11.2013, 13:44:49 via App

Benutz doch clientseitig javascript html to pdf
Damit sollte es gehen.
http://code.google.com/p/jspdf/
Den code einfach in einer WebView ausführen

— geändert am 28.11.2013, 13:45:21

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Barbaric Chicken
  • Forum-Beiträge: 66

28.11.2013, 13:59:54 via Website

Ohje,

generell eine sehr gute Idee, so simple wie einfach!

Aber ich habe von Javascript absolut nicht den hauch einer Ahnung. Ich weiß nicht wie ich bibliotheken in javscript verwende oder ein skript ohne button klick ausführe.
Es würde also lange dauern mich da jetzt einzuarbeiten.

Hast du ein paar Zeilen die das verwenden?

Gruß

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

28.11.2013, 14:13:39 via App

Ne parat nicht. aber icb kann im lauf des Tages noch ein paar zeilen schreiben und testen.
Dann kann kann ich es auch posten.
Habe gerade nicht so viel Zeit dafür..

— geändert am 28.11.2013, 14:14:03

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Barbaric Chicken
  • Forum-Beiträge: 66

28.11.2013, 14:18:04 via Website

Okay, das würde mir wahnsinnig helfen.
Wie du Zeit findest nur kein Stress^^

Dankeschön.

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

28.11.2013, 18:38:09 via Website

OK
Ich habe es getestet leider funktionier es auf meinen Computer nicht.
Irgendwie komisch.
VLT. Findest du noch eine andere lösung dafür

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Barbaric Chicken
  • Forum-Beiträge: 66

29.11.2013, 15:14:13 via Website

Hallo habe es nun so gemacht.

ListView zu PDF unter Android 4.4

Ich habe mir eine eigene Klasse geschrieben, die von View ableitet und in der onDraw Methode alle notwendigen Dinge zeichnet, um eine Zeile aus der Liste zu imitieren. Auch Texte usw. habe ich per Canvas gezeichnet. Hier mal die Klasse:

1public class PrintWindow extends View
2{
3 private String name,formeclair,dosageu,dosageup1,taking,duration,enddate;
4 private Paint painter;
5 private int x,y;
6
7 public PrintWindow(Context c)
8 {
9 super(c);
10 }
11
12 public PrintWindow(Context context,String name,String formeclair,String dosageu,String dosageup1,String taking, String duration, String enddate,int x, int y)
13 {
14 super(context);
15 this.name = name;
16 this.formeclair = formeclair;
17 this.dosageu = dosageu;
18 this.dosageup1 = dosageup1;
19 this.taking = taking;
20 this.duration = duration;
21 this.enddate = enddate;
22 this.x = x;
23 this.y = y;
24
25 this.painter = new Paint();
26 painter.setStyle(Style.STROKE);
27 painter.setColor(Color.rgb(49, 85, 210));
28 painter.setStrokeWidth(4);
29 }
30
31 @Override
32 protected void onDraw(Canvas canvas)
33 {
34 super.onDraw(canvas);
35 //Draw Border
36 canvas.drawRect(0+x, 0+y, 285+x, 150+y, painter);
37
38 //Draw Header bg
39 painter.setStyle(Style.FILL);
40 canvas.drawRect(2+x, 2+y, 283+x, 25+y, painter);
41
42 //Draw gray bg
43 painter.setColor(Color.rgb(235, 235, 235));
44 canvas.drawRect(3+x, 25+y, 283+x, 150+y, painter);
45
46 //Draw white boxes
47 painter.setColor(Color.rgb(255, 255, 255));
48 canvas.drawRect(15+x, 35+y, 268+x, 80+y, painter);
49 canvas.drawRect(15+x, 90+y, 268+x, 135+y, painter);
50
51 //Draw text with white color (the values) the header,
52
53 painter.setTextSize(16);
54 if(name.length()>34)
55 painter.setTextSize(14);
56 canvas.drawText(name, 10+x,18+y, painter);
57
58 //Draw text with blue color (the names)
59 painter.setColor(Color.rgb(49, 85, 210));
60 painter.setTextSize(10);
61 canvas.drawText("Formeclair:", 20+x, 45+y, painter);
62 canvas.drawText("Dosageu:", 20+x, 60+y, painter);
63 canvas.drawText("DosageuP1:", 20+x, 75+y, painter);
64
65 canvas.drawText("Taking:", 20+x, 100+y, painter);
66 canvas.drawText("Duration:", 20+x, 115+y, painter);
67 canvas.drawText("Enddate:", 20+x, 130+y, painter);
68
69 //Draw text with black color (the values)
70 painter.setColor(Color.rgb(0,0,0));
71 painter.setTextSize(10);
72 canvas.drawText(formeclair, 150+x, 45+y, painter);
73 canvas.drawText(dosageu, 150+x, 60+y, painter);
74 canvas.drawText(dosageup1, 150+x, 75+y, painter);
75
76 canvas.drawText(taking, 150+x, 100+y, painter);
77 canvas.drawText(duration, 150+x, 115+y, painter);
78 canvas.drawText(enddate, 150+x, 130+y, painter);
79 }
80
81 @Override
82 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
83 {
84
85 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
86 setMeasuredDimension(500, 280);
87 }

Warum war das nötig?
Mein erste Ansatz war das ganze mit einer LayouFile zu machen. Jedoch stürzte alles ab wenn ich versuchte dieses dann in das PDF zu zeichnen. Warum konnte ich einfach nicht herausfinden.
Dann war meine Idee, einfach die Liste wie sie ist in das PDF zu zeichnen. Leider zeigt eine Liste immer nur die Elemente an die auch sichtbar sind, alle anderen werden erst dann geladen, wenn sie benötigt werden. Das führte also dazu, dass die ersten 3 Elemente in die PDF geschrieben wurde, danach aber für 6 Elemente Schwarz kam.

Anschliesend iteriere ich über den Adapter der Liste, bzw. in meinem Fall kamen die Daten aus einer Datenbank also bin ich direkt über die Datenbank gegangen. Für jedes Element im Adapter/Datenbank erzeuge ich ein neues Objekt der obigen Klasse und passe die Koordinaten an ( Die koordinaten passen nur im PDF, lässt man sich das in einer Activity anzeigen ist alles verloren xD)
Mit den neuen Funktionen die Android 4.4 zur Verfügung stellt zeichne ich dann die View in das PDF Dokument.
Der Code dazu sieht so aus:

1private PrintedPdfDocument generatePDF()
2 {
3 //First get all takings
4 ArrayList<databaseObject>tm = Database.getAllObjects();
5 //Start at page 0
6 int pageNumber = 0;
7
8 //Set config for pdf file
9 PrintAttributes.Builder attrsBuilder = new PrintAttributes.Builder();
10 attrsBuilder.setResolution(new PrintAttributes.Resolution("1", "Test", 300, 300));
11 attrsBuilder.setMediaSize(PrintAttributes.MediaSize.ISO_A4);
12 attrsBuilder.setMinMargins(new PrintAttributes.Margins(100,100,100,100));
13
14 //Create a new document
15 PrintedPdfDocument document = new PrintedPdfDocument(getActivity(), attrsBuilder.build());
16 //Get first page
17 Page page = document.startPage(pageNumber);
18 int x = 0;
19 int y = 0;
20 for(int i=0;i<tm.size();i++)
21 {
22 //With the current configuration exactly 10 items fit into one page of the pdf.
23 //That means after 10 items we have to start a new page!
24 if(i!=0 && i%10 == 0)
25 {
26 x=0;
27 y=0;
28 pageNumber++;
29 document.finishPage(page);
30 page = document.startPage(pageNumber);
31 }
32
33 //Draw the current item into the pdf with the help of PrintWindow class
34 Canvas canvas = page.getCanvas();
35 String duration = "";
36 if(tm.get(i).getTaking().equals("Hourly"))
37 {
38 duration = "Every "+tm.get(i).getDuration() + " Hours.";
39 }
40 else if(tm.get(i).getTaking().equals("Daily"))
41 {
42 duration = "At "+tm.get(i).getDuration() + " o clock";
43 }
44
45 PrintWindow pw = new PrintWindow(getActivity(), tm.get(i).getName(), tm.get(i).getFormeclair(),
46 tm.get(i).getDosageu(), tm.get(i).getDosageup1(), tm.get(i).getTaking(), duration,
47 tm.get(i).getEnddate(), x, y);
48
49 pw.draw(canvas);
50
51 if(i!=0 && i%2 == 1)
52 {
53 x = 0;
54 y = y+160;
55 }
56 else
57 {
58 x = 295;
59
60 }
61 }
62 document.finishPage(page);
63
64 //Create the file in the pictures directory of sd card
65 File pdf = new File(Utils.MED_LIST_PATH);
66 if(pdf.exists())
67 pdf.delete();
68
69 try {
70 pdf.createNewFile();
71 document.writeTo(new FileOutputStream(pdf));
72 } catch (IOException e) {
73 e.printStackTrace();
74 }
75 document.close();
76
77 return document;
78 }


Wen es auch interessiert... zum Drucken habe ich dann einfach auf die Samsung Mobile Print App aus dem Store zurückgegriffen. Mit Hilfe dieser starte ich folgenden Intent:
1Intent intent = new Intent("com.sec.print.mobileprint.action.PRINT");
2 Uri uri = Uri.parse(Utils.MED_LIST_PATH);
3 intent.putExtra("com.sec.print.mobileprint.extra.CONTENT", uri );
4 intent.putExtra("com.sec.print.mobileprint.extra.CONTENT_TYPE", "DOCUMENT");
5 intent.putExtra("com.sec.print.mobileprint.extra.OPTION_TYPE", "DOCUMENT_PRINT");
6 intent.putExtra("com.sec.print.mobileprint.extra.JOB_NAME", "print medicaments list");
7 startActivity(intent);

Das reicht die erzeugte PDF an die Samsung app weiter und ermöglicht das direkte drucken aus dieser heraus. Das war die einfachste Lösung für den Moment. Alternativ habe ich versucht die neuen Funktionen von 4.4 für das Drucken zu verwenden, leider konnte aber die mitgelieferte Druckererkennung in Android meinen benötigten Drucker nicht finden. Somit war die Sache erledigt :(

Hoffe es hilft mal irgendwann irgendwem.

Viele Grüße

— geändert am 29.11.2013, 15:16:43

Antworten