{"id":18465142,"url":"https://github.com/natario1/viewprinter","last_synced_at":"2025-08-22T00:31:01.217Z","repository":{"id":99104655,"uuid":"106020134","full_name":"natario1/ViewPrinter","owner":"natario1","description":"Live preview, edit and print functionality for View hierarchies. Supports PDF, PNG, JPEG.","archived":false,"fork":false,"pushed_at":"2019-10-23T10:32:27.000Z","size":761,"stargazers_count":190,"open_issues_count":10,"forks_count":35,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-12-06T23:12:53.538Z","etag":null,"topics":["android","android-library","android-printer","pdf","pdf-document","print","printer"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/natario1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["natario1"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2017-10-06T15:25:09.000Z","updated_at":"2024-07-09T01:59:32.000Z","dependencies_parsed_at":"2023-06-03T20:45:43.651Z","dependency_job_id":null,"html_url":"https://github.com/natario1/ViewPrinter","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natario1%2FViewPrinter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natario1%2FViewPrinter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natario1%2FViewPrinter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natario1%2FViewPrinter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/natario1","download_url":"https://codeload.github.com/natario1/ViewPrinter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230542288,"owners_count":18242332,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-library","android-printer","pdf","pdf-document","print","printer"],"created_at":"2024-11-06T09:12:05.944Z","updated_at":"2024-12-20T06:06:28.303Z","avatar_url":"https://github.com/natario1.png","language":"Java","readme":"[![Build Status](https://travis-ci.org/natario1/ViewPrinter.svg?branch=master)](https://travis-ci.org/natario1/ViewPrinter)\n[![Release](https://img.shields.io/github/release/natario1/ViewPrinter.svg)](https://github.com/natario1/ViewPrinter/releases)\n[![Issues](https://img.shields.io/github/issues-raw/natario1/ViewPrinter.svg)](https://github.com/natario1/ViewPrinter/issues)\n\n*Need support, consulting, or have any other business-related question? Feel free to \u003ca href=\"mailto:mat.iavarone@gmail.com\"\u003eget in touch\u003c/a\u003e.*\n\n*Like the project, make profit from it, or simply want to thank back? Please consider [sponsoring me](https://github.com/sponsors/natario1)!*\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"art/logo_400.png\" vspace=\"10\" width=\"250\" height=\"250\"\u003e\n\u003c/p\u003e\n\n*The ViewPrinter logo was created inside ViewPrinter itself, with a few minutes and some Canvas drawing.\nIt's a FloatingActionButton with circles on it, then exported to PNG. See source code in the demo app.*\n\n# ViewPrinter\n\nViewPrinter lets you preview, edit and print View hierarchies, be it graphics, texts, \nor whatever you can draw in Android.\n\n```groovy\ncompile 'com.otaliastudios:viewprinter:0.3.0'\n```\n\n\u003cp\u003e\n  \u003cimg src=\"art/preview_page.png\" width=\"250\" vspace=\"20\" hspace=\"5\"\u003e\n  \u003cimg src=\"art/preview_options.png\" width=\"250\" vspace=\"20\" hspace=\"5\"\u003e\n  \u003cimg src=\"art/preview_logo.png\" width=\"250\" vspace=\"20\" hspace=\"5\"\u003e\n\u003c/p\u003e\n\n## Features\n\n- [`DocumentView`](#documentview) : a live preview container for editable, zoomable, pannable views.\n- Automatic splitting into separate pages\n- Automatic splitting into separate page columns\n- [`AutoSplitTextView`](#text-content) and [`AutoSplitEditText`](#text-content) to split text into separate views\n- Standardized or custom [`PrintSize`](#printsize)s, or even wrap content\n- [`PdfPrinter`](#pdfprinter) prints document to PDF respecting pages\n- [`JpegPrinter`](#jpegprinter) and [`PngPrinter`](#pngprinter) to print single pages\n\nViewPrinter depends on [`natario1/ZoomLayout`](https://github.com/natario1/ZoomLayout): check it out!\n\n## Why\n\nThe starting point of this library is that the Android framework is extremely powerful and versatile when drawing.\nAndroid is not a complete word processor, and is not a complete graphic editor. But it is a decent mix between the two,\nand with a few Android drawing skills - even just layout - we can draw objects, construct hierarchies,\ncreate complex layouts with dependencies, apply transformations and whatever else we usually do.\n\nThis can be an incomplete, but very powerful and versatile tool for document creation, whether its text,\nyour resume, or a graphical task. The only things lacking, in order to leverage this versatility, are:\n\n- a decent [document preview editor](#live-preview)\n- an [easy way to print](#print) the document\n\nThis library provides both.\n\n# Docs\n\n#### [Live Preview](#live-preview)\n\n- [`DocumentView`](#documentview)\n  - [Free content](#free-content)\n  - [Paged content](#paged-content)\n  - [Callbacks](#callbacks)\n- [Automatic Splitting](#automatic-splitting)\n  - [Pagination](#pagination)\n  - [Columns](#columns)\n  - [Text content](#text-content)\n- [Custom Views](#custom-views)\n\n#### [Print](#print)\n\n- [`PrintSize` and Units](#printsize-and-units)\n- [Printing documents](#printing-documents)\n  - [Permissions](#permissions)\n  - [`PdfPrinter`](#pdfprinter)\n  - [`PngPrinter`](#pngprinter)\n  - [`JpegPrinter`](#jpegprinter)\n- [`Printable` and Print Preview](#printable-and-print-preview)\n\n\n\n# Live Preview\n\n## DocumentView\n\n```xml\n\u003ccom.otaliastudios.printer.DocumentView\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    app:pageElevation=\"0.01in\"\n    app:pageInsetTop=\"20pt\"\n    app:pageInsetBottom=\"20pt\"\n    app:pageInsetLeft=\"30pt\"\n    app:pageInsetRight=\"30pt\"\n    app:pageDividerWidth=\"0.1in\"\n    app:columnsPerPage=\"1\"\n    app:pageBackground=\"@color/white\"\n    app:pagerType=\"horizontal\"\n    app:printSize=\"ISO_A5\"\u003e\n\n    \u003c!-- Content here. --\u003e\n\n\u003c/com.otaliastudios.printer.DocumentView\u003e\n```\n\n`DocumentView` offers a live, zoom-and-pannable preview of your View content.\nIt is actually an instance of [`ZoomLayout`](https://github.com/natario1/ZoomLayout) so\nhead there to discover more visual APIs.\n\n`DocumentView` can host any kind and number of Android views. Internally, they are laid\nout into pages (or columns) that act as a vertical `LinearLayout`, so keep that in mind\nwhen adding childs.\n\n### Free content\n\nThe document view can act as if it had no physical boundaries. This can be achieved\nby setting the `PrintSize` to `PrintSize.WRAP_CONTENT`, which is a special size designed\nfor this.\n\nIn this case, the content can extend to whatever dimensions you want, and the printed\noutput file will follow.\n\n```xml\n\u003ccom.otaliastudios.printer.DocumentView\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    app:printSize=\"wrapContent\"\u003e\n\n    \u003c!-- Allowed --\u003e\n    \u003cView\n        android:layout_width=\"5000px\"\n        android:layout_height=\"5000px\"/\u003e\n\n\u003c/com.otaliastudios.printer.DocumentView\u003e\n```\n\nIf your content changes, the page will adapt to it.\n\n### Paged content\n\nTypically you would like to define the output file size (be it PDF or PNG or whatever).\nIt can be achieved through `app:printSize` or `view.setPrintSize(PrintSize)`, and\nby doing this you are implicitly setting a boundary for the page content.\n\nYour page(s) will be laid out as having that dimension. Keep this in mind when adding\nyour child views:\n\n```xml\n\u003ccom.otaliastudios.printer.DocumentView\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    app:printSize=\"ISO_A5\"\u003e\n\n    \u003c!-- MATCH_PARENT on both: this view will occupy a whole page/column! --\u003e\n    \u003cView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"/\u003e\n        \n    \u003c!-- MATCH_PARENT on width: this view will fit the page/column width and extend to its height.\n         If it happens to be bigger than the page, part of it will be hidden (there's nothing we \n         can do) --\u003e\n    \u003cView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"/\u003e\n        \n    \u003c!-- WRAP_CONTENT: nothing special, the view wraps content, bounded by the page. --\u003e\n    \u003cView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"/\u003e\n    \n\u003c/com.otaliastudios.printer.DocumentView\u003e\n```\n\n### Callbacks\n\nYou can be notified of pages creation or destruction by simply setting a `DocumentCallback`:\n\n```java\ndocument.setDocumentCallback(new DocumentCallback() {\n    @Override\n    public void onPageCreated(int number) {}\n    \n    @Override\n    public void onPageDestroyed(int number) {}\n})\n```\n\n## Automatic Splitting\n\nThe document preview will automatically split the content to make it fit into your page.\nThe auto-split funcionality acts on three layers:\n\n- Views are distributed over [pages](#pagination)\n- Views are distributed over [columns](#columns)\n- [Text content](#text-content) is distributed over multiple views\n\n### Pagination\n\nTo enable pagination, you simply have to set a [`PrintSize`](#printsize-and-units) that is\ndifferent than `PrintSize.WRAP_CONTENT`. In this context, when our views start to go out of\nthe page boundaries, a new page is created and the view is moved.\n\nIt is recommended that you use `DocumentTextView` and `DocumentEditText` for your texts: these\nviews will notify their parent when they are too small to fit the page. For custom views,\nplease take a look at the `DocumentHelper` methods.\n\n### Columns\n\nTo enable columns, use `document.setColumnsPerPage(int)` or the XML attribute `app:columnsPerPage`.\nThis will split every page into columns, and we will move Views around if they happen to be\nbigger than their available space in the current column.\n\nAgain, it is recommended that you use `DocumentTextView` and `DocumentEditText` for your texts.\nFor other kinds of content, it is your responsibility to ensure that the views are small enough.\n\n### Text Content\n\nWe provide support for text splitting, as you can see in the demo app.\n\n- For static text, please use `AutoSplitTextView`\n- For editable text, please use `AutoSplitEditText`\n\nThese views should work out of the box. When space is not enough, the view will clone itself\ninto a new child view, trying to keep as much properties as possible (text properties, padding, scale, etc.).\nThis new view will have no id, but you can use `findViewById(R.id.firstView)` to get the first view\nof this chain, and act on that.\n\n|Method|Description|\n|------|-----------|\n|`setChainText(CharSequence)`|Sets text for the whole chain. This means that it will be redistributed as it should.|\n|`getChainText()`|Returns the text for the whole chain - not just the current view.|\n|`getFirst()`|Returns the first view of the chain - the original view that started splitting.|\n|`next()`|Returns the next view of the chain.|\n|`previous()`|Returns the previous view of the chain.|\n\nThe `AutoSplitEditText` also supports the `app:chainBackground` XML attribute. It will control\nthe edit text background, and hide it when the view loses its focus, for example.\n\n## Custom Views\n\nDifferent views might not be fully supported when there are pages. For example, it's hard to know\nif a view is smaller than it would like to be, and it's impossible to split its internal content.\nWe provide some helpers to address the most common issues.\n\n### Documentable\n\nThis is a general interface that might get richer in the future. For now we provide callbacks\nfor the attach / detach lifecycle of a direct view.\n\n|Method|Description|\n|------|-----------|\n|`onAttach(int, int)`|Notifies that this view was attached to the given page and column.|\n|`onPreDetach()`|Notifies that this view is about to be detached. It can still act on its parent now.|\n|`onDetach()`|Notifies that this view has been detached (probably to move it to another page / column).|\n\n### DocumentHelper\n\nThe document helper will help your views notify the page when they are smaller than they would like\nto be. Just call `DocumentHelper.onLayout(view)` after the view has been laid out. The helper will\ncheck if we need to trigger a re-layout or some movements.\n\n### AutoSplitView\n\nThis is, again, a general purpose interface for views that want to implement auto splitting.\nThe basic example is `AutoSplitTextView` which clones itself to split its content over multiple\nviews. If you need to implement this, take a look at our implementations and the interface javadocs.\n\n### AutoSplitTextHelper\n\nThis helper can help you implement the `AutoSplitView` interface for text views. It's all done -\nyou just have to delegate the appropriate methods. It is used internally by `AutoSplitTextView` and\n`AutoSplitEditText`.\n\n# Print\n\n## PrintSize and Units\n\nThe `PrintSize` object is what links the live preview of `DocumentView` to the printers,\ndefining the actual size of each page.\n\nThe `PrintSize` class offers lots of predefined, standardized sizes that you can use for printing\nyour documents, or a special `WRAP_CONTENT` size that is suitable for one-page content.\n\nYou can also define a custom `PrintSize` of your choice, using the static methods:\n\n- `PrintSize.fromMils(int, int)`: sets the content size in *mils*, that is, thousandth-s of an inch.\n- `PrintSize.fromPoints(float, float)`: sets the content size in *points*, that is, 72th-s of an inch.\n- `PrintSize.fromInches(float, float)`: sets the content size in *inches*.\n- `PrintSize.fromMillimeters(int, int)`: sets the content size in *millimeters*.\n- `PrintSize.fromPixels(Context, float, float)`: sets the content size in *pixels*. We need a valid context to know the display metrics.\n\nThere is no preferable API - it's up to your content and how you want to deal with it.\nThese units must be considered in XML also when laying out your views, for example:\n\n```xml\nandroid:layout_width=\"20pt\"\nandroid:layout_width=\"2in\"\nandroid:layout_width=\"2px\"\nandroid:textSize=\"20px\"\napp:pageInsets=\"30mm\"\n```\n\nDepending on what you do, standard units like `sp` and `dp` *might* make no sense here.\n\n## Printing documents\n\nThe printing process is extremely simple, and currently requires a non empty `DocumentView` preview\nto work. Once you have added your content, simply call the `print(String, File, String)`\nmethod of the printer of your choice. You must pass:\n\n- `String printId`: an identifier for this printing process\n- `File file`: a directory where the file will be written\n- `String name`: the filename of the output file\n\nThe printing action will be executed in a background thread, and you will receive a successful\n`PrintCallback` callback on the UI thread once it ended, so you can display your file.\n\n### Permissions\n\nYou must have appropriate permissions to write the file in that location.\nOn Marshmallow+, these permissions must be explicitly asked to the user.\n\nThe library currently will automatically ask the `READ_EXTERNAL_STORAGE` and `WRITE_EXTERNAL_STORAGE`\npermissions if the output file appears to be in the external storage. Make sure you\n\n- declare these permissions in your manifest\n- implement `onRequestPermissionResult` as such:\n\n```java\n@Override\npublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n    super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n    if (mPrinter.onRequestPermissionRequest(requestCode, permissions, grantResults)) {\n        mPrinter.print(mId, mDirectory, mFilename);\n    }\n}\n```\n\n### PdfPrinter\n\n```java\nmPrinter = new PdfPrinter(mDocumentView, mPrintCallback);\nmPrinter.setPrintPageBackground(true);\nmPrinter.print(\"id\", mFile, \"document.pdf\");\n```\n\nNothing special. This will create a document with your exact name in the directory, as long as you \nhave rights to write there. The output PDF will have as much pages as your live preview.\n\nYou can choose whether to include or exclude the page background using `mPrinter.setPrintPageBackground()`\nwhich defaults to `true`.\n\n### PngPrinter\n\n```java\nmPrinter = new PngPrinter(mDocumentView, mPrintCallback);\nmPrinter.setPrintPageBackground(true);\nmPrinter.setPrintPages(PRINT_ALL);\nmPrinter.setPrintScale(1f);\nmPrinter.print(\"id\", mFile, \"my-image\");\n```\n\nImage printers have a couple differences with the `PdfPrinter`:\n\n- You can choose which pages to print (defaults to all) using `setPrintPages(int...)`.\n  If more than one are selected, we will save separate files in your directory, e.g.\n  `my-image-1.png`, `my-image-2.png`, `my-image-3.png`.\n\n- This also means that the `PrintCallback` can be called multiple times, each time passing\n  the actual image file.\n  \n- You can downscale the resulting image using `setPrintScale(float)`, defaults to 1. For instance,\n  this is useful for caching low-quality previews. A `1000x1000` image with a `0.5` scale will\n  result in a `500x500` file.\n\n### JpegPrinter\n\n```java\nmPrinter = new JpegPrinter(mDocumentView, mPrintCallback);\nmPrinter.setPrintPageBackground(true);\nmPrinter.setPrintablePages(PRINT_ALL);\nmPrinter.setPrintScale(1f);\nmPrinter.setPrintQuality(90);\nmPrinter.print(\"id\", mFile, \"my-image\");\n```\n\nOn top of the `PngPrinter` functionality, this will let you specify a JPEG compression quality\nusing `mPrinter.setPrintQuality()`.\n\n## Printable and Print Preview\n\nThe `Printable` interface can be implemented by any view in the hierarchy, no matter how deep.\nThis will let it receive pre- and post-print event notifications, that can help in hiding visual\nartifacts that should not make their way to the final page.\n\nFor instance, you can use `onPrePrint` to hide the red underlines in text fields.\n\n```java\npublic interface Printable {\n\n    // View is about to be printed.\n    void onPrePrint();\n\n    // View has been printed.\n    void onPostPrint();\n}\n```\n\nThe pre-print mode gives an actual preview of the final document. This can be toggled\nin the live editor using `documentView.enterPrintPreview()` and `documentView.exitPrintPreview()`.\n\nWith these, every `Printable` view in the hierarchy will enter its pre-print / post-print mode.\nIf there are no `Printable` views, these methods have no noticeable effect.\n\n# Contributions\n\nYou are welcome to contribute with suggestions or pull requests. To contact me,\n\u003ca href=\"mailto:mat.iavarone@gmail.com\"\u003esend an email.\u003c/a\u003e\n","funding_links":["https://github.com/sponsors/natario1","https://github.com/sponsors/natario1)!"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnatario1%2Fviewprinter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnatario1%2Fviewprinter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnatario1%2Fviewprinter/lists"}