├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lib ├── build.gradle ├── libs │ └── PDFjet.jar └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── hendrix │ │ └── pdfmyxml │ │ ├── PdfDocument.java │ │ ├── interfaces │ │ ├── IData.java │ │ ├── IDisposable.java │ │ └── IId.java │ │ ├── utils │ │ ├── BitmapUtils.java │ │ └── MeasureUtils.java │ │ └── viewRenderer │ │ ├── AbstractViewRenderer.java │ │ ├── IViewRenderer.java │ │ ├── RecycledViewRenderer.java │ │ ├── SimpleViewRenderer.java │ │ └── ViewRendererFactory.java │ └── res │ └── values │ └── strings.xml ├── proguard-rules.pro └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | .idea/ 15 | *.iml 16 | 17 | # Gradle files 18 | .gradle/ 19 | build/ 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | # Keystore 31 | *.jks 32 | com_crashlytics_export_strings.xml 33 | crashlytics-build.properties 34 | 35 | ### OSX ### 36 | .DS_Store 37 | .AppleDouble 38 | .LSOverride 39 | 40 | # Icon must end with two \r 41 | Icon 42 | 43 | 44 | # Thumbnails 45 | ._* 46 | 47 | # Files that might appear on external disk 48 | .Spotlight-V100 49 | .Trashes 50 | 51 | # Directories potentially created on remote AFP share 52 | .AppleDB 53 | .AppleDesktop 54 | Network Trash Folder 55 | Temporary Items 56 | .apdisk 57 | Status API Training Shop Blog About 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android-PdfMyXml [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Android--PdfMyXml-green.svg?style=flat)](https://android-arsenal.com/details/1/2297) [![Jitpack](https://jitpack.io/v/HendrixString/Android-PdfMyXml.svg)](https://jitpack.io/#HendrixString/Android-PdfMyXml) 2 | convert your android `XML` layouts into PDF document, works on all versions of Android. 3 | 4 | ### Dependencies 5 | * [`pdfjet`](https://github.com/soster/pdfjet) 6 | 7 | ## How to use 8 | 9 | Option 1: Simply fork or download the project, you can also download and create `.aar` file yourself. 10 | 11 | Option 2: Jitpack 12 | 13 | Add Jitpack in your root build.gradle at the end of repositories: 14 | ```groovy 15 | allprojects { 16 | repositories { 17 | ... 18 | maven { url "https://jitpack.io" } 19 | } 20 | } 21 | ``` 22 | 23 | Add to your dependencies: 24 | 25 | ```groovy 26 | dependencies { 27 | compile 'com.github.HendrixString:Android-PdfMyXml:{Tag}' // the latest version is "v1.0.1" 28 | } 29 | ``` 30 | 31 | ## Notable features 32 | * should work on all Android versions 33 | * completely scalable 34 | * supports bitmap re usage. 35 | * production proved code. Used in a commercial project. 36 | 37 | ### Instructions 38 | #### 1. create XML layouts 39 | First create XML layouts. give it dimensions in **pixels** (and for all it's sub views) and proportions according landscape or portrait according to ratio **1:1.41**.

40 | page1.xml 41 | ```java 42 | 43 | 47 | 52 | 53 | 54 | ``` 55 | 56 | you can create as many as pages/templates as you need. 57 | 58 | #### 2. Implement a View renderer 59 | implement your View renderer by extending `AbstractViewRenderer` or by anonymously instantiating it and injecting the layout id. the initView(View view) will supply you an inflated View automatically. There are other options but I wont cover it now. 60 | ```java 61 | AbstractViewRenderer page = new AbstractViewRenderer(context, R.layout.page1) { 62 | private String _text; 63 | 64 | public void setText(String text) { 65 | _text = text; 66 | } 67 | 68 | @Override 69 | protected void initView(View view) { 70 | TextView tv_hello = (TextView)view.findViewById(R.id.tv_hello); 71 | tv_hello.setText(_text); 72 | } 73 | }; 74 | 75 | // you can reuse the bitmap if you want 76 | page.setReuseBitmap(true); 77 | 78 | ``` 79 | 80 | #### 3. Build the PDF document 81 | Use `PdfDocument` or `PdfDocument.Builder` to add pages and render and run it all at background with progress bar. 82 | ```java 83 | PdfDocument doc = new PdfDocument(ctx); 84 | 85 | // add as many pages as you have 86 | doc.addPage(page); 87 | 88 | doc.setRenderWidth(2115); 89 | doc.setRenderHeight(1500); 90 | doc.setOrientation(PdfDocument.A4_MODE.LANDSCAPE); 91 | doc.setProgressTitle(R.string.gen_please_wait); 92 | doc.setProgressMessage(R.string.gen_pdf_file); 93 | doc.setFileName("test"); 94 | doc.setSaveDirectory(_ctx.getExternalFilesDir(null)); 95 | doc.setInflateOnMainThread(false); 96 | doc.setListener(new PdfDocument.Callback() { 97 | @Override 98 | public void onComplete(File file) { 99 | Log.i(PdfDocument.TAG_PDF_MY_XML, "Complete"); 100 | } 101 | 102 | @Override 103 | public void onError(Exception e) { 104 | Log.i(PdfDocument.TAG_PDF_MY_XML, "Error"); 105 | } 106 | }); 107 | 108 | doc.createPdf(ctx); 109 | 110 | ``` 111 | 112 | or use `PdfDocument.Builder` 113 | ```java 114 | new PdfDocument.Builder(ctx).addPage(page).orientation(PdfDocument.A4_MODE.LANDSCAPE) 115 | .progressMessage(R.string.gen_pdf_file).progressTitle(R.string.gen_please_wait) 116 | .renderWidth(2115).renderHeight(1500) 117 | .saveDirectory(_ctx.getExternalFilesDir(null)); 118 | .filename("test") 119 | .listener(new PdfDocument.Callback() { 120 | @Override 121 | public void onComplete(File file) { 122 | Log.i(PdfDocument.TAG_PDF_MY_XML, "Complete"); 123 | } 124 | 125 | @Override 126 | public void onError(Exception e) { 127 | Log.i(PdfDocument.TAG_PDF_MY_XML, "Error"); 128 | } 129 | }).create().createPdf(this); 130 | ``` 131 | 132 | ### Additional Contributors 133 | * [`Sébastiaan`](https://github.com/se-bastiaan) 134 | 135 | ### License 136 | If you like it -> star or share it with others 137 | 138 | ``` 139 | Copyright (C) 2016 Tomer Shalev (https://github.com/HendrixString) 140 | 141 | This program is free software: you can redistribute it and/or modify 142 | it under the terms of the GNU General Public License as published by 143 | the Free Software Foundation, either version 3 of the License, or 144 | (at your option) any later version. 145 | 146 | This program is distributed in the hope that it will be useful, 147 | but WITHOUT ANY WARRANTY; without even the implied warranty of 148 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 149 | GNU General Public License for more details. 150 | 151 | You should have received a copy of the GNU General Public License 152 | along with this program. If not, see . 153 | ``` 154 | 155 | ### Contact Author 156 | * [tomer.shalev@gmail.com](tomer.shalev@gmail.com) 157 | * [Google+ TomershalevMan](https://plus.google.com/+TomershalevMan/about) 158 | * [Facebook - HendrixString](https://www.facebook.com/HendrixString) 159 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.5.0' 9 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | jcenter() 19 | } 20 | } 21 | 22 | task clean(type: Delete) { 23 | delete rootProject.buildDir 24 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HendrixString/Android-PdfMyXml/6984df8b37ac1f805761d8d71805af3c6658df65/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /lib/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | 4 | group='com.github.hendrixstring' 5 | 6 | android { 7 | compileSdkVersion 21 8 | buildToolsVersion "23.0.2" 9 | 10 | defaultConfig { 11 | minSdkVersion 15 12 | targetSdkVersion 21 13 | versionCode 1 14 | versionName "1.0" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile fileTree(dir: 'libs', include: ['*.jar']) 26 | } -------------------------------------------------------------------------------- /lib/libs/PDFjet.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HendrixString/Android-PdfMyXml/6984df8b37ac1f805761d8d71805af3c6658df65/lib/libs/PDFjet.jar -------------------------------------------------------------------------------- /lib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/src/main/java/com/hendrix/pdfmyxml/PdfDocument.java: -------------------------------------------------------------------------------- 1 | package com.hendrix.pdfmyxml; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Context; 5 | import android.content.res.Resources; 6 | import android.graphics.Bitmap; 7 | import android.os.Build; 8 | import android.os.Handler; 9 | import android.util.Log; 10 | 11 | import com.hendrix.pdfmyxml.interfaces.IDisposable; 12 | import com.hendrix.pdfmyxml.utils.BitmapUtils; 13 | import com.hendrix.pdfmyxml.viewRenderer.AbstractViewRenderer; 14 | import com.pdfjet.A4; 15 | import com.pdfjet.Image; 16 | import com.pdfjet.ImageType; 17 | import com.pdfjet.PDF; 18 | import com.pdfjet.Page; 19 | 20 | import java.io.ByteArrayInputStream; 21 | import java.io.File; 22 | import java.io.FileOutputStream; 23 | import java.io.InputStream; 24 | import java.util.ArrayList; 25 | 26 | /** 27 | * a PDF document creator 28 | * 29 | * @see com.hendrix.pdfmyxml.PdfDocument.Builder 30 | * 31 | * @author Tomer Shalev 32 | */ 33 | @SuppressWarnings("UnusedDeclaration") 34 | public class PdfDocument implements IDisposable{ 35 | static final public String TAG_PDF_MY_XML = "PDF_MY_XML"; 36 | 37 | private static final String sDefault_Filename_prefix = "pdf_"; 38 | // android context 39 | private Context _ctx = null; 40 | // the orientation 41 | private A4_MODE _orientation = A4_MODE.LANDSCAPE; 42 | // file name 43 | private String file_name; 44 | // file object of pdf 45 | private File file; 46 | // save directory of pdf 47 | private File save_directory; 48 | // state of the rendering 49 | private boolean _isWorking = false; 50 | // inflate on main thread 51 | private boolean _inflateOnMainThread = true; 52 | // progress dialog 53 | private ProgressDialog _ringProgressDialog; 54 | // progress dialog message 55 | private String _txtProgressMessage = "Generating Pdf.."; 56 | // progress dialog title 57 | private String _txtProgressTitle = "Please wait"; 58 | // rendered pages streams 59 | protected ArrayList _pages_rendered = null; 60 | // views to render 61 | protected ArrayList _pages = null; 62 | // async part 63 | private Handler _handler = new Handler(); 64 | // background thread 65 | private Thread _thread = null; 66 | // exception if happened 67 | private Exception _error = null; 68 | 69 | /** 70 | * the rendered dimensions in {@code Pixels} of the {@link AbstractViewRenderer} 71 | */ 72 | private int _renderWidth = 0; 73 | private int _renderHeight = 0; 74 | 75 | public PdfDocument(Context ctx) { 76 | setContext(ctx); 77 | 78 | _pages = new ArrayList<>(); 79 | _pages_rendered = new ArrayList<>(); 80 | } 81 | 82 | /** 83 | * the document orientation, contains aspect ratio info 84 | */ 85 | public enum A4_MODE { 86 | PORTRAIT(0.707f, A4.PORTRAIT), LANDSCAPE(1.41f, A4.LANDSCAPE); 87 | 88 | private float _ar; 89 | private float[] _a4 = null; 90 | 91 | A4_MODE(float ar, float[] mode) { 92 | _ar = ar; 93 | _a4 = mode; 94 | } 95 | 96 | /** 97 | * 98 | * @return the aspect ratio of the mode {@code ar = width/height} 99 | */ 100 | public float aspectRatio() { return _ar; } 101 | 102 | /** 103 | * 104 | * @return the corresponding mode in pdfjet lib 105 | */ 106 | public float[] A4() { 107 | return _a4; 108 | } 109 | } 110 | 111 | /** 112 | * add a page with a custom class view renderer. please note that the bitmap of the view will be recycled. 113 | * 114 | * @param page a view renderer instance 115 | * 116 | * @see com.hendrix.pdfmyxml.viewRenderer.AbstractViewRenderer 117 | */ 118 | public void addPage(AbstractViewRenderer page) { 119 | if(_inflateOnMainThread) 120 | renderView(page); 121 | else 122 | _pages.add(page); 123 | } 124 | 125 | /** 126 | * add a page with a rendered bitmap. the bitmap will not be recycled, it's up to 127 | * the user to recycle. 128 | * 129 | * @param page a bitmap 130 | * 131 | */ 132 | public void addPage(Bitmap page) { 133 | ByteArrayInputStream stream = BitmapUtils.bitmapToPngInputStream(page); 134 | _pages_rendered.add(stream); 135 | } 136 | 137 | /** 138 | * clear all of the pages and rendered pages 139 | */ 140 | public void clearPages() 141 | { 142 | _pages.clear(); 143 | _pages_rendered.clear(); 144 | } 145 | 146 | /** 147 | * set the rendered width in {@code Pixels} of the {@link AbstractViewRenderer} 148 | * 149 | * @param value width in {@code Pixels} 150 | */ 151 | public void setRenderWidth(int value) 152 | { 153 | _renderWidth = value; 154 | } 155 | 156 | /** 157 | * set the rendered height in {@code Pixels} of the {@link AbstractViewRenderer} 158 | * 159 | * @param value height in {@code Pixels} 160 | */ 161 | public void setRenderHeight(int value) 162 | { 163 | _renderHeight = value; 164 | } 165 | 166 | /** 167 | * set the context 168 | * 169 | * @param ctx the context 170 | */ 171 | public void setContext(Context ctx) { 172 | _ctx = ctx; 173 | } 174 | 175 | /** 176 | * 177 | * @return get the orientation 178 | * 179 | * @see PdfDocument.A4_MODE 180 | */ 181 | public A4_MODE getOrientation() { 182 | return _orientation; 183 | } 184 | 185 | /** 186 | * set the orientation 187 | * 188 | * @param orientation {@code {PORTRAIT, LANDSCAPE}} 189 | * 190 | * @see PdfDocument.A4_MODE 191 | */ 192 | public void setOrientation(A4_MODE orientation) { 193 | _orientation = orientation; 194 | } 195 | 196 | /** 197 | * set the text message for the progress dialog 198 | * 199 | * @param resId a string resource identifier 200 | */ 201 | public void setProgressMessage(int resId) { 202 | _txtProgressMessage = _ctx.getString(resId); 203 | } 204 | 205 | /** 206 | * set the text title for the progress dialog 207 | * 208 | * @param resId a string resource identifier 209 | */ 210 | public void setProgressTitle(int resId) { 211 | _txtProgressTitle = _ctx.getString(resId); 212 | } 213 | 214 | /** 215 | * 216 | * @return the pdf file name 217 | */ 218 | public String getFileName() { 219 | return file_name; 220 | } 221 | 222 | /** 223 | * set the file name 224 | * 225 | * @param fileName the pdf file name 226 | */ 227 | public void setFileName(String fileName) { 228 | file_name = fileName; 229 | } 230 | 231 | /** 232 | * set the file save directory 233 | * 234 | * @param directory the pdf file save directory 235 | */ 236 | public void setSaveDirectory(File directory) { 237 | save_directory = directory; 238 | } 239 | 240 | /** 241 | * 242 | * @return the pdf {@link java.io.File} if available 243 | */ 244 | public File getFile() { 245 | return file; 246 | } 247 | 248 | /** 249 | * does the a PDF is generating now? 250 | * 251 | * @return {@code true/false} 252 | */ 253 | public boolean isWorking() { 254 | return _isWorking; 255 | } 256 | 257 | /** 258 | * set the inflation of views on the Main thread. 259 | * use it, in case you are having inflation errors. 260 | * by default, and even though not recommended by Google, the 261 | * inflation and rendering to bitmaps happens on the background thread. 262 | * 263 | * @param enabled {@code true/false} 264 | */ 265 | public void setInflateOnMainThread(boolean enabled) { 266 | _inflateOnMainThread = enabled; 267 | } 268 | 269 | /** 270 | * create the pdf and render according to report types and a time frame 271 | * 272 | * @param window an {@link android.app.Activity} in which to display a progress dialog (Optional) 273 | */ 274 | public void createPdf(Context window) { 275 | if (isWorking()) 276 | return; 277 | 278 | Resources res = _ctx.getResources(); 279 | 280 | if (window != null) { 281 | if(_ringProgressDialog !=null) { 282 | _ringProgressDialog.dismiss(); 283 | } 284 | 285 | _ringProgressDialog = ProgressDialog.show(window, _txtProgressTitle, _txtProgressMessage, true); 286 | 287 | if(!_ringProgressDialog.isShowing()) 288 | _ringProgressDialog.show(); 289 | } 290 | 291 | _thread = new Thread(new Runnable() { 292 | @Override 293 | public void run() { 294 | _isWorking = true; 295 | 296 | //_pages_rendered.clear(); 297 | 298 | if(!_inflateOnMainThread) { 299 | for (AbstractViewRenderer view : _pages) { 300 | Log.i(TAG_PDF_MY_XML, "render page"); 301 | renderView(view); 302 | } 303 | } 304 | 305 | internal_generatePdf(); 306 | 307 | Log.i(TAG_PDF_MY_XML, "pdf 1"); 308 | 309 | clearPages(); 310 | 311 | Log.i(TAG_PDF_MY_XML, "pdf 2"); 312 | 313 | // go back to the main thread 314 | _handler.post(new Runnable() { 315 | @Override 316 | public void run() { 317 | if(_ringProgressDialog !=null) 318 | _ringProgressDialog.dismiss(); 319 | 320 | if(_listener != null) { 321 | if(_error != null) 322 | _listener.onError(_error); 323 | else 324 | _listener.onComplete(file); 325 | } 326 | 327 | Log.i(TAG_PDF_MY_XML, "pdf 3"); 328 | 329 | release(); 330 | } 331 | }); 332 | 333 | } 334 | 335 | }); 336 | 337 | _thread.setPriority(Thread.MAX_PRIORITY); 338 | _thread.start(); 339 | } 340 | 341 | private Callback _listener = null; 342 | 343 | /** 344 | * set a listener for the PDF generation events 345 | * 346 | * @param listener a {@link com.hendrix.pdfmyxml.PdfDocument.Callback} 347 | */ 348 | public void setListener(Callback listener) { 349 | _listener = listener; 350 | } 351 | 352 | private void internal_generatePdf() 353 | { 354 | String name = (file_name == null) ? sDefault_Filename_prefix + System.currentTimeMillis() : file_name; 355 | 356 | file_name = name + ".pdf"; 357 | //File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "pdf"); 358 | File dir = save_directory == null ? _ctx.getExternalFilesDir(null) : save_directory; 359 | 360 | file = new File(dir, file_name); 361 | _error = null; 362 | 363 | try { 364 | FileOutputStream fos = new FileOutputStream(file);//"Example_01.pdf"); 365 | PDF pdf = new com.pdfjet.PDF(fos); 366 | 367 | Page page; 368 | Image image; 369 | float ar; 370 | 371 | for (InputStream inputStream : _pages_rendered) { 372 | page = new Page(pdf, _orientation.A4()); 373 | image = new Image(pdf, inputStream, ImageType.PNG); 374 | 375 | Log.i(TAG_PDF_MY_XML, "add page"); 376 | 377 | inputStream.close(); //doesn't do anything in byte array 378 | 379 | ar = page.getWidth() / image.getWidth(); 380 | 381 | image.scaleBy(ar); 382 | 383 | image.drawOn(page); 384 | } 385 | 386 | pdf.flush(); 387 | fos.close(); 388 | } 389 | catch (Exception exc) { 390 | _error = exc; 391 | } 392 | 393 | } 394 | 395 | /** 396 | * render the view 397 | * 398 | * @param page {@link com.hendrix.pdfmyxml.viewRenderer.AbstractViewRenderer} instance 399 | */ 400 | private void renderView(AbstractViewRenderer page) { 401 | page.attachContext(_ctx); 402 | 403 | if(_renderWidth==0 || _renderHeight==0) 404 | if(Build.VERSION.SDK_INT <= 17) 405 | Log.e(TAG_PDF_MY_XML, "_renderWidth,_renderHeight==0 on API <= 17 can lead to bad behaviour with RelativeLayout and may crash, please use explicit values!!!"); 406 | 407 | Bitmap bmp = page.render(_renderWidth, _renderHeight); 408 | ByteArrayInputStream stream = BitmapUtils.bitmapToPngInputStream(bmp); 409 | 410 | page.disposeBitmap(); 411 | 412 | _pages_rendered.add(stream); 413 | } 414 | 415 | /** 416 | * release this class for future usage 417 | */ 418 | private void release() { 419 | _pages.clear(); 420 | _pages_rendered.clear(); 421 | 422 | _error = null; 423 | _isWorking = false; 424 | 425 | file_name = null; 426 | file = null; 427 | 428 | if(_ringProgressDialog != null) { 429 | _ringProgressDialog.dismiss(); 430 | _ringProgressDialog = null; 431 | } 432 | } 433 | 434 | /** 435 | * dispose the item 436 | */ 437 | @Override 438 | public void dispose() { 439 | release(); 440 | 441 | _listener = null; 442 | _handler = null; 443 | _thread = null; 444 | _ringProgressDialog = null; 445 | } 446 | 447 | /** 448 | * callback interface for PDF creation 449 | */ 450 | public interface Callback { 451 | 452 | /** 453 | * successful completion of pdf 454 | * 455 | * @param file the file 456 | */ 457 | void onComplete(File file); 458 | 459 | /** 460 | * error creating the PDF 461 | */ 462 | void onError(Exception e); 463 | } 464 | 465 | /** 466 | * a mutable builder for document 467 | */ 468 | public static class Builder { 469 | private PdfDocument _doc = null; 470 | 471 | public Builder(Context ctx) { 472 | _doc = new PdfDocument(ctx); 473 | } 474 | 475 | /** 476 | * create the pdf document instance. afterwards, use {@link com.hendrix.pdfmyxml.PdfDocument#createPdf(Context)} 477 | * 478 | * @return a {@link com.hendrix.pdfmyxml.PdfDocument} 479 | */ 480 | public PdfDocument create() { 481 | return _doc; 482 | } 483 | 484 | /** 485 | * add a page with a custom class view renderer. please note that the bitmap of the view will be recycled. 486 | * 487 | * @param page a view renderer instance 488 | * 489 | * @see com.hendrix.pdfmyxml.viewRenderer.AbstractViewRenderer 490 | */ 491 | public Builder addPage(AbstractViewRenderer page) { 492 | _doc.addPage(page); 493 | 494 | return this; 495 | } 496 | 497 | /** 498 | * set the rendered width in {@code Pixels} of the {@link AbstractViewRenderer} 499 | * 500 | * @param value width in {@code Pixels} 501 | */ 502 | public Builder renderWidth(int value) 503 | { 504 | _doc.setRenderWidth(value); 505 | 506 | return this; 507 | } 508 | 509 | /** 510 | * set the rendered height in {@code Pixels} of the {@link AbstractViewRenderer} 511 | * 512 | * @param value height in {@code Pixels} 513 | */ 514 | public Builder renderHeight(int value) 515 | { 516 | _doc.setRenderHeight(value); 517 | 518 | return this; 519 | } 520 | 521 | /** 522 | * add a page with a rendered bitmap. the bitmap will not be recycled, it's up to 523 | * the user to recycle. 524 | * 525 | * @param page a bitmap 526 | * 527 | */ 528 | public Builder addPage(Bitmap page) { 529 | _doc.addPage(page); 530 | 531 | return this; 532 | } 533 | 534 | /** 535 | * set the file name 536 | * 537 | * @param name the pdf file name 538 | */ 539 | public Builder filename(String name) { 540 | _doc.setFileName(name); 541 | 542 | return this; 543 | } 544 | 545 | /** 546 | * set the file save directory 547 | * 548 | * @param directory the pdf file save directory 549 | */ 550 | public Builder saveDirectory(File directory) { 551 | _doc.setSaveDirectory(directory); 552 | 553 | return this; 554 | } 555 | 556 | /** 557 | * set the inflation of views on the Main thread. 558 | * use it, in case you are having inflation errors. 559 | * by default, and even though not recommended by Google, the 560 | * inflation and rendering to bitmaps happens on the background thread. 561 | * 562 | * @param enabled {@code true/false} 563 | */ 564 | public Builder inflateOnMainThread(boolean enabled) { 565 | _doc.setInflateOnMainThread(enabled); 566 | 567 | return this; 568 | } 569 | 570 | /** 571 | * set a listener for the PDF generation events 572 | * 573 | * @param listener a {@link com.hendrix.pdfmyxml.PdfDocument.Callback} 574 | */ 575 | public Builder listener(Callback listener) { 576 | _doc.setListener(listener); 577 | 578 | return this; 579 | } 580 | 581 | /** 582 | * set the orientation 583 | * 584 | * @param mode {@code {PORTRAIT, LANDSCAPE}} 585 | * 586 | * @see PdfDocument.A4_MODE 587 | */ 588 | public Builder orientation(A4_MODE mode) { 589 | _doc.setOrientation(mode); 590 | 591 | return this; 592 | } 593 | 594 | /** 595 | * set the text message for the progress dialog 596 | * 597 | * @param resId a string resource identifier 598 | */ 599 | public Builder progressMessage(int resId) { 600 | _doc.setProgressMessage(resId); 601 | 602 | return this; 603 | } 604 | 605 | /** 606 | * set the text title for the progress dialog 607 | * 608 | * @param resId a string resource identifier 609 | */ 610 | public Builder progressTitle(int resId) { 611 | _doc.setProgressTitle(resId); 612 | 613 | return this; 614 | } 615 | 616 | } 617 | 618 | } 619 | -------------------------------------------------------------------------------- /lib/src/main/java/com/hendrix/pdfmyxml/interfaces/IData.java: -------------------------------------------------------------------------------- 1 | package com.hendrix.pdfmyxml.interfaces; 2 | 3 | public interface IData { 4 | 5 | void setData(Object data); 6 | Object getData(); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /lib/src/main/java/com/hendrix/pdfmyxml/interfaces/IDisposable.java: -------------------------------------------------------------------------------- 1 | package com.hendrix.pdfmyxml.interfaces; 2 | 3 | public interface IDisposable { 4 | /** 5 | * dispose the item 6 | */ 7 | void dispose(); 8 | } 9 | -------------------------------------------------------------------------------- /lib/src/main/java/com/hendrix/pdfmyxml/interfaces/IId.java: -------------------------------------------------------------------------------- 1 | package com.hendrix.pdfmyxml.interfaces; 2 | 3 | public interface IId { 4 | 5 | void setId(String id); 6 | String getId(); 7 | } 8 | -------------------------------------------------------------------------------- /lib/src/main/java/com/hendrix/pdfmyxml/utils/BitmapUtils.java: -------------------------------------------------------------------------------- 1 | package com.hendrix.pdfmyxml.utils; 2 | 3 | import android.content.res.Resources; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Bitmap.CompressFormat; 6 | import android.graphics.Bitmap.Config; 7 | import android.graphics.BitmapFactory; 8 | import android.graphics.BitmapShader; 9 | import android.graphics.Canvas; 10 | import android.graphics.Color; 11 | import android.graphics.Matrix; 12 | import android.graphics.Paint; 13 | import android.graphics.PorterDuff.Mode; 14 | import android.graphics.PorterDuffXfermode; 15 | import android.graphics.Rect; 16 | import android.graphics.Shader.TileMode; 17 | import android.util.DisplayMetrics; 18 | import android.util.TypedValue; 19 | 20 | import java.io.ByteArrayInputStream; 21 | import java.io.ByteArrayOutputStream; 22 | 23 | /** 24 | * @author Tomer Shalev 25 | */ 26 | @SuppressWarnings("UnusedDeclaration") 27 | public final class BitmapUtils 28 | { 29 | private static DisplayMetrics _dm; 30 | private static Resources _resources; 31 | 32 | private BitmapUtils() { 33 | } 34 | 35 | public static void init(Resources resources) 36 | { 37 | _resources = resources; 38 | _dm = _resources.getDisplayMetrics(); 39 | } 40 | 41 | public enum ScaleMode { 42 | STRETCH, LETTERBOX, ZOOM, NONE 43 | } 44 | 45 | /** 46 | * not the regular bitmap resizer. much smarter with resizing and cropping options and resizing with proportions. 47 | * @param bmSrc the source bitmap 48 | * @param rectDest rectangle, you need to pass at least width or height or both. For example, specify only width to scale, and height will be calc dynamically 49 | * @param scaleMode - one of the enums: ScaleMode {STRETCH,LETTERBOX,ZOOM,NONE} 50 | * @param fitBitmapResult effective cropping of dead pixels, applied only when ScaleMode.LETTERBOX is used 51 | * @param scaleConditionally scale only if rectDest < bmSrc.rect, i.e rectDest is contained inside bmSrc.rect 52 | * @return resulting bitmap 53 | * 54 | *

TODO:
55 | * - add translation for zoom, center images
56 | * - requires QA (i didnt have time) 57 | * 58 | */ 59 | static public Bitmap resizeBitmap(Bitmap bmSrc, Rect rectDest, ScaleMode scaleMode, boolean fitBitmapResult, 60 | boolean scaleConditionally, boolean recycleBmpSource) 61 | { 62 | Matrix mat = new Matrix(); 63 | Bitmap bmResult; 64 | 65 | int wOrig = bmSrc.getWidth(); 66 | int hOrig = bmSrc.getHeight(); 67 | 68 | int wScaleTo = rectDest.width(); 69 | int hScaleTo = rectDest.height(); 70 | 71 | if(wScaleTo==0 && hScaleTo==0) 72 | throw new Error("resizeBitmap: need at least $scaleTo.width or $scaleTo.height"); 73 | 74 | float arW = (wScaleTo != 0) ? (float)wScaleTo / (float)wOrig : Float.NaN; 75 | float arH = (hScaleTo != 0) ? (float)hScaleTo / (float)hOrig : Float.NaN; 76 | 77 | arW = Float.isNaN(arW) ? arH: arW; 78 | arH = Float.isNaN(arH) ? arW: arH; 79 | 80 | float arMin = Math.min(arW, arH); 81 | float arMax = Math.max(arW, arH); 82 | 83 | wScaleTo = (wScaleTo != 0) ? wScaleTo : (int)(((float)wOrig)*arW); 84 | hScaleTo = (hScaleTo != 0) ? hScaleTo : (int)(((float)hOrig)*arH); 85 | 86 | if(scaleConditionally) { 87 | boolean isScaleConditionally = (wScaleTo >= bmSrc.getWidth()) && (hScaleTo >= bmSrc.getHeight()); 88 | if(isScaleConditionally) 89 | return Bitmap.createBitmap(bmSrc); 90 | } 91 | 92 | bmResult = Bitmap.createBitmap(wScaleTo, hScaleTo, Config.ARGB_8888); 93 | 94 | Canvas canvas = new Canvas(bmResult); 95 | 96 | switch(scaleMode) 97 | { 98 | case STRETCH: 99 | { 100 | mat.reset(); 101 | mat.postScale(arW, arH); 102 | 103 | canvas.drawBitmap(bmSrc, mat, null); 104 | 105 | break; 106 | } 107 | case LETTERBOX: 108 | { 109 | if(fitBitmapResult) { 110 | if(bmResult != null) 111 | bmResult.recycle(); 112 | 113 | wScaleTo = (int)((float)wOrig * arMin); 114 | hScaleTo = (int)((float)hOrig * arMin); 115 | bmResult = Bitmap.createBitmap(wScaleTo, hScaleTo, Config.ARGB_8888); 116 | 117 | canvas.setBitmap(bmResult); 118 | } 119 | 120 | mat.reset(); 121 | mat.postScale(arMin, arMin); 122 | 123 | canvas.drawBitmap(bmSrc, mat, null); 124 | 125 | break; 126 | } 127 | case ZOOM: 128 | { 129 | mat.reset(); 130 | mat.postScale(arMax, arMax); 131 | 132 | canvas.drawBitmap(bmSrc, mat, null); 133 | 134 | break; 135 | } 136 | case NONE: 137 | { 138 | mat.reset(); 139 | 140 | canvas.drawBitmap(bmSrc, mat, null); 141 | 142 | break; 143 | } 144 | 145 | } 146 | 147 | if(recycleBmpSource) 148 | bmSrc.recycle(); 149 | 150 | return bmResult; 151 | } 152 | 153 | /** 154 | * 155 | * @param picturePath complete path name for the file to be decoded. 156 | * @return Bitmap instance 157 | */ 158 | public static Bitmap pathToBitmap(String picturePath) 159 | { 160 | BitmapFactory.Options opts = new BitmapFactory.Options(); 161 | 162 | opts.inDither = false; //Disable Dithering mode 163 | opts.inPurgeable = true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared 164 | opts.inInputShareable = true; //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future 165 | opts.inTempStorage = new byte[32 * 1024]; 166 | 167 | return BitmapFactory.decodeFile(picturePath, opts); 168 | } 169 | 170 | /** 171 | * cut a circle from a bitmap 172 | * 173 | * @param picturePath complete path name for the file. 174 | * @param destCube the cube dimension of dest bitmap 175 | * @return the bitmap 176 | */ 177 | public static Bitmap cutCircleFromBitmap(String picturePath, int destCube) 178 | { 179 | BitmapFactory.Options opts = new BitmapFactory.Options(); 180 | 181 | opts.inDither = false; //Disable Dithering mode 182 | opts.inPurgeable = true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared 183 | opts.inInputShareable = true; //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future 184 | opts.inTempStorage = new byte[32 * 1024]; 185 | 186 | Bitmap bitmapImg = BitmapFactory.decodeFile(picturePath, opts); 187 | 188 | int cube = destCube; 189 | 190 | if(bitmapImg == null) 191 | return null; 192 | 193 | int smallest = Math.min(bitmapImg.getWidth(), bitmapImg.getHeight()); 194 | 195 | Bitmap output = Bitmap.createBitmap(cube, cube, Config.ARGB_8888); 196 | Canvas canvas = new Canvas(output); 197 | 198 | final int color = 0xff424242; 199 | final Paint paint = new Paint(); 200 | 201 | int left = (int) ((bitmapImg.getWidth() - smallest) * 0.5); 202 | int top = (int) ((bitmapImg.getHeight() - smallest) * 0.5); 203 | 204 | final Rect rectSrc = new Rect(left, top, left + smallest, top + smallest); 205 | final Rect rectDest = new Rect(0, 0, cube, cube); 206 | 207 | paint.setAntiAlias(true); 208 | 209 | canvas.drawARGB(0, 0, 0, 0); 210 | 211 | paint.setColor(color); 212 | 213 | canvas.drawCircle(cube / 2, cube / 2, cube / 2, paint); 214 | 215 | paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 216 | 217 | canvas.drawBitmap(bitmapImg, rectSrc, rectDest, paint); 218 | 219 | bitmapImg.recycle(); 220 | 221 | return output; 222 | } 223 | 224 | /** 225 | * Bitmap into compressed PNG 226 | * 227 | * @param image the Bitmap 228 | * @return byte array of PNG 229 | */ 230 | public static byte[] bitmapToPng(final Bitmap image) 231 | { 232 | if (image == null) 233 | return null; 234 | 235 | ByteArrayOutputStream ba = new ByteArrayOutputStream(); 236 | 237 | if (image.compress(CompressFormat.PNG, 100, ba)) 238 | return ba.toByteArray(); 239 | else 240 | return null; 241 | } 242 | 243 | /** 244 | * Bitmap into compressed PNG as InputStream object 245 | * 246 | * @param image the Bitmap 247 | * @return compressed PNG as InputStream object 248 | */ 249 | public static ByteArrayInputStream bitmapToPngInputStream(final Bitmap image) 250 | { 251 | return new ByteArrayInputStream(bitmapToPng(image)); 252 | } 253 | 254 | /** 255 | * Bitmap into compressed jpeg 256 | * 257 | * @param image the Bitmap 258 | * @param quality quality of compression 259 | * @return byte array of jpeg 260 | */ 261 | public static byte[] bitmapToJpg(final Bitmap image, final int quality) 262 | { 263 | if (image == null) 264 | return null; 265 | 266 | ByteArrayOutputStream ba = new ByteArrayOutputStream(); 267 | 268 | if (image.compress(CompressFormat.JPEG, quality, ba)) 269 | return ba.toByteArray(); 270 | else 271 | return null; 272 | } 273 | 274 | /** 275 | * raw byteArray into Bitmap 276 | * 277 | * @param image the byteArray 278 | * @return Bitmap 279 | */ 280 | public static Bitmap imgToBitmap(final byte[] image) 281 | { 282 | if (image == null) 283 | return null; 284 | 285 | return BitmapFactory.decodeByteArray(image, 0, image.length); 286 | } 287 | 288 | /** 289 | * dp to pixels 290 | * @param val dp 291 | * @return pixels 292 | */ 293 | public static int dpToPx(float val) 294 | { 295 | return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, val, _dm); 296 | } 297 | 298 | /** 299 | * mask bitmap 300 | * @param src todo 301 | * @param mask todo 302 | * @param dst todo 303 | * @param dstCanvas todo 304 | * @param paint todo 305 | * @param paintMode todo 306 | * @return todo 307 | */ 308 | public static Bitmap maskBitmap(Bitmap src, Bitmap mask, Bitmap dst, Canvas dstCanvas, Paint paint, PorterDuffXfermode paintMode) 309 | { 310 | if (dst == null) 311 | dst = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(), Config.ARGB_8888); 312 | 313 | if (dstCanvas == null) 314 | dstCanvas = new Canvas(dst); 315 | 316 | if (paintMode == null) 317 | paintMode = new PorterDuffXfermode(Mode.DST_IN); 318 | 319 | if (paint == null) { 320 | paint = new Paint(Paint.ANTI_ALIAS_FLAG); 321 | paint.setXfermode(paintMode); 322 | } 323 | 324 | dstCanvas.drawBitmap(src, 0, 0, null); 325 | dstCanvas.drawBitmap(mask, 0, 0, paint); 326 | 327 | paint.setXfermode(null); 328 | 329 | return dst; 330 | } 331 | 332 | /** 333 | * mask a bitmap 334 | * 335 | * @param src the bitmap to mask 336 | * @param drawableResId a resource id of the mask 337 | * @return a bitmap 338 | */ 339 | public static Bitmap maskBitmap(Bitmap src, int drawableResId) 340 | { 341 | Bitmap mask = BitmapFactory.decodeResource(_resources, drawableResId); 342 | 343 | return maskBitmap(src, mask, null, null, null, null); 344 | } 345 | 346 | /** 347 | * create a circle from cutout from a bitmap. 348 | * does not alter sizes. 349 | * 350 | * @param bitmap the bitmap 351 | * @see #cutCircleFromBitmap(String, int) 352 | * @return a bitmap circle cutout 353 | */ 354 | public static Bitmap roundBitMap(Bitmap bitmap) 355 | { 356 | Bitmap circleBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); 357 | 358 | BitmapShader shader = new BitmapShader (bitmap, TileMode.CLAMP, TileMode.CLAMP); 359 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 360 | 361 | paint.setShader(shader); 362 | 363 | Canvas c = new Canvas(circleBitmap); 364 | 365 | c.drawCircle(bitmap.getWidth()/2, bitmap.getHeight()/2, bitmap.getWidth()/2, paint); 366 | 367 | return circleBitmap; 368 | } 369 | 370 | public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) 371 | { 372 | Bitmap sbmp; 373 | 374 | if(bmp.getWidth() != radius || bmp.getHeight() != radius) 375 | sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false); 376 | else 377 | sbmp = bmp; 378 | 379 | Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(), Config.ARGB_8888); 380 | Canvas canvas = new Canvas(output); 381 | 382 | //final int color = 0xffa19774; 383 | final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 384 | final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight()); 385 | 386 | paint.setAntiAlias(true); 387 | paint.setFilterBitmap(true); 388 | paint.setDither(true); 389 | 390 | canvas.drawARGB(0, 0, 0, 0); 391 | 392 | paint.setColor(Color.parseColor("#BAB399")); 393 | 394 | canvas.drawCircle(sbmp.getWidth() / 2+0.7f, sbmp.getHeight() / 2+0.7f, sbmp.getWidth() / 2+0.1f, paint); 395 | 396 | paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 397 | 398 | canvas.drawBitmap(sbmp, rect, rect, paint); 399 | 400 | return output; 401 | } 402 | 403 | } -------------------------------------------------------------------------------- /lib/src/main/java/com/hendrix/pdfmyxml/utils/MeasureUtils.java: -------------------------------------------------------------------------------- 1 | package com.hendrix.pdfmyxml.utils; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * @author Tomer Shalev 7 | */ 8 | @SuppressWarnings("unused") 9 | public class MeasureUtils { 10 | 11 | private MeasureUtils() { 12 | } 13 | 14 | static public int DIPToPixels(Context context, float dip) 15 | { 16 | final float scale = context.getResources().getDisplayMetrics().density; 17 | 18 | // also can use 19 | //TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 65, context.getResources().getDisplayMetrics()); 20 | 21 | return (int) (dip * scale + 0.5f); 22 | } 23 | 24 | static public int pixelsToDIP(Context context, int pixels) 25 | { 26 | final float scale = context.getResources().getDisplayMetrics().density; 27 | 28 | return (int) ((pixels - 0.5f) / scale); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /lib/src/main/java/com/hendrix/pdfmyxml/viewRenderer/AbstractViewRenderer.java: -------------------------------------------------------------------------------- 1 | package com.hendrix.pdfmyxml.viewRenderer; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import com.hendrix.pdfmyxml.utils.MeasureUtils; 12 | 13 | /** 14 | * @author Tomer Shalev 15 | */ 16 | abstract public class AbstractViewRenderer implements IViewRenderer { 17 | protected View _view = null; 18 | protected Context _ctx = null; 19 | private Bitmap _bmp = null; 20 | private boolean _flagReuseBitmap = false; 21 | private Object _data = null; 22 | 23 | /** 24 | * 25 | * @param ctx a context 26 | * @param layoutResId a layout resource id 27 | */ 28 | public AbstractViewRenderer(Context ctx, int layoutResId) { 29 | this(ctx, LayoutInflater.from(ctx).inflate(layoutResId, null)); 30 | } 31 | 32 | /** 33 | * 34 | * @param ctx a context 35 | * @param view an inflated view 36 | */ 37 | public AbstractViewRenderer(Context ctx, View view) { 38 | attachContext(ctx); 39 | 40 | _view = view; 41 | } 42 | 43 | protected AbstractViewRenderer() { 44 | throw new UnsupportedOperationException(); 45 | } 46 | 47 | /** 48 | * attach a context to the renderer 49 | * 50 | * @param ctx the context 51 | */ 52 | @Override 53 | public void attachContext(Context ctx) { 54 | _ctx = ctx; 55 | } 56 | 57 | /** 58 | * render the view with a reused {@link Bitmap} 59 | * 60 | * @param bitmap a bitmap to render into (reused) 61 | * @param width the width 62 | * @param height the height 63 | * 64 | *

Note:

65 | * on API <= 17, you must give explicit {@code width} and {@code height} because of a bug in {@link android.widget.RelativeLayout} 66 | */ 67 | @Override 68 | public final Bitmap render(Bitmap bitmap, int width, int height) { 69 | validate(); 70 | 71 | initView(getView()); 72 | 73 | View view = getView(); 74 | 75 | int specWidth = View.MeasureSpec.makeMeasureSpec(width, width==0 ? View.MeasureSpec.UNSPECIFIED : View.MeasureSpec.EXACTLY); 76 | int specHeight = View.MeasureSpec.makeMeasureSpec(height, height==0 ? View.MeasureSpec.UNSPECIFIED : View.MeasureSpec.EXACTLY); 77 | 78 | view.measure(specWidth, specHeight); 79 | 80 | view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); 81 | 82 | // recycle bitmap 83 | Bitmap b = bitmap;//Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); 84 | 85 | Canvas c = new Canvas(b); 86 | c.translate(-view.getScrollX(), -view.getScrollY()); 87 | 88 | view.draw(c); 89 | 90 | return _bmp=b; 91 | } 92 | 93 | /** 94 | * render the bitmap 95 | * 96 | * @param width the wanted width for rendering, in Pixels. if 0, then the view will measure itself as big as it needs to be(only on API > 17). 97 | * @param height the wanted height for rendering, in Pixels. if 0, then the view will measure itself as big as it needs to be(only on API > 17). 98 | * 99 | *

Note:

100 | * on API <= 17, you must give explicit {@code width} and {@code height} because of a bug in {@link android.widget.RelativeLayout} 101 | */ 102 | @Override final public Bitmap render(int width, int height) { 103 | validate(); 104 | 105 | initView(getView()); 106 | 107 | View view = getView(); 108 | 109 | int specWidth = View.MeasureSpec.makeMeasureSpec(width == 0 ? ViewGroup.LayoutParams.WRAP_CONTENT : width, width == 0 ? View.MeasureSpec.UNSPECIFIED : View.MeasureSpec.EXACTLY); 110 | int specHeight = View.MeasureSpec.makeMeasureSpec(height == 0 ? ViewGroup.LayoutParams.WRAP_CONTENT : height, height==0 ? View.MeasureSpec.UNSPECIFIED : View.MeasureSpec.EXACTLY); 111 | int a = ViewGroup.LayoutParams.MATCH_PARENT; 112 | System.out.println("a"); 113 | 114 | try { 115 | view.measure(specWidth, specHeight); 116 | } 117 | catch (NullPointerException exc) { 118 | exc.printStackTrace(); 119 | } 120 | 121 | view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); 122 | 123 | Bitmap b; 124 | 125 | // recycle bitmap 126 | if(!_flagReuseBitmap) { 127 | disposeBitmap(); 128 | b = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); 129 | } 130 | else { 131 | // reuse bitmap 132 | b = (_bmp==null || _bmp.isRecycled()) ? Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888) : _bmp; 133 | b.eraseColor(Color.TRANSPARENT); 134 | } 135 | 136 | Canvas c = new Canvas(b); 137 | c.translate(-view.getScrollX(), -view.getScrollY()); 138 | 139 | view.draw(c); 140 | 141 | return _bmp=b; 142 | } 143 | 144 | final public Bitmap render2(int width, int height) { 145 | validate(); 146 | 147 | initView(getView()); 148 | 149 | View view = getView(); 150 | 151 | int specWidth = View.MeasureSpec.makeMeasureSpec(MeasureUtils.DIPToPixels(_ctx, width), width==0 ? View.MeasureSpec.UNSPECIFIED : View.MeasureSpec.EXACTLY); 152 | int specHeight = View.MeasureSpec.makeMeasureSpec(MeasureUtils.DIPToPixels(_ctx, height), height==0 ? View.MeasureSpec.UNSPECIFIED : View.MeasureSpec.EXACTLY); 153 | 154 | try { 155 | view.measure(specWidth, specHeight); 156 | } 157 | catch (NullPointerException exc) { 158 | exc.printStackTrace(); 159 | } 160 | 161 | view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); 162 | 163 | Bitmap b; 164 | 165 | // recycle bitmap 166 | if(!_flagReuseBitmap) { 167 | disposeBitmap(); 168 | b = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); 169 | } 170 | else { 171 | // reuse bitmap 172 | b = (_bmp==null || _bmp.isRecycled()) ? Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888) : _bmp; 173 | b.eraseColor(Color.TRANSPARENT); 174 | } 175 | 176 | Canvas c = new Canvas(b); 177 | c.translate(-view.getScrollX(), -view.getScrollY()); 178 | 179 | view.draw(c); 180 | 181 | return _bmp=b; 182 | } 183 | 184 | /** 185 | * return the rendered bitmap 186 | * 187 | * @return the rendered bitmap 188 | */ 189 | @Override 190 | public Bitmap getBitmap() { 191 | return _bmp; 192 | } 193 | 194 | /** 195 | * get the view to render 196 | * 197 | * @return the view 198 | */ 199 | @Override 200 | public View getView() { 201 | return _view; 202 | } 203 | 204 | /** 205 | * width of the canvas 206 | * 207 | * @return width 208 | */ 209 | @Override 210 | public int getWidth() { 211 | return getView().getWidth(); 212 | } 213 | 214 | /** 215 | * height of the canvas 216 | * 217 | * @return height 218 | */ 219 | @Override 220 | public int getHeight() { 221 | return getView().getHeight(); 222 | } 223 | 224 | /** 225 | * init the view. this is where you will do setup of 226 | * the view's subviews, assign text etc... 227 | */ 228 | abstract protected void initView(View view); 229 | 230 | /** 231 | * validate the input 232 | * 233 | * @throws IllegalArgumentException if context or view is null 234 | */ 235 | private void validate() { 236 | if(_ctx==null) 237 | throw new IllegalArgumentException("ViewRenderer:: context was not set!!"); 238 | if(_view==null) 239 | throw new IllegalArgumentException("ViewRenderer:: view or layout resource was not set!!"); 240 | } 241 | 242 | /** 243 | * 244 | * @return flag reuse bitmap 245 | */ 246 | public boolean isReuseBitmap() { 247 | return _flagReuseBitmap; 248 | } 249 | 250 | /** 251 | * flag for indicating bitmap re usage if possible for multiple. 252 | * 253 | * @param flagReuseBitmap {@code true/false} 254 | */ 255 | public void setReuseBitmap(boolean flagReuseBitmap) { 256 | _flagReuseBitmap = flagReuseBitmap; 257 | } 258 | 259 | /** 260 | * dispose the item 261 | */ 262 | @Override 263 | public void dispose() { 264 | _bmp.recycle(); 265 | _view = null; 266 | _ctx = null; 267 | } 268 | 269 | /** 270 | * dispose the bitmap 271 | */ 272 | public void disposeBitmap() { 273 | if(_bmp != null) 274 | _bmp.recycle(); 275 | _bmp = null; 276 | } 277 | 278 | @Override 279 | public void setData(Object data) { 280 | _data = data; 281 | } 282 | 283 | @Override 284 | public Object getData() { 285 | return _data; 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /lib/src/main/java/com/hendrix/pdfmyxml/viewRenderer/IViewRenderer.java: -------------------------------------------------------------------------------- 1 | package com.hendrix.pdfmyxml.viewRenderer; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.view.View; 6 | 7 | import com.hendrix.pdfmyxml.interfaces.IData; 8 | import com.hendrix.pdfmyxml.interfaces.IDisposable; 9 | 10 | /** 11 | * @author Tomer Shalev 12 | */ 13 | public interface IViewRenderer extends IDisposable, IData { 14 | 15 | /** 16 | * attach a context to the renderer 17 | * 18 | * @param ctx the context 19 | */ 20 | void attachContext(Context ctx); 21 | 22 | /** 23 | * render the view 24 | * 25 | * @param width the width 26 | * @param height the height 27 | */ 28 | Bitmap render(int width, int height); 29 | 30 | /** 31 | * render the view 32 | * 33 | * @param bitmap a bitmap to render into 34 | * @param width the width 35 | * @param height the height 36 | */ 37 | Bitmap render(Bitmap bitmap, int width, int height); 38 | 39 | /** 40 | * return the rendered bitmap 41 | * 42 | * @return the rendered bitmap 43 | */ 44 | Bitmap getBitmap(); 45 | 46 | /** 47 | * get the view to render 48 | * 49 | * @return the view 50 | */ 51 | View getView(); 52 | 53 | /** 54 | * width of the canvas 55 | * 56 | * @return width 57 | */ 58 | int getWidth(); 59 | 60 | /** 61 | * height of the canvas 62 | * 63 | * @return height 64 | */ 65 | int getHeight(); 66 | } 67 | -------------------------------------------------------------------------------- /lib/src/main/java/com/hendrix/pdfmyxml/viewRenderer/RecycledViewRenderer.java: -------------------------------------------------------------------------------- 1 | package com.hendrix.pdfmyxml.viewRenderer; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | 7 | /** 8 | * a View renderer with recycling capabilities. 9 | * 10 | * @author Tomer Shalev 11 | */ 12 | public class RecycledViewRenderer extends SimpleViewRenderer { 13 | 14 | public RecycledViewRenderer() { 15 | } 16 | 17 | /** 18 | * recycle the view renderer with a new view 19 | * 20 | * @param ctx the context 21 | * @param view a new view 22 | */ 23 | public RecycledViewRenderer recycleWith(Context ctx, View view) { 24 | attachContext(ctx); 25 | 26 | _view = view; 27 | 28 | return this; 29 | } 30 | 31 | /** 32 | * recycle the view renderer with a new view 33 | * 34 | * @param ctx the context 35 | * @param layoutResId a resource layout id 36 | */ 37 | public RecycledViewRenderer recycleWith(Context ctx, int layoutResId) { 38 | return recycleWith(ctx, LayoutInflater.from(ctx).inflate(layoutResId, null)); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /lib/src/main/java/com/hendrix/pdfmyxml/viewRenderer/SimpleViewRenderer.java: -------------------------------------------------------------------------------- 1 | package com.hendrix.pdfmyxml.viewRenderer; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | 6 | /** 7 | * a simple view renderer implementation of abstract view renderer with empty init. 8 | * i.e - use it to render a view that was already measured or a layout resource 9 | * that will get as big as it needs to 10 | * @author Tomer Shalev 11 | */ 12 | public class SimpleViewRenderer extends AbstractViewRenderer { 13 | /** 14 | * @param ctx a context 15 | * @param layoutResId a layout resource id 16 | */ 17 | public SimpleViewRenderer(Context ctx, int layoutResId) { 18 | super(ctx, layoutResId); 19 | } 20 | 21 | /** 22 | * @param ctx a context 23 | * @param view a view 24 | */ 25 | public SimpleViewRenderer(Context ctx,View view) { 26 | super(ctx, view); 27 | } 28 | 29 | public SimpleViewRenderer() {} 30 | 31 | /** 32 | * empty view init 33 | * 34 | * @param view the view 35 | */ 36 | @Override 37 | protected void initView(View view) { 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/main/java/com/hendrix/pdfmyxml/viewRenderer/ViewRendererFactory.java: -------------------------------------------------------------------------------- 1 | package com.hendrix.pdfmyxml.viewRenderer; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.view.View; 6 | 7 | /** 8 | * a recycled view renderer factory. 9 | * 10 | * @author Tomer Shalev 11 | */ 12 | public class ViewRendererFactory { 13 | volatile static private RecycledViewRenderer _rvr = new RecycledViewRenderer(); 14 | 15 | /** 16 | * recycle a view renderer with the following 17 | * 18 | * @param ctx the context 19 | * @param view the view to renderer 20 | * @param width the width 21 | * @param height the height 22 | * 23 | * @return a bitmap of the view 24 | */ 25 | static public Bitmap getBitmapOfView(Context ctx, View view, int width, int height) { 26 | return _rvr.recycleWith(ctx, view).render(width, height); 27 | } 28 | 29 | /** 30 | * recycle a view renderer with the following 31 | * 32 | * @param ctx the context 33 | * @param layoutResId the layout resource identifier 34 | * @param width the width 35 | * @param height the height 36 | * 37 | * @return a bitmap of the view 38 | */ 39 | static public Bitmap getBitmapOfView(Context ctx, int layoutResId, int width, int height) { 40 | return _rvr.recycleWith(ctx, layoutResId).render(width, height); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PdfDroid 3 | 4 | -------------------------------------------------------------------------------- /proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:/src_mreshet/android/AndroidStudioProjects/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':lib' 2 | --------------------------------------------------------------------------------