[
  {
    "path": ".gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n### Android template\n# Built application files\n#*.apk\n*.ap_\n\n# Files for the Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\n\n# Gradle files\n.gradle/\nbuild/\n/*/build/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n\n### JetBrains template\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion\n\n*.iml\n\n## Directory-based project format:\n.idea/\n# if you remove the above rule, at least ignore the following:\n\n# User-specific stuff:\n# .idea/workspace.xml\n# .idea/tasks.xml\n# .idea/dictionaries\n\n# Sensitive or high-churn files:\n# .idea/dataSources.ids\n# .idea/dataSources.xml\n# .idea/sqlDataSources.xml\n# .idea/dynamic.xml\n# .idea/uiDesigner.xml\n\n# Gradle:\n# .idea/gradle.xml\n# .idea/libraries\n\n# Mongo Explorer plugin:\n# .idea/mongoSettings.xml\n\n## File-based project format:\n*.ipr\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\n\n\n### Gradle template\n.gradle\n\n# Ignore Gradle GUI config\ngradle-app.setting\n\n# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)\n!gradle-wrapper.jar\n\n###\nandroid-crop\n\n\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "README -V1.0+.md",
    "content": "## [TakePhoto](https://github.com/crazycodeboy/TakePhoto) 简介    \n`TakePhoto`是一款用于Android设备获取照片（拍照或从相册、文件中选择）、裁剪图片、压缩图片的开源工具库，目前最新版本**[2.0.0已发布，请使用最新版](https://github.com/crazycodeboy/TakePhoto)**。   \n\n**V1.0+**  \n\n- 支持以拍照的方式获取照片 \n- 支持从相册选择照片  \n- 支持对照片进行裁切\n- 支持对照片进行压缩\n- 支持对裁切及压缩参数自定义  \n- 支持因拍照Activity被回收后的自动恢复   \n\nGitHub地址： [https://github.com/crazycodeboy/TakePhoto](https://github.com/crazycodeboy/TakePhoto)\n## 如何使用   \n### 使用TakePhoto有以下两种方式：\n**方式一：通过继承的方式**  \n1. 继承TakePhotoActivity、TakePhotoFragmentActivity、TakePhotoFragment三者之一。  \n2. 通过`getTakePhoto()`获取TakePhoto实例进行相关操作。  \n3. 重写以下方法获取结果        \n```java\nvoid takeSuccess(String imagePath);  \nvoid takeFail(String msg);\nvoid takeCancel();\n```  \n此方式使用简单，满足的大部分的使用需求，具体使用详见simple。如果通过继承的方式无法满足实际项目的使用，可以通过下面介绍的方式。  \n\n**方式二：通过组装的方式**  \n1. 获取TakePhoto实例`TakePhoto takePhoto=new TakePhotoImpl(getActivity(),this);`  \n2. 在 `onCreate`,`onActivityResult`,`onSaveInstanceState`方法中调用TakePhoto对用的方法。  \n3. 调用TakePhoto实例进行相关操作。  \n4. 在`TakeResultListener`相关方法中获取结果。      \n### 关于压缩照片 \n你可以选择是否对照片进行压缩处理。  \n```java\n /**\n  * 启用照片压缩\n  * @param config 压缩照片配置\n  * @param showCompressDialog 压缩时是否显示进度对话框\n  * @return \n  */\n TakePhoto onEnableCompress(CompressConfig config,boolean showCompressDialog);\n```\neg：  \n`getTakePhoto().onEnableCompress(new CompressConfig.Builder().setMaxSize(50*1024).setMaxPixel(800).create(),true).onPicSelectCrop(imageUri);`  \n如果你启用了照片压缩，TakePhoto会使用`CompressImage`对照片进行压缩处理，CompressImage目前支持对照片的尺寸以及照片的质量进行压缩。默认情况下，CompressImage开启了尺寸与质量双重压缩，\n你可以通过CompressConfig.Builder对照片压缩后的尺寸以及质量进行相关设置。如果你想改变压缩的方式可以通过CompressConfig.Builder进行相关设置。  \n## 关于兼容性问题  \nTakePhoto是基于Android官方标准API编写的，适配了目前市场上主流的Rom。如果你在使用过程中发现了适配问题，可以提交Issues。   \n1. 为适配部分手机拍照时会回收Activity,TakePhoto在`onSaveInstanceState`与 `onCreate`做了相应的恢复处理。  \n2. 为适配部分手机拍照或从相册选择照片时屏幕方向会发生转变,从而导致拍照失败的问题，可以在AndroidManifest.xml中对使用了TakePhoto的Activity添加android:configChanges=\"orientation|keyboardHidden|screenSize\"配置。  \neg:  \n```\n<activity\n    android:name=\".MainActivity\"\n    android:screenOrientation=\"portrait\"\n    android:configChanges=\"orientation|keyboardHidden|screenSize\"\n    android:label=\"@string/app_name\" >\n    <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n    </intent-filter>\n</activity>\n```\n\n## 在项目中使用    \n为方便大家使用，现已将TakePhoto发布到JCenter(如果你对如何将项目发布到JCenter感兴趣可以参考：《[教你轻松将Android library 发布到JCenter](http://blog.csdn.net/fengyuzhengfan/article/details/51407009))》  \nGradle:  \n```groovy \n    compile 'com.jph.takephoto:takephoto_library:1.0.1'\n```\n\nMaven:  \n```groovy \n<dependency>\n  <groupId>com.jph.takephoto</groupId>\n  <artifactId>takephoto_library</artifactId>\n  <version>1.0.1</version>\n  <type>pom</type>\n</dependency>\n```  \n## 最后  \n如果你对[TakePhoto](https://github.com/crazycodeboy/TakePhoto)有更好的建议或想改造它，欢迎大家Fork and Pull requests。  \n"
  },
  {
    "path": "README.2+.md",
    "content": "## [TakePhoto](https://github.com/crazycodeboy/TakePhoto) 简介  \n`TakePhoto`是一款用于在Android设备上获取照片（拍照或从相册、文件中选择）、裁剪图片、压缩图片的开源工具库，目前最新版本[2.0.4](https://github.com/crazycodeboy/TakePhoto/)。  \n2.0以下版本及API说明，详见[TakePhoto1.0+](https://github.com/crazycodeboy/TakePhoto/blob/master/README%20-V1.0+.md)。  \n\n**V2.0**    \n\n- 支持通过相机拍照获取图片\n- 支持从相册选择图片\n- 支持从文件选择图片  \n- 支持对图片进行压缩\n- 支持对图片进行裁剪\n- 支持对裁剪及压缩参数个性化配置  \n- 提供自带裁剪工具(可选)  \n- 支持智能选取及裁剪异常处理\n- 支持因拍照Activity被回收后的自动恢复   \n\nGitHub地址： [https://github.com/crazycodeboy/TakePhoto](https://github.com/crazycodeboy/TakePhoto)\n\n## 预览图  \n\n运行效果图：    \n\n![运行效果图](https://raw.githubusercontent.com/crazycodeboy/TakePhoto/master/Screenshots/%E9%A2%84%E8%A7%88%E5%9B%BE.jpg)\n\n\n## 如何使用   \n\n### 使用TakePhoto有以下两种方式：\n**方式一：通过继承的方式**  \n1. 继承`TakePhotoActivity`、`TakePhotoFragmentActivity`、`TakePhotoFragment`三者之一。  \n2. 通过`getTakePhoto()`获取`TakePhoto`实例进行相关操作。  \n3. 重写以下方法获取结果        \n\n```java\nvoid takeSuccess(String imagePath);  \nvoid takeFail(String msg);\nvoid takeCancel();\n```  \n此方式使用简单，满足的大部分的使用需求，具体使用详见simple。如果通过继承的方式无法满足实际项目的使用，可以通过下面介绍的方式。  \n\n**方式二：通过组装的方式**  \n1. 获取TakePhoto实例`TakePhoto takePhoto=new TakePhotoImpl(getActivity(),this);`  \n2. 在 `onCreate`,`onActivityResult`,`onSaveInstanceState`方法中调用TakePhoto对用的方法。  \n3. 调用TakePhoto实例进行相关操作。  \n4. 在`TakeResultListener`相关方法中获取结果。      \n\n### 获取图片\nTakePhoto提供拍照，从相册选择，从文件中选择三种方式获取图片。    \n\n#### API:\n\n```java\n/**\n * 从文件中获取图片（不裁剪）\n */\nvoid onPickFromDocuments();\n/**\n * 从相册中获取图片（不裁剪）\n */\nvoid onPickFromGallery();\n/**\n * 从相机获取图片(不裁剪)\n * @param outPutUri 图片保存的路径\n */\nvoid onPickFromCapture(Uri outPutUri);\n```\n以上三种方式均提供对应的裁剪API，详见：[裁剪图片](https://github.com/crazycodeboy/TakePhoto#裁剪图片)。    \n**注：**  \n由于不同Android Rom厂商对系统有不同程度的定制，有可能导致某种选择图片的方式不支持，所以为了提高`TakePhoto`的兼容性，当某种选的图片的方式不支持时，`TakePhoto`会自动切换成使用另一种选择图片的方式进行图片选择。      \n\n### 裁剪图片  \n\n#### API  \n`TakePhoto`支持对图片进行裁剪，无论是拍照的照片,还是从相册、文件中选择的图片。你只需要调用`TakePhoto`的相应方法即可：  \n\n```java\n/**\n * 从相机获取图片并裁剪\n * @param outPutUri 图片裁剪之后保存的路径\n * @param options 裁剪配置             \n */\nvoid onPickFromCaptureWithCrop(Uri outPutUri, CropOptions options);\n/**\n * 从相册中获取图片并裁剪\n * @param outPutUri 图片裁剪之后保存的路径\n * @param options 裁剪配置\n */\nvoid onPickFromGalleryWithCrop(Uri outPutUri, CropOptions options);\n/**\n * 从文件中获取图片并裁剪\n * @param outPutUri 图片裁剪之后保存的路径\n * @param options 裁剪配置\n */\nvoid onPickFromDocumentsWithCrop(Uri outPutUri, CropOptions options);\n```   \n#### 对指定图片进行裁剪     \n另外，TakePhoto也支持你对指定图片进行裁剪：     \n\n```java\n/**\n * 裁剪图片\n * @param imageUri 要裁剪的图片\n * @param outPutUri 图片裁剪之后保存的路径\n * @param options 裁剪配置\n */\nvoid onCrop(Uri imageUri, Uri outPutUri, CropOptions options)throws TException;\n```\n\n#### CropOptions\n`CropOptions`是用于裁剪的配置类，通过它你可以对图片的裁剪比例，最大输出大小，以及是否使用`TakePhoto`自带的裁剪工具进行裁剪等，进行个性化配置。    \n\n**Usage:**  \n\n```java\n CropOptions cropOptions=new CropOptions.Builder().setAspectX(1).setAspectY(1).setWithOwnCrop(true).create();  \n getTakePhoto().onPickFromDocumentsWithCrop(imageUri,cropOptions);  \n //或  \n getTakePhoto().onCrop(imageUri,outPutUri,cropOptions);  \n\n```\n\n**注：**  \n由于不同Android Rom厂商对系统有不同程度的定制，有可能系统中没有自带或第三方的裁剪工具，所以为了提高`TakePhoto`的兼容性，当系统中没有自带或第三方裁剪工具时，`TakePhoto`会自动切换到使用`TakePhoto`自带的裁剪工具进行裁剪。  \n\n\n### 压缩图片\n你可以选择是否对图片进行压缩处理，你只需要告诉它你是否要启用压缩功能以及`CompressConfig`即可。  \n\n#### API\n```java\n /**\n  * 启用图片压缩\n  * @param config 压缩图片配置\n  * @param showCompressDialog 压缩时是否显示进度对话框\n  * @return\n  */\n TakePhoto onEnableCompress(CompressConfig config,boolean showCompressDialog);\n```\n\n**Usage:**  \n\n```java\ngetTakePhoto().onEnableCompress(compressConfig,true).onPickFromGalleryWithCrop(imageUri,cropOptions);\n```  \n如果你启用了图片压缩，`TakePhoto`会使用`CompressImage`对图片进行压缩处理，`CompressImage`目前支持对图片的尺寸以及图片的质量进行压缩。默认情况下，`CompressImage`开启了尺寸与质量双重压缩。  \n\n#### 对指定图片进行压缩  \n另外，你也可以对指定图片进行压缩：    \n**Usage:**  \n\n```java\nnew CompressImageImpl(compressConfig).compress(picturePath, new CompressImage.CompressListener() {\n    @Override\n    public void onCompressSuccess(String imgPath) {//图片压缩成功\n\n    }\n    @Override\n    public void onCompressFailed(String imagePath,String msg) {//图片压缩失败\n\n    }\n});\n```\n\n#### CompressConfig  \n`CompressConfig`是用于图片压缩的配置类，你可以通过`CompressConfig.Builder`对图片压缩后的尺寸以及质量进行相关设置。如果你想改变压缩的方式可以通过`CompressConfig.Builder`进行相关设置。     \n**Usage:**   \n\n```java\nCompressConfig compressConfig=new CompressConfig.Builder().setMaxSize(50*1024).setMaxPixel(800).create();\ngetTakePhoto().onEnableCompress(compressConfig,true).onPickFromGallery();\n```\n\n\n## 兼容性\n\n### TakePhoto在深度兼容性方面的测试    \n![兼容性测试报告](https://raw.githubusercontent.com/crazycodeboy/TakePhoto/master/Screenshots/%E5%85%BC%E5%AE%B9%E6%80%A7%E6%B5%8B%E8%AF%95.jpg)\n\n### 获取更高的兼容性    \n`TakePhot`o是基于Android官方标准API编写的，适配了目前市场上主流的Rom。如果你在使用过程中发现了适配问题，可以[提交Issues](https://github.com/crazycodeboy/TakePhoto/issues)。   \n1. 为适配部分手机拍照时会回收`Activity`，`TakePhoto`在`onSaveInstanceState`与 `onCreate`做了相应的恢复处理。  \n2. 为适配部分手机拍照或从相册选择图片时屏幕方向会发生转变,从而导致拍照失败的问题，可以在AndroidManifest.xml中对使用了`TakePhoto`的`Activity`添加android:configChanges=\"orientation|keyboardHidden|screenSize\"配置。  \neg:  \n\n```\n<activity\n    android:name=\".MainActivity\"\n    android:screenOrientation=\"portrait\"\n    android:configChanges=\"orientation|keyboardHidden|screenSize\"\n    android:label=\"@string/app_name\" >\n    <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n    </intent-filter>\n</activity>\n```\n\n## 在项目中使用    \n为方便大家使用，现已将TakePhoto V2.0.4发布到JCenter(如果你对如何将项目发布到JCenter感兴趣可以参考：《[教你轻松将Android library 发布到JCenter](http://blog.csdn.net/fengyuzhengfan/article/details/51407009))》  \nGradle:  \n\n```groovy\n    compile 'com.jph.takephoto:takephoto_library:2.0.4'\n```\n\nMaven:  \n\n```groovy\n<dependency>\n  <groupId>com.jph.takephoto</groupId>\n  <artifactId>takephoto_library</artifactId>\n  <version>2.0.4</version>\n  <type>pom</type>\n</dependency>\n```  \n\n## 最后  \n如果你对[TakePhoto](https://github.com/crazycodeboy/TakePhoto)有更好的建议或想改造它，欢迎大家[Fork and Pull requests](https://github.com/crazycodeboy/TakePhoto)。  \n"
  },
  {
    "path": "README.md",
    "content": "## [TakePhoto](https://github.com/crazycodeboy/TakePhoto) 简介\n\n[![PRs Welcome](https://img.shields.io/badge/PRs-Welcome-brightgreen.svg)](https://github.com/crazycodeboy/TakePhoto/pulls)\n[![Download](https://api.bintray.com/packages/crazycodeboy/maven/TakePhoto/images/download.svg) ](https://bintray.com/crazycodeboy/maven/TakePhoto/_latestVersion)\n[![GitHub release](https://img.shields.io/github/release/crazycodeboy/TakePhoto.svg?maxAge=2592000?style=flat-square)](https://github.com/crazycodeboy/TakePhoto/releases)\n[![License Apache2.0](http://img.shields.io/badge/license-Apache2.0-brightgreen.svg?style=flat)](https://raw.githubusercontent.com/crazycodeboy/TakePhoto/master/LICENSE)\n\n\n\n`TakePhoto`是一款用于在Android设备上获取照片（拍照或从相册、文件中选择）、裁剪图片、压缩图片的开源工具库，目前最新版本[4.1.0](https://github.com/crazycodeboy/TakePhoto/)。\n3.0以下版本及API说明，详见[TakePhoto2.0+](https://github.com/crazycodeboy/TakePhoto/blob/master/README.2+.md)。  \n\n>TakePhoto交流平台：QQ群：556387607（群1，未满）\n\n**V4.0**\n\n- 支持通过相机拍照获取图片\n- 支持从相册选择图片\n- 支持从文件选择图片  \n- 支持批量图片选取\n- 支持图片压缩以及批量图片压缩\n- 支持图片裁切以及批量图片裁切\n- 支持照片旋转角度自动纠正\n- 支持自动权限管理(无需关心SD卡及摄像头权限等问题)\n- 支持对裁剪及压缩参数个性化配置  \n- 提供自带裁剪工具(可选)  \n- 支持智能选取及裁剪异常处理\n- 支持因拍照Activity被回收后的自动恢复   \n- 支持Android8.1\n- +支持多种压缩工具\n- +支持多种图片选择工具\n\nGitHub地址： [https://github.com/crazycodeboy/TakePhoto](https://github.com/crazycodeboy/TakePhoto)\n## 目录\n\n- [安装说明](#安装说明)\n- [演示](#演示)\n- [使用说明](#使用说明)\n- [自定义UI](#自定义ui)\n- [API](#api)\n- [兼容性](#兼容性)\n- [贡献](#贡献)\n- [更新说明](#更新说明)\n- [最后](#混淆)\n\n## 安装说明  \n**Gradle:**  \n\n```groovy\n    compile 'com.jph.takephoto:takephoto_library:4.1.0'\n```\n\n**Maven:**  \n\n```groovy\n<dependency>\n  <groupId>com.jph.takephoto</groupId>\n  <artifactId>takephoto_library</artifactId>\n  <version>4.1.0</version>\n  <type>pom</type>\n</dependency>\n```  \n\n\n## 演示 \n\n运行效果图：    \n![预览图](https://raw.githubusercontent.com/crazycodeboy/TakePhoto/master/Screenshots/takephoto_preview.png)\n![运行效果图](https://raw.githubusercontent.com/crazycodeboy/TakePhoto/master/Screenshots/%E9%A2%84%E8%A7%88%E5%9B%BE.jpg)\n\n\n## 使用说明   \n\n### 使用TakePhoto有以下两种方式：\n**方式一：通过继承的方式**  \n1. 继承`TakePhotoActivity`、`TakePhotoFragmentActivity`、`TakePhotoFragment`三者之一。  \n2. 通过`getTakePhoto()`获取`TakePhoto`实例进行相关操作。  \n3. 重写以下方法获取结果        \n\n```java\n void takeSuccess(TResult result);\n void takeFail(TResult result,String msg);\n void takeCancel();\n```  \n此方式使用简单，满足的大部分的使用需求，具体使用详见[simple](https://github.com/crazycodeboy/TakePhoto/blob/master/simple/src/main/java/com/jph/simple/SimpleActivity.java)。如果通过继承的方式无法满足实际项目的使用，可以通过下面介绍的方式。  \n\n**方式二：通过组装的方式**  \n\n可参照：[TakePhotoActivity](https://github.com/crazycodeboy/TakePhoto/blob/master/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoActivity.java)，以下为主要步骤：  \n\n1.实现`TakePhoto.TakeResultListener,InvokeListener`接口。\n\n2.在 `onCreate`,`onActivityResult`,`onSaveInstanceState`方法中调用TakePhoto对用的方法。  \n\n3.重写`onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)`，添加如下代码。\n\n```java\n  @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        //以下代码为处理Android6.0、7.0动态权限所需\n        TPermissionType type=PermissionManager.onRequestPermissionsResult(requestCode,permissions,grantResults);\n        PermissionManager.handlePermissionsResult(this,type,invokeParam,this);\n    }\n```    \n\n4.重写`TPermissionType invoke(InvokeParam invokeParam)`方法，添加如下代码：  \n\n```java\n @Override\n    public TPermissionType invoke(InvokeParam invokeParam) {\n        TPermissionType type=PermissionManager.checkPermission(TContextWrap.of(this),invokeParam.getMethod());\n        if(TPermissionType.WAIT.equals(type)){\n            this.invokeParam=invokeParam;\n        }\n        return type;\n    }\n```\n\n5.添加如下代码获取TakePhoto实例：  \n\n```java\n   /**\n     *  获取TakePhoto实例\n     * @return\n     */\n    public TakePhoto getTakePhoto(){\n        if (takePhoto==null){\n            takePhoto= (TakePhoto) TakePhotoInvocationHandler.of(this).bind(new TakePhotoImpl(this,this));\n        }\n        return takePhoto;\n    }    \n```\n\n## 自定义UI\n\nTakePhoto不仅支持对相关参数的自定义，也支持对UI的自定义，下面就像大家介绍如何自定义TakePhoto的相册与裁剪工具的UI。\n\n### 自定义相册\n如果TakePhoto自带相册的UI不符合你应用的主题的话，你可以对它进行自定义。方法如下：   \n\n#### 自定义Toolbar \n\n在“res/layout”目录中创建一个名为“toolbar.xml”的布局文件，内容如下：   \n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v7.widget.Toolbar xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"?attr/actionBarSize\"\n    app:theme=\"@style/CustomToolbarTheme\"\n    android:background=\"#ffa352\">\n</android.support.v7.widget.Toolbar>\n```\n\n在“toolbar.xml”文件中你可以指定TakePhoto自带相册的主题以及Toolbar的背景色。\n\n#### 自定义状态栏\n\n在“res/values”目录中创建一个名为“colors.xml”的资源文件，内容如下： \n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"multiple_image_select_primaryDark\">#212121</color>\n</resources>\n```\n\n通过上述方式便可以自定义状态栏的颜色。\n\n#### 自定义提示文字\n\n在“res/values”目录的“string.xml”文件冲添加如下代码：\n\n```xml\n<resources>    \n    <string name=\"album_view\">选择图片</string>\n    <string name=\"image_view\">单击选择</string>\n    <string name=\"add\">确定</string>\n    <string name=\"selected\">已选</string>\n    <string name=\"limit_exceeded\">最多能选 %d 张</string>\n</resources>\n```\n\n重写上述代码，便可以自定义TakePhoto自带相册的提示文字。\n\n### 自定义裁切工具\n\n在“res/layout”目录中创建一个名为“crop__activity_crop.xml”与“crop__layout_done_cancel.xml”的布局文件，内容如下：  \n\n**crop__activity_crop.xml**  \n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <com.soundcloud.android.crop.CropImageView\n        android:id=\"@+id/crop_image\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentTop=\"true\"\n        android:background=\"@drawable/crop__texture\"\n        android:layout_above=\"@+id/done_cancel_bar\" />\n    <include\n        android:id=\"@+id/done_cancel_bar\"\n        android:layout_alignParentBottom=\"true\"\n        layout=\"@layout/crop__layout_done_cancel\"\n        android:layout_height=\"50dp\"\n        android:layout_width=\"match_parent\" />\n</RelativeLayout>\n```\n\n**crop__layout_done_cancel.xml**  \n\n```xml\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    style=\"@style/Crop.DoneCancelBar\">\n    <FrameLayout\n        android:id=\"@+id/btn_cancel\"\n        style=\"@style/Crop.ActionButton\">\n        <TextView style=\"@style/Crop.ActionButtonText.Cancel\" />\n    </FrameLayout>\n    <FrameLayout\n        android:id=\"@+id/btn_done\"\n        style=\"@style/Crop.ActionButton\">\n        <TextView style=\"@style/Crop.ActionButtonText.Done\" />\n    </FrameLayout>\n</LinearLayout>\n```\n\n重写上述代码，便可以自定义TakePhoto裁切工具的UI。\n\n## API\n\n### 获取图片\nTakePhoto提供拍照，从相册选择，从文件中选择三种方式获取图片。    \n\n#### API:\n\n```java\n/**\n * 从文件中获取图片（不裁剪）\n */\nvoid onPickFromDocuments();\n/**\n * 从相册中获取图片（不裁剪）\n */\nvoid onPickFromGallery();\n/**\n * 从相机获取图片(不裁剪)\n * @param outPutUri 图片保存的路径\n */\nvoid onPickFromCapture(Uri outPutUri);\n/**\n * 图片多选\n * @param limit 最多选择图片张数的限制\n **/\nvoid onPickMultiple(int limit);\n```\n以上三种方式均提供对应的裁剪API，详见：[裁剪图片](https://github.com/crazycodeboy/TakePhoto#裁剪图片)。    \n**注：**  \n由于不同Android Rom厂商对系统有不同程度的定制，有可能导致某种选择图片的方式不支持，所以为了提高`TakePhoto`的兼容性，当某种选的图片的方式不支持时，`TakePhoto`会自动切换成使用另一种选择图片的方式进行图片选择。      \n\n### 裁剪图片  \n\n#### API  \n`TakePhoto`支持对图片进行裁剪，无论是拍照的照片,还是从相册、文件中选择的图片。你只需要调用`TakePhoto`的相应方法即可：  \n\n```java\n/**\n * 从相机获取图片并裁剪\n * @param outPutUri 图片裁剪之后保存的路径\n * @param options 裁剪配置             \n */\nvoid onPickFromCaptureWithCrop(Uri outPutUri, CropOptions options);\n/**\n * 从相册中获取图片并裁剪\n * @param outPutUri 图片裁剪之后保存的路径\n * @param options 裁剪配置\n */\nvoid onPickFromGalleryWithCrop(Uri outPutUri, CropOptions options);\n/**\n * 从文件中获取图片并裁剪\n * @param outPutUri 图片裁剪之后保存的路径\n * @param options 裁剪配置\n */\nvoid onPickFromDocumentsWithCrop(Uri outPutUri, CropOptions options);\n/**\n * 图片多选，并裁切\n * @param limit 最多选择图片张数的限制\n * @param options  裁剪配置\n * */\nvoid onPickMultipleWithCrop(int limit, CropOptions options);\n```   \n#### 对指定图片进行裁剪     \n另外，TakePhoto也支持你对指定图片进行裁剪：     \n\n```java\n/**\n * 裁剪图片\n * @param imageUri 要裁剪的图片\n * @param outPutUri 图片裁剪之后保存的路径\n * @param options 裁剪配置\n */\nvoid onCrop(Uri imageUri, Uri outPutUri, CropOptions options)throws TException;\n/**\n * 裁剪多张图片\n * @param multipleCrop 要裁切的图片的路径以及输出路径\n * @param options 裁剪配置\n */\nvoid onCrop(MultipleCrop multipleCrop, CropOptions options)throws TException;\n```\n\n#### CropOptions\n`CropOptions`是用于裁剪的配置类，通过它你可以对图片的裁剪比例，最大输出大小，以及是否使用`TakePhoto`自带的裁剪工具进行裁剪等，进行个性化配置。    \n\n**Usage:**  \n\n```java\n CropOptions cropOptions=new CropOptions.Builder().setAspectX(1).setAspectY(1).setWithOwnCrop(true).create();  \n getTakePhoto().onPickFromDocumentsWithCrop(imageUri,cropOptions);  \n //或  \n getTakePhoto().onCrop(imageUri,outPutUri,cropOptions);  \n\n```\n\n**注：**  \n由于不同Android Rom厂商对系统有不同程度的定制，有可能系统中没有自带或第三方的裁剪工具，所以为了提高`TakePhoto`的兼容性，当系统中没有自带或第三方裁剪工具时，`TakePhoto`会自动切换到使用`TakePhoto`自带的裁剪工具进行裁剪。  \n\n>另外TakePhoto4.0+支持指定使用TakePhoto自带相册,如：`takePhoto.setTakePhotoOptions(new TakePhotoOptions.Builder().setWithOwnGallery(true).create());`\n详情可参考:[Demo](https://github.com/crazycodeboy/TakePhoto/blob/master/simple/src/main/java/com/jph/simple/CustomHelper.java)\n\n### 压缩图片\n你可以选择是否对图片进行压缩处理，你只需要告诉它你是否要启用压缩功能以及`CompressConfig`即可。  \n\n#### API\n```java\n /**\n  * 启用图片压缩\n  * @param config 压缩图片配置\n  * @param showCompressDialog 压缩时是否显示进度对话框\n  * @return\n  */\n void onEnableCompress(CompressConfig config,boolean showCompressDialog);\n```\n\n**Usage:**  \n\n```java\nTakePhoto takePhoto=getTakePhoto();\ntakePhoto.onEnableCompress(compressConfig,true);\ntakePhoto.onPickFromGallery();\n```  \n如果你启用了图片压缩，`TakePhoto`会使用`CompressImage`对图片进行压缩处理，`CompressImage`目前支持对图片的尺寸以及图片的质量进行压缩。默认情况下，`CompressImage`开启了尺寸与质量双重压缩。  \n\n#### 对指定图片进行压缩  \n另外，你也可以对指定图片进行压缩：    \n**Usage:**  \n\n```java\nnew CompressImageImpl(compressConfig,result.getImages(), new CompressImage.CompressListener() {\n    @Override\n    public void onCompressSuccess(ArrayList<TImage> images) {\n        //图片压缩成功\n    }\n    @Override\n    public void onCompressFailed(ArrayList<TImage> images, String msg) {\n        //图片压缩失败\n    }\n}).compress();\n```\n\n#### CompressConfig  \n`CompressConfig`是用于图片压缩的配置类，你可以通过`CompressConfig.Builder`对图片压缩后的尺寸以及质量进行相关设置。如果你想改变压缩的方式可以通过`CompressConfig.Builder`进行相关设置。     \n**Usage:**   \n\n```java\nCompressConfig compressConfig=new CompressConfig.Builder().setMaxSize(50*1024).setMaxPixel(800).create();\n```\n#### 指定压缩工具\n\n#### 使用TakePhoto压缩工具进行压缩： \n\n```\nCompressConfig config=new CompressConfig.Builder()\n                    .setMaxSize(maxSize)\n                    .setMaxPixel(width>=height? width:height)\n                    .create();\ntakePhoto.onEnableCompress(config,showProgressBar);\n```\n\n#### 使用Luban进行压缩： \n```\nLubanOptions option=new LubanOptions.Builder()\n                    .setGear(Luban.CUSTOM_GEAR)\n                    .setMaxHeight(height)\n                    .setMaxWidth(width)\n                    .setMaxSize(maxSize)\n                    .create();\nCompressConfig config=CompressConfig.ofLuban(option);\ntakePhoto.onEnableCompress(config,showProgressBar);\n```\n\n>详情可参考Demo:[CustomHelper.java](https://github.com/crazycodeboy/TakePhoto/blob/master/simple/src/main/java/com/jph/simple/CustomHelper.java)\n\n\n## 兼容性\n\n### Android6.0\n由于Android6.0新增了\"运行时权限控制(Runtime Permissions)\"，为了应对这一改变，TakePhoto加入和自动权限管理，当TakePhoto检测到需要权限时，TakePhoto会自动申请权限，所以小伙伴们不用担心权限的使用问题。\n\n### Android7.0  \n\n在Android N中，Android 框架执行了 StrictMode，应用间共享文件和以前也有所区别。为了适配Android7.0的改变，同时也为了方便大家使用TakePhoto，TakePhoto会自动根据手机的Android版本自行适配，小伙伴们依旧可以向TakePhoto传递`Uri imageUri = Uri.fromFile(file);`类型的Uri而不用担心兼容性问题。\n\n### TakePhoto在深度兼容性方面的测试    \n![兼容性测试报告](https://raw.githubusercontent.com/crazycodeboy/TakePhoto/master/Screenshots/%E5%85%BC%E5%AE%B9%E6%80%A7%E6%B5%8B%E8%AF%95.jpg)\n\n### 获取更高的兼容性    \n`TakePhot`o是基于Android官方标准API编写的，适配了目前市场上主流的Rom。如果你在使用过程中发现了适配问题，可以[提交Issues](https://github.com/crazycodeboy/TakePhoto/issues)。   \n1. 为适配部分手机拍照时会回收`Activity`，`TakePhoto`在`onSaveInstanceState`与 `onCreate`做了相应的恢复处理。  \n2. 为适配部分手机拍照或从相册选择图片时屏幕方向会发生转变,从而导致拍照失败的问题，可以在AndroidManifest.xml中对使用了`TakePhoto`的`Activity`添加android:configChanges=\"orientation|keyboardHidden|screenSize\"配置。  \neg:  \n\n```\n<activity\n    android:name=\".MainActivity\"\n    android:screenOrientation=\"portrait\"\n    android:configChanges=\"orientation|keyboardHidden|screenSize\"\n    android:label=\"@string/app_name\" >\n    <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n    </intent-filter>\n</activity>\n```\n\n## 贡献  \n如果你在使用TakePhoto中遇到任何问题可以提[Issues](https://github.com/crazycodeboy/TakePhoto/issues)出来。另外欢迎大家为TakePhoto贡献智慧，欢迎大家[Fork and Pull requests](https://github.com/crazycodeboy/TakePhoto)。     \n\n## 更新说明\n\nv4.1.0(2018/4/2)\n-----------------\n\n1. Upgrade glide to 4.6.1；\n2. Upgrade  buildToolsVersion & targetSdkVersion ；\n3. rename package name ;\n\nv4.0.3(2017/1/18)\n-----------------\n**Bugfixes**\n\n1. Fixed bug and add new features([`62a6725`](https://github.com/crazycodeboy/TakePhoto/commit/62a6725a99118ec0ce0f4cf1cd76b2ba70e21745))-@[Yanqilong](https://github.com/Yanqilong)\n2. fix 鲁班压缩出现路径重复([`a0a64a59`](https://github.com/crazycodeboy/TakePhoto/commit/a0a64a59762fa8554eb46b6ec544f70a5d46f551))-@[namezhouyu](https://github.com/namezhouyu)\n\n\nv4.0.2(2016/11/28)\n------------------\n1. 压缩成功后返回原图路径(originalPath), 以便用户可以自行处理原图。\n2. 压缩成功后压缩路径path改为compressPath。\n3. 压缩成功后返回图片来源类型，现在分CAMERA, OTHER两种。\n4. 用户可以配置CompressConfig.enableReserveRaw(boolean)方法，ture保留原图，false删除原图，当且仅当类型为CAMERA此配置才有效\n5. 纠正拍照旋转角度功能改为可选\n\n## 最后\n\n### 关于代码混淆\n如果你的项目中启用了代码混淆，可在混淆规则文件(如：proguard-rules.pro)中添加如下代码：   \n\n```\n-keep class com.jph.takephoto.** { *; }\n-dontwarn com.jph.takephoto.**\n\n-keep class com.darsh.multipleimageselect.** { *; }\n-dontwarn com.darsh.multipleimageselect.**\n\n-keep class com.soundcloud.android.crop.** { *; }\n-dontwarn com.soundcloud.android.crop.**\n\n```\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n        google()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.1.0'\n//        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'\n//        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n        google()\n    }\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Apr 02 19:53:50 CST 2018\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-4.4-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':takephoto_library', ':simple'\n"
  },
  {
    "path": "simple/.gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n### Android template\n# Built application files\n*.apk\n*.ap_\n\n# Files for the Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\n\n# Gradle files\n.gradle/\nbuild/\n/*/build/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n\n### JetBrains template\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion\n\n*.iml\n\n## Directory-based project format:\n.idea/\n# if you remove the above rule, at least ignore the following:\n\n# User-specific stuff:\n# .idea/workspace.xml\n# .idea/tasks.xml\n# .idea/dictionaries\n\n# Sensitive or high-churn files:\n# .idea/dataSources.ids\n# .idea/dataSources.xml\n# .idea/sqlDataSources.xml\n# .idea/dynamic.xml\n# .idea/uiDesigner.xml\n\n# Gradle:\n# .idea/gradle.xml\n# .idea/libraries\n\n# Mongo Explorer plugin:\n# .idea/mongoSettings.xml\n\n## File-based project format:\n*.ipr\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\n\n\n### Gradle template\n.gradle\n\n# Ignore Gradle GUI config\ngradle-app.setting\n\n# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)\n!gradle-wrapper.jar\n\n\n"
  },
  {
    "path": "simple/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion '26.0.3'\n\n    defaultConfig {\n        applicationId \"org.devio.simple\"\n        minSdkVersion 14\n        targetSdkVersion 26\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':takephoto_library')\n}\n"
  },
  {
    "path": "simple/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\Program Files\\adt-bundle-windows-x86_64-20140702\\sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n-dontwarn android.support.**\n-keep class android.support.** { *; }\n\n\n-keepattributes InnerClasses\n-dontoptimize"
  },
  {
    "path": "simple/src/androidTest/java/org/devio/simple/ApplicationTest.java",
    "content": "package org.devio.simple;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "simple/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"org.devio.simple\" >\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/AppTheme\" >\n        <activity\n            android:name=\".MainActivity\"\n            android:screenOrientation=\"portrait\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:label=\"@string/app_name\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity android:name=\".SimpleActivity\"\n            android:screenOrientation=\"portrait\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"></activity>\n        <activity android:name=\".SimpleFragmentActivity\"\n            android:screenOrientation=\"portrait\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"></activity>\n        <activity android:name=\".ResultActivity\"></activity>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "simple/src/main/java/org/devio/simple/CustomHelper.java",
    "content": "package org.devio.simple;\n\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.view.View;\nimport android.widget.EditText;\nimport android.widget.RadioGroup;\n\nimport org.devio.takephoto.app.TakePhoto;\nimport org.devio.takephoto.compress.CompressConfig;\nimport org.devio.takephoto.model.CropOptions;\nimport org.devio.takephoto.model.LubanOptions;\nimport org.devio.takephoto.model.TakePhotoOptions;\n\nimport java.io.File;\n\n\n/**\n * - 支持通过相机拍照获取图片\n * - 支持从相册选择图片\n * - 支持从文件选择图片\n * - 支持多图选择\n * - 支持批量图片裁切\n * - 支持批量图片压缩\n * - 支持对图片进行压缩\n * - 支持对图片进行裁剪\n * - 支持对裁剪及压缩参数自定义\n * - 提供自带裁剪工具(可选)\n * - 支持智能选取及裁剪异常处理\n * - 支持因拍照Activity被回收后的自动恢复\n * Author: crazycodeboy\n * Date: 2016/9/21 0007 20:10\n * Version:4.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class CustomHelper {\n    private View rootView;\n    private RadioGroup rgCrop, rgCompress, rgFrom, rgCropSize, rgCropTool, rgShowProgressBar, rgPickTool, rgCompressTool, rgCorrectTool,\n        rgRawFile;\n    private EditText etCropHeight, etCropWidth, etLimit, etSize, etHeightPx, etWidthPx;\n\n    public static CustomHelper of(View rootView) {\n        return new CustomHelper(rootView);\n    }\n\n    private CustomHelper(View rootView) {\n        this.rootView = rootView;\n        init();\n    }\n\n    private void init() {\n        rgCrop = (RadioGroup) rootView.findViewById(R.id.rgCrop);\n        rgCompress = (RadioGroup) rootView.findViewById(R.id.rgCompress);\n        rgCompressTool = (RadioGroup) rootView.findViewById(R.id.rgCompressTool);\n        rgCropSize = (RadioGroup) rootView.findViewById(R.id.rgCropSize);\n        rgFrom = (RadioGroup) rootView.findViewById(R.id.rgFrom);\n        rgPickTool = (RadioGroup) rootView.findViewById(R.id.rgPickTool);\n        rgRawFile = (RadioGroup) rootView.findViewById(R.id.rgRawFile);\n        rgCorrectTool = (RadioGroup) rootView.findViewById(R.id.rgCorrectTool);\n        rgShowProgressBar = (RadioGroup) rootView.findViewById(R.id.rgShowProgressBar);\n        rgCropTool = (RadioGroup) rootView.findViewById(R.id.rgCropTool);\n        etCropHeight = (EditText) rootView.findViewById(R.id.etCropHeight);\n        etCropWidth = (EditText) rootView.findViewById(R.id.etCropWidth);\n        etLimit = (EditText) rootView.findViewById(R.id.etLimit);\n        etSize = (EditText) rootView.findViewById(R.id.etSize);\n        etHeightPx = (EditText) rootView.findViewById(R.id.etHeightPx);\n        etWidthPx = (EditText) rootView.findViewById(R.id.etWidthPx);\n\n\n\n    }\n\n    public void onClick(View view, TakePhoto takePhoto) {\n        File file = new File(Environment.getExternalStorageDirectory(), \"/temp/\" + System.currentTimeMillis() + \".jpg\");\n        if (!file.getParentFile().exists()) {\n            file.getParentFile().mkdirs();\n        }\n        Uri imageUri = Uri.fromFile(file);\n\n        configCompress(takePhoto);\n        configTakePhotoOption(takePhoto);\n        switch (view.getId()) {\n            case R.id.btnPickBySelect:\n                int limit = Integer.parseInt(etLimit.getText().toString());\n                if (limit > 1) {\n                    if (rgCrop.getCheckedRadioButtonId() == R.id.rbCropYes) {\n                        takePhoto.onPickMultipleWithCrop(limit, getCropOptions());\n                    } else {\n                        takePhoto.onPickMultiple(limit);\n                    }\n                    return;\n                }\n                if (rgFrom.getCheckedRadioButtonId() == R.id.rbFile) {\n                    if (rgCrop.getCheckedRadioButtonId() == R.id.rbCropYes) {\n                        takePhoto.onPickFromDocumentsWithCrop(imageUri, getCropOptions());\n                    } else {\n                        takePhoto.onPickFromDocuments();\n                    }\n                    return;\n                } else {\n                    if (rgCrop.getCheckedRadioButtonId() == R.id.rbCropYes) {\n                        takePhoto.onPickFromGalleryWithCrop(imageUri, getCropOptions());\n                    } else {\n                        takePhoto.onPickFromGallery();\n                    }\n                }\n                break;\n            case R.id.btnPickByTake:\n                if (rgCrop.getCheckedRadioButtonId() == R.id.rbCropYes) {\n                    takePhoto.onPickFromCaptureWithCrop(imageUri, getCropOptions());\n                } else {\n                    takePhoto.onPickFromCapture(imageUri);\n                }\n                break;\n            default:\n                break;\n        }\n    }\n\n    private void configTakePhotoOption(TakePhoto takePhoto) {\n        TakePhotoOptions.Builder builder = new TakePhotoOptions.Builder();\n        if (rgPickTool.getCheckedRadioButtonId() == R.id.rbPickWithOwn) {\n            builder.setWithOwnGallery(true);\n        }\n        if (rgCorrectTool.getCheckedRadioButtonId() == R.id.rbCorrectYes) {\n            builder.setCorrectImage(true);\n        }\n        takePhoto.setTakePhotoOptions(builder.create());\n\n    }\n\n    private void configCompress(TakePhoto takePhoto) {\n        if (rgCompress.getCheckedRadioButtonId() != R.id.rbCompressYes) {\n            takePhoto.onEnableCompress(null, false);\n            return;\n        }\n        int maxSize = Integer.parseInt(etSize.getText().toString());\n        int width = Integer.parseInt(etCropWidth.getText().toString());\n        int height = Integer.parseInt(etHeightPx.getText().toString());\n        boolean showProgressBar = rgShowProgressBar.getCheckedRadioButtonId() == R.id.rbShowYes ? true : false;\n        boolean enableRawFile = rgRawFile.getCheckedRadioButtonId() == R.id.rbRawYes ? true : false;\n        CompressConfig config;\n        if (rgCompressTool.getCheckedRadioButtonId() == R.id.rbCompressWithOwn) {\n            config = new CompressConfig.Builder().setMaxSize(maxSize)\n                .setMaxPixel(width >= height ? width : height)\n                .enableReserveRaw(enableRawFile)\n                .create();\n        } else {\n            LubanOptions option = new LubanOptions.Builder().setMaxHeight(height).setMaxWidth(width).setMaxSize(maxSize).create();\n            config = CompressConfig.ofLuban(option);\n            config.enableReserveRaw(enableRawFile);\n        }\n        takePhoto.onEnableCompress(config, showProgressBar);\n\n\n    }\n\n    private CropOptions getCropOptions() {\n        if (rgCrop.getCheckedRadioButtonId() != R.id.rbCropYes) {\n            return null;\n        }\n        int height = Integer.parseInt(etCropHeight.getText().toString());\n        int width = Integer.parseInt(etCropWidth.getText().toString());\n        boolean withWonCrop = rgCropTool.getCheckedRadioButtonId() == R.id.rbCropOwn ? true : false;\n\n        CropOptions.Builder builder = new CropOptions.Builder();\n\n        if (rgCropSize.getCheckedRadioButtonId() == R.id.rbAspect) {\n            builder.setAspectX(width).setAspectY(height);\n        } else {\n            builder.setOutputX(width).setOutputY(height);\n        }\n        builder.setWithOwnCrop(withWonCrop);\n        return builder.create();\n    }\n\n}\n"
  },
  {
    "path": "simple/src/main/java/org/devio/simple/MainActivity.java",
    "content": "package org.devio.simple;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.View;\n\n\n/**\n * - 支持通过相机拍照获取图片\n * - 支持从相册选择图片\n * - 支持从文件选择图片\n * - 支持多图选择\n * - 支持批量图片裁切\n * - 支持批量图片压缩\n * - 支持对图片进行压缩\n * - 支持对图片进行裁剪\n * - 支持对裁剪及压缩参数自定义\n * - 提供自带裁剪工具(可选)\n * - 支持智能选取及裁剪异常处理\n * - 支持因拍照Activity被回收后的自动恢复\n * Author: crazycodeboy\n * Date: 2016/9/21 0007 20:10\n * Version:4.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class MainActivity extends Activity implements View.OnClickListener {\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main_layout);\n    }\n\n    @Override\n    public void onClick(View view) {\n        switch (view.getId()) {\n            case R.id.btnTakePhotoActivity:\n                startActivity(new Intent(this, SimpleActivity.class));\n                break;\n            case R.id.btnTakePhotoFragment:\n                startActivity(new Intent(this, SimpleFragmentActivity.class));\n                break;\n            default:\n        }\n    }\n}\n"
  },
  {
    "path": "simple/src/main/java/org/devio/simple/ResultActivity.java",
    "content": "package org.devio.simple;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\n\nimport com.bumptech.glide.Glide;\n\nimport org.devio.takephoto.model.TImage;\n\nimport java.io.File;\nimport java.util.ArrayList;\n\n\n/**\n * - 支持通过相机拍照获取图片\n * - 支持从相册选择图片\n * - 支持从文件选择图片\n * - 支持多图选择\n * - 支持批量图片裁切\n * - 支持批量图片压缩\n * - 支持对图片进行压缩\n * - 支持对图片进行裁剪\n * - 支持对裁剪及压缩参数自定义\n * - 提供自带裁剪工具(可选)\n * - 支持智能选取及裁剪异常处理\n * - 支持因拍照Activity被回收后的自动恢复\n * Author: crazycodeboy\n * Date: 2016/9/21 0007 20:10\n * Version:4.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class ResultActivity extends Activity {\n    ArrayList<TImage> images;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_result_layout);\n        images = (ArrayList<TImage>) getIntent().getSerializableExtra(\"images\");\n        showImg();\n    }\n\n    private void showImg() {\n        LinearLayout linearLayout = (LinearLayout) findViewById(R.id.llImages);\n        for (int i = 0, j = images.size(); i < j - 1; i += 2) {\n            View view = LayoutInflater.from(this).inflate(R.layout.image_show, null);\n            ImageView imageView1 = (ImageView) view.findViewById(R.id.imgShow1);\n            ImageView imageView2 = (ImageView) view.findViewById(R.id.imgShow2);\n            Glide.with(this).load(new File(images.get(i).getCompressPath())).into(imageView1);\n            Glide.with(this).load(new File(images.get(i + 1).getCompressPath())).into(imageView2);\n            linearLayout.addView(view);\n        }\n        if (images.size() % 2 == 1) {\n            View view = LayoutInflater.from(this).inflate(R.layout.image_show, null);\n            ImageView imageView1 = (ImageView) view.findViewById(R.id.imgShow1);\n            Glide.with(this).load(new File(images.get(images.size() - 1).getCompressPath())).into(imageView1);\n            linearLayout.addView(view);\n        }\n\n    }\n}\n"
  },
  {
    "path": "simple/src/main/java/org/devio/simple/SimpleActivity.java",
    "content": "package org.devio.simple;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\n\nimport org.devio.takephoto.app.TakePhotoActivity;\nimport org.devio.takephoto.model.TImage;\nimport org.devio.takephoto.model.TResult;\n\nimport java.util.ArrayList;\n\n\n/**\n * - 支持通过相机拍照获取图片\n * - 支持从相册选择图片\n * - 支持从文件选择图片\n * - 支持多图选择\n * - 支持批量图片裁切\n * - 支持批量图片压缩\n * - 支持对图片进行压缩\n * - 支持对图片进行裁剪\n * - 支持对裁剪及压缩参数自定义\n * - 提供自带裁剪工具(可选)\n * - 支持智能选取及裁剪异常处理\n * - 支持因拍照Activity被回收后的自动恢复\n * Author: crazycodeboy\n * Date: 2016/9/21 0007 20:10\n * Version:4.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class SimpleActivity extends TakePhotoActivity {\n    private CustomHelper customHelper;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        View contentView = LayoutInflater.from(this).inflate(R.layout.common_layout, null);\n        setContentView(contentView);\n        customHelper = CustomHelper.of(contentView);\n    }\n\n    public void onClick(View view) {\n        customHelper.onClick(view, getTakePhoto());\n    }\n\n    @Override\n    public void takeCancel() {\n        super.takeCancel();\n    }\n\n    @Override\n    public void takeFail(TResult result, String msg) {\n        super.takeFail(result, msg);\n    }\n\n    @Override\n    public void takeSuccess(TResult result) {\n        super.takeSuccess(result);\n        showImg(result.getImages());\n    }\n\n    private void showImg(ArrayList<TImage> images) {\n        Intent intent = new Intent(this, ResultActivity.class);\n        intent.putExtra(\"images\", images);\n        startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "simple/src/main/java/org/devio/simple/SimpleFragment.java",
    "content": "package org.devio.simple;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport org.devio.takephoto.app.TakePhotoFragment;\nimport org.devio.takephoto.model.TImage;\nimport org.devio.takephoto.model.TResult;\n\nimport java.util.ArrayList;\n\n\n/**\n * - 支持通过相机拍照获取图片\n * - 支持从相册选择图片\n * - 支持从文件选择图片\n * - 支持多图选择\n * - 支持批量图片裁切\n * - 支持批量图片压缩\n * - 支持对图片进行压缩\n * - 支持对图片进行裁剪\n * - 支持对裁剪及压缩参数自定义\n * - 提供自带裁剪工具(可选)\n * - 支持智能选取及裁剪异常处理\n * - 支持因拍照Activity被回收后的自动恢复\n * Author: crazycodeboy\n * Date: 2016/9/21 0007 20:10\n * Version:4.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class SimpleFragment extends TakePhotoFragment {\n    private CustomHelper customHelper;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        View view = inflater.inflate(R.layout.common_layout, null);\n        customHelper = CustomHelper.of(view);\n        return view;\n    }\n\n    public void onClick(View view) {\n        customHelper.onClick(view, getTakePhoto());\n    }\n\n    @Override\n    public void takeCancel() {\n        super.takeCancel();\n    }\n\n    @Override\n    public void takeFail(TResult result, String msg) {\n        super.takeFail(result, msg);\n    }\n\n    @Override\n    public void takeSuccess(TResult result) {\n        super.takeSuccess(result);\n        showImg(result.getImages());\n    }\n\n    private void showImg(ArrayList<TImage> images) {\n        Intent intent = new Intent(getContext(), ResultActivity.class);\n        intent.putExtra(\"images\", images);\n        startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "simple/src/main/java/org/devio/simple/SimpleFragmentActivity.java",
    "content": "package org.devio.simple;\n\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.FragmentActivity;\nimport android.support.v4.app.FragmentTransaction;\nimport android.view.View;\n\n\n/**\n * - 支持通过相机拍照获取图片\n * - 支持从相册选择图片\n * - 支持从文件选择图片\n * - 支持多图选择\n * - 支持批量图片裁切\n * - 支持批量图片压缩\n * - 支持对图片进行压缩\n * - 支持对图片进行裁剪\n * - 支持对裁剪及压缩参数自定义\n * - 提供自带裁剪工具(可选)\n * - 支持智能选取及裁剪异常处理\n * - 支持因拍照Activity被回收后的自动恢复\n * Author: crazycodeboy\n * Date: 2016/9/21 0007 20:10\n * Version:4.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class SimpleFragmentActivity extends FragmentActivity {\n    SimpleFragment fragment;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.simple_fragment_layout);\n        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n        transaction.add(R.id.fragment1, fragment = new SimpleFragment(), \"test\");\n        transaction.commit();\n    }\n\n    public void onClick(View v) {\n        fragment.onClick(v);\n    }\n}\n"
  },
  {
    "path": "simple/src/main/res/layout/activity_main_layout.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    >\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\">\n        <Button\n            android:id=\"@+id/btnTakePhotoActivity\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:onClick=\"onClick\"\n            android:layout_margin=\"5dp\"\n            android:text=\"在Activity中使用\" />\n    </LinearLayout>\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\">\n\n        <Button\n            android:id=\"@+id/btnTakePhotoFragment\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:onClick=\"onClick\"\n            android:layout_margin=\"5dp\"\n            android:text=\"在Fragment中使用\" />\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "simple/src/main/res/layout/activity_result_layout.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    >\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <LinearLayout\n            android:id=\"@+id/llImages\"\n            android:orientation=\"vertical\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"/>\n    </ScrollView>\n</LinearLayout>"
  },
  {
    "path": "simple/src/main/res/layout/common_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"10dp\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"裁切配置：\"\n                android:textColor=\"@android:color/black\"\n                android:textSize=\"18sp\" />\n\n            <View\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"1px\"\n                android:background=\"@android:color/darker_gray\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"是否裁切：\" />\n\n                <RadioGroup\n                    android:id=\"@+id/rgCrop\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <RadioButton\n                        android:id=\"@+id/rbCropYes\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_horizontal\"\n                        android:checked=\"true\"\n                        android:text=\"是\" />\n\n                    <RadioButton\n                        android:id=\"@+id/rbCropNo\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"否\" />\n                </RadioGroup>\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"裁切工具：\" />\n\n                <RadioGroup\n                    android:id=\"@+id/rgCropTool\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <RadioButton\n                        android:id=\"@+id/rbCropByOther\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_horizontal\"\n                        android:checked=\"true\"\n                        android:text=\"第三方\" />\n\n                    <RadioButton\n                        android:id=\"@+id/rbCropOwn\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"TakePhoto自带\" />\n                </RadioGroup>\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"尺寸/比例：\" />\n\n                <RadioGroup\n                    android:id=\"@+id/rgCropSize\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <RadioButton\n                        android:id=\"@+id/rbOutPut\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_horizontal\"\n                        android:checked=\"true\"\n                        android:text=\"宽x高\" />\n\n                    <RadioButton\n                        android:id=\"@+id/rbAspect\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"宽/高\" />\n                </RadioGroup>\n\n                <EditText\n                    android:id=\"@+id/etCropWidth\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginLeft=\"10dp\"\n                    android:inputType=\"number\"\n                    android:minWidth=\"42dp\"\n                    android:text=\"800\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"x\" />\n\n                <EditText\n                    android:id=\"@+id/etCropHeight\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:minWidth=\"42dp\"\n                    android:text=\"800\" />\n            </LinearLayout>\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"10dp\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"压缩配置：\"\n                android:textColor=\"@android:color/black\"\n                android:textSize=\"18sp\" />\n\n            <View\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"1px\"\n                android:background=\"@android:color/darker_gray\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"压缩工具：\" />\n\n                <RadioGroup\n                    android:id=\"@+id/rgCompressTool\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <RadioButton\n                        android:id=\"@+id/rbCompressWithOwn\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_horizontal\"\n                        android:checked=\"true\"\n                        android:text=\"自带\" />\n\n                    <RadioButton\n                        android:id=\"@+id/rbCompressWithLuban\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"Luban\" />\n                </RadioGroup>\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"是否压缩：\" />\n\n                <RadioGroup\n                    android:id=\"@+id/rgCompress\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <RadioButton\n                        android:id=\"@+id/rbCompressYes\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_horizontal\"\n                        android:checked=\"true\"\n                        android:text=\"是\" />\n\n                    <RadioButton\n                        android:id=\"@+id/rbCompressNo\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"否\" />\n                </RadioGroup>\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"显示压缩进度条：\" />\n\n                <RadioGroup\n                    android:id=\"@+id/rgShowProgressBar\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <RadioButton\n                        android:id=\"@+id/rbShowYes\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_horizontal\"\n                        android:checked=\"true\"\n                        android:text=\"是\" />\n\n                    <RadioButton\n                        android:id=\"@+id/rbShowNo\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"否\" />\n                </RadioGroup>\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"大小不超过：\" />\n\n                <EditText\n                    android:id=\"@+id/etSize\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"number\"\n                    android:minWidth=\"42dp\"\n                    android:text=\"102400\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"B\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginLeft=\"20dp\"\n                    android:text=\"宽：\" />\n\n                <EditText\n                    android:id=\"@+id/etWidthPx\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"number\"\n                    android:minWidth=\"42dp\"\n                    android:text=\"800\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginLeft=\"20dp\"\n                    android:text=\"高：\" />\n\n                <EditText\n                    android:id=\"@+id/etHeightPx\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"number\"\n                    android:minWidth=\"42dp\"\n                    android:text=\"800\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"px\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"10dp\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"选择图片配置：\"\n                android:textColor=\"@android:color/black\"\n                android:textSize=\"18sp\" />\n\n            <View\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"1px\"\n                android:background=\"@android:color/darker_gray\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_vertical\"\n                    android:orientation=\"horizontal\">\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"使用TakePhoto自带相册：\" />\n\n                    <RadioGroup\n                        android:id=\"@+id/rgPickTool\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:orientation=\"horizontal\">\n\n                        <RadioButton\n                            android:id=\"@+id/rbPickWithOwn\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:layout_gravity=\"center_horizontal\"\n                            android:checked=\"true\"\n                            android:text=\"是\" />\n\n                        <RadioButton\n                            android:id=\"@+id/rbPickWithOther\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:text=\"否\" />\n                    </RadioGroup>\n                </LinearLayout>\n\n                <TextView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:text=\"提示：选择多张图片时会自动切换到TakePhoto自带相册\"\n                    android:textColor=\"#FF0000\"\n                    android:textSize=\"12sp\" />\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"vertical\">\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:gravity=\"center_vertical\"\n                        android:orientation=\"horizontal\">\n\n                        <TextView\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:text=\"最多选择：\" />\n\n                        <EditText\n                            android:id=\"@+id/etLimit\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:inputType=\"number\"\n                            android:minWidth=\"30dp\"\n                            android:text=\"5\" />\n\n                        <TextView\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:text=\"张\" />\n                    </LinearLayout>\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:gravity=\"center_vertical\"\n                        android:orientation=\"horizontal\">\n\n                        <TextView\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:text=\"从哪选择：\" />\n\n                        <RadioGroup\n                            android:id=\"@+id/rgFrom\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:orientation=\"horizontal\">\n\n                            <RadioButton\n                                android:id=\"@+id/rbGallery\"\n                                android:layout_width=\"wrap_content\"\n                                android:layout_height=\"wrap_content\"\n                                android:layout_gravity=\"center_horizontal\"\n                                android:checked=\"true\"\n                                android:text=\"从相册\" />\n\n                            <RadioButton\n                                android:id=\"@+id/rbFile\"\n                                android:layout_width=\"wrap_content\"\n                                android:layout_height=\"wrap_content\"\n                                android:text=\"从文件\" />\n                        </RadioGroup>\n                    </LinearLayout>\n                </LinearLayout>\n            </LinearLayout>\n\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"其他配置：\"\n                android:textColor=\"@android:color/black\"\n                android:textSize=\"18sp\" />\n\n            <View\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"1px\"\n                android:background=\"@android:color/darker_gray\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_vertical\"\n                    android:orientation=\"horizontal\">\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"纠正拍照的照片旋转角度：\" />\n\n                    <RadioGroup\n                        android:id=\"@+id/rgCorrectTool\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:orientation=\"horizontal\">\n\n                        <RadioButton\n                            android:id=\"@+id/rbCorrectYes\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:layout_gravity=\"center_horizontal\"\n                            android:text=\"是\" />\n\n                        <RadioButton\n                            android:id=\"@+id/rbCorrectNo\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:checked=\"true\"\n                            android:text=\"否\" />\n                    </RadioGroup>\n                </LinearLayout>\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_vertical\"\n                    android:orientation=\"horizontal\">\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"拍照压缩后是否保存原图：\" />\n\n                    <RadioGroup\n                        android:id=\"@+id/rgRawFile\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:orientation=\"horizontal\">\n\n                        <RadioButton\n                            android:id=\"@+id/rbRawYes\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:layout_gravity=\"center_horizontal\"\n                            android:checked=\"true\"\n                            android:text=\"是\" />\n\n                        <RadioButton\n                            android:id=\"@+id/rbRawNo\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:text=\"否\" />\n                    </RadioGroup>\n                </LinearLayout>\n\n            </LinearLayout>\n\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"10dp\"\n                android:orientation=\"horizontal\">\n\n                <Button\n                    android:id=\"@+id/btnPickByTake\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:onClick=\"onClick\"\n                    android:text=\"拍照\" />\n\n                <Button\n                    android:id=\"@+id/btnPickBySelect\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:onClick=\"onClick\"\n                    android:text=\"选择照片\" />\n            </LinearLayout>\n        </LinearLayout>\n    </LinearLayout>\n</ScrollView>"
  },
  {
    "path": "simple/src/main/res/layout/image_show.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_height=\"match_parent\"\n    android:layout_width=\"match_parent\"\n    android:orientation=\"horizontal\"\n    >\n    <ImageView\n        android:id=\"@+id/imgShow1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_marginRight=\"5dp\"\n        android:background=\"@android:color/darker_gray\"\n        android:scaleType=\"fitCenter\" />\n    <ImageView\n        android:id=\"@+id/imgShow2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_marginRight=\"5dp\"\n        android:background=\"@android:color/darker_gray\"\n        android:scaleType=\"fitCenter\" />\n</LinearLayout>\n"
  },
  {
    "path": "simple/src/main/res/layout/simple_fragment_layout.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/holo_green_dark\"\n    >\n    <FrameLayout android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@android:color/darker_gray\"\n        android:id=\"@+id/fragment1\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "simple/src/main/res/menu/menu_main.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\" tools:context=\".MainActivity\">\n    <item android:id=\"@+id/action_settings\" android:title=\"@string/action_settings\"\n        android:orderInCategory=\"100\" app:showAsAction=\"never\" />\n</menu>\n"
  },
  {
    "path": "simple/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "simple/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">TakePhoto</string>\n\n    <string name=\"hello_world\">Hello world!</string>\n    <string name=\"action_settings\">Settings</string>\n</resources>\n"
  },
  {
    "path": "simple/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "simple/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "takephoto_library/.gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n### Android template\n# Built application files\n*.apk\n*.ap_\n\n# Files for the Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\n\n# Gradle files\n.gradle/\nbuild/\n/*/build/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n\n### JetBrains template\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion\n\n*.iml\n\n## Directory-based project format:\n.idea/\n# if you remove the above rule, at least ignore the following:\n\n# User-specific stuff:\n# .idea/workspace.xml\n# .idea/tasks.xml\n# .idea/dictionaries\n\n# Sensitive or high-churn files:\n# .idea/dataSources.ids\n# .idea/dataSources.xml\n# .idea/sqlDataSources.xml\n# .idea/dynamic.xml\n# .idea/uiDesigner.xml\n\n# Gradle:\n# .idea/gradle.xml\n# .idea/libraries\n\n# Mongo Explorer plugin:\n# .idea/mongoSettings.xml\n\n## File-based project format:\n*.ipr\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\n\n\n### Gradle template\n.gradle\n\n# Ignore Gradle GUI config\ngradle-app.setting\n\n# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)\n!gradle-wrapper.jar  \nbintrayUpload.gradle\n\n\n"
  },
  {
    "path": "takephoto_library/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 27\n    buildToolsVersion '26.0.3'\n\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 27\n        versionCode 45\n        versionName \"4.1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile 'com.soundcloud.android.crop:lib_crop:1.0.0'\n    compile 'com.darsh.multipleimageselect:multipleimageselect:1.0.5'\n    compile 'me.shaohui.advancedluban:library:1.3.2'\n}\n//apply from: \"bintrayUpload.gradle\""
  },
  {
    "path": "takephoto_library/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\Program Files\\adt-bundle-windows-x86_64-20140702\\sdk1/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n\n-dontwarn android.support.**\n-keep class android.support.** { *; }\n\n\n-keepattributes InnerClasses\n-dontoptimize\n\n\n-keep class com.jph.takephoto.** { *; }\n-dontwarn com.jph.takephoto.**\n\n-keep class com.darsh.multipleimageselect.** { *; }\n-dontwarn com.darsh.multipleimageselect.**\n\n-keep class com.soundcloud.android.crop.** { *; }\n-dontwarn com.soundcloud.android.crop.**\n\n"
  },
  {
    "path": "takephoto_library/src/androidTest/java/org/devio/takephoto/ApplicationTest.java",
    "content": "package org.devio.takephoto;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "takephoto_library/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"org.devio.takephoto\">\n\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n\n    <application android:allowBackup=\"true\">\n        <activity android:name=\"com.soundcloud.android.crop.CropImageActivity\" />\n        <provider\n            android:name=\"android.support.v4.content.FileProvider\"\n            android:authorities=\"${applicationId}.fileprovider\"\n            android:grantUriPermissions=\"true\"\n            android:exported=\"false\">\n            <meta-data\n                android:name=\"android.support.FILE_PROVIDER_PATHS\"\n                android:resource=\"@xml/file_paths\" />\n        </provider>\n    </application>\n</manifest>\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/app/TakePhoto.java",
    "content": "package org.devio.takephoto.app;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\n\nimport org.devio.takephoto.model.MultipleCrop;\nimport org.devio.takephoto.model.TException;\nimport org.devio.takephoto.permission.PermissionManager;\nimport org.devio.takephoto.compress.CompressConfig;\nimport org.devio.takephoto.model.CropOptions;\nimport org.devio.takephoto.model.TResult;\nimport org.devio.takephoto.model.TakePhotoOptions;\n\n\n/**\n * - 支持通过相机拍照获取图片\n * - 支持从相册选择图片\n * - 支持从文件选择图片\n * - 支持多图选择\n * - 支持批量图片裁切\n * - 支持批量图片压缩\n * - 支持对图片进行压缩\n * - 支持对图片进行裁剪\n * - 支持对裁剪及压缩参数自定义\n * - 提供自带裁剪工具(可选)\n * - 支持智能选取及裁剪异常处理\n * - 支持因拍照Activity被回收后的自动恢复\n * Author: crazycodeboy\n * Date: 2016/9/21 0007 20:10\n * Version:4.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic interface TakePhoto {\n    /**\n     * 图片多选\n     *\n     * @param limit 最多选择图片张数的限制\n     */\n    void onPickMultiple(int limit);\n\n    /**\n     * 图片多选，并裁切\n     *\n     * @param limit   最多选择图片张数的限制\n     * @param options 裁剪配置\n     */\n    void onPickMultipleWithCrop(int limit, CropOptions options);\n\n    /**\n     * 从文件中获取图片（不裁剪）\n     */\n    void onPickFromDocuments();\n\n    /**\n     * 从文件中获取图片并裁剪\n     *\n     * @param outPutUri 图片裁剪之后保存的路径\n     * @param options   裁剪配置\n     */\n    void onPickFromDocumentsWithCrop(Uri outPutUri, CropOptions options);\n\n    /**\n     * 从相册中获取图片（不裁剪）\n     */\n    void onPickFromGallery();\n\n    /**\n     * 从相册中获取图片并裁剪\n     *\n     * @param outPutUri 图片裁剪之后保存的路径\n     * @param options   裁剪配置\n     */\n    void onPickFromGalleryWithCrop(Uri outPutUri, CropOptions options);\n\n    /**\n     * 从相机获取图片(不裁剪)\n     *\n     * @param outPutUri 图片保存的路径\n     */\n    void onPickFromCapture(Uri outPutUri);\n\n    /**\n     * 从相机获取图片并裁剪\n     *\n     * @param outPutUri 图片裁剪之后保存的路径\n     * @param options   裁剪配置\n     */\n    void onPickFromCaptureWithCrop(Uri outPutUri, CropOptions options);\n\n    /**\n     * 裁剪图片\n     *\n     * @param imageUri  要裁剪的图片\n     * @param outPutUri 图片裁剪之后保存的路径\n     * @param options   裁剪配置\n     */\n    void onCrop(Uri imageUri, Uri outPutUri, CropOptions options) throws TException;\n\n    /**\n     * 裁剪多张图片\n     *\n     * @param multipleCrop 要裁切的图片的路径以及输出路径\n     * @param options      裁剪配置\n     */\n    void onCrop(MultipleCrop multipleCrop, CropOptions options) throws TException;\n\n    void permissionNotify(PermissionManager.TPermissionType type);\n\n    /**\n     * 启用图片压缩\n     *\n     * @param config             压缩图片配置\n     * @param showCompressDialog 压缩时是否显示进度对话框\n     */\n    void onEnableCompress(CompressConfig config, boolean showCompressDialog);\n\n    /**\n     * 设置TakePhoto相关配置\n     *\n     * @param options\n     */\n    void setTakePhotoOptions(TakePhotoOptions options);\n\n    void onCreate(Bundle savedInstanceState);\n\n    void onSaveInstanceState(Bundle outState);\n\n    /**\n     * 处理拍照或从相册选择的图片或裁剪的结果\n     *\n     * @param requestCode\n     * @param resultCode\n     * @param data\n     */\n    void onActivityResult(int requestCode, int resultCode, Intent data);\n\n    /**\n     * 拍照结果监听接口\n     */\n    interface TakeResultListener {\n        void takeSuccess(TResult result);\n\n        void takeFail(TResult result, String msg);\n\n        void takeCancel();\n    }\n}"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/app/TakePhotoActivity.java",
    "content": "package org.devio.takephoto.app;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport org.devio.takephoto.model.InvokeParam;\nimport org.devio.takephoto.permission.PermissionManager;\nimport org.devio.takephoto.permission.TakePhotoInvocationHandler;\nimport org.devio.takephoto.R;\nimport org.devio.takephoto.model.TContextWrap;\nimport org.devio.takephoto.model.TResult;\nimport org.devio.takephoto.permission.InvokeListener;\n\n/**\n * 继承这个类来让Activity获取拍照的能力<br>\n * Author: crazycodeboy\n * Date: 2016/9/21 0007 20:10\n * Version:3.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class TakePhotoActivity extends Activity implements TakePhoto.TakeResultListener, InvokeListener {\n    private static final String TAG = TakePhotoActivity.class.getName();\n    private TakePhoto takePhoto;\n    private InvokeParam invokeParam;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        getTakePhoto().onCreate(savedInstanceState);\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        getTakePhoto().onSaveInstanceState(outState);\n        super.onSaveInstanceState(outState);\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        getTakePhoto().onActivityResult(requestCode, resultCode, data);\n        super.onActivityResult(requestCode, resultCode, data);\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        PermissionManager.TPermissionType type = PermissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        PermissionManager.handlePermissionsResult(this, type, invokeParam, this);\n    }\n\n    /**\n     * 获取TakePhoto实例\n     *\n     * @return\n     */\n    public TakePhoto getTakePhoto() {\n        if (takePhoto == null) {\n            takePhoto = (TakePhoto) TakePhotoInvocationHandler.of(this).bind(new TakePhotoImpl(this, this));\n        }\n        return takePhoto;\n    }\n\n    @Override\n    public void takeSuccess(TResult result) {\n        Log.i(TAG, \"takeSuccess：\" + result.getImage().getCompressPath());\n    }\n\n    @Override\n    public void takeFail(TResult result, String msg) {\n        Log.i(TAG, \"takeFail:\" + msg);\n    }\n\n    @Override\n    public void takeCancel() {\n        Log.i(TAG, getResources().getString(R.string.msg_operation_canceled));\n    }\n\n    @Override\n    public PermissionManager.TPermissionType invoke(InvokeParam invokeParam) {\n        PermissionManager.TPermissionType type = PermissionManager.checkPermission(TContextWrap.of(this), invokeParam.getMethod());\n        if (PermissionManager.TPermissionType.WAIT.equals(type)) {\n            this.invokeParam = invokeParam;\n        }\n        return type;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/app/TakePhotoFragment.java",
    "content": "package org.devio.takephoto.app;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.util.Log;\n\nimport org.devio.takephoto.permission.PermissionManager;\nimport org.devio.takephoto.permission.TakePhotoInvocationHandler;\nimport org.devio.takephoto.model.InvokeParam;\nimport org.devio.takephoto.model.TContextWrap;\nimport org.devio.takephoto.model.TResult;\nimport org.devio.takephoto.permission.InvokeListener;\n\n/**\n * 继承这个类来让Fragment获取拍照的能力<br>\n * Author: crazycodeboy\n * Date: 2016/9/21 0007 20:10\n * Version:3.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class TakePhotoFragment extends Fragment implements TakePhoto.TakeResultListener, InvokeListener {\n    private static final String TAG = TakePhotoFragment.class.getName();\n    private InvokeParam invokeParam;\n    private TakePhoto takePhoto;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        getTakePhoto().onCreate(savedInstanceState);\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public void onSaveInstanceState(Bundle outState) {\n        getTakePhoto().onSaveInstanceState(outState);\n        super.onSaveInstanceState(outState);\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        getTakePhoto().onActivityResult(requestCode, resultCode, data);\n        super.onActivityResult(requestCode, resultCode, data);\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        PermissionManager.TPermissionType type = PermissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        PermissionManager.handlePermissionsResult(getActivity(), type, invokeParam, this);\n    }\n\n    /**\n     * 获取TakePhoto实例\n     *\n     * @return\n     */\n    public TakePhoto getTakePhoto() {\n        if (takePhoto == null) {\n            takePhoto = (TakePhoto) TakePhotoInvocationHandler.of(this).bind(new TakePhotoImpl(this, this));\n        }\n        return takePhoto;\n    }\n\n    @Override\n    public void takeSuccess(TResult result) {\n        Log.i(TAG, \"takeSuccess：\" + result.getImage().getCompressPath());\n    }\n\n    @Override\n    public void takeFail(TResult result, String msg) {\n        Log.i(TAG, \"takeFail:\" + msg);\n    }\n\n    @Override\n    public void takeCancel() {\n        Log.i(TAG, getResources().getString(org.devio.takephoto.R.string.msg_operation_canceled));\n    }\n\n    @Override\n    public PermissionManager.TPermissionType invoke(InvokeParam invokeParam) {\n        PermissionManager.TPermissionType type = PermissionManager.checkPermission(TContextWrap.of(this), invokeParam.getMethod());\n        if (PermissionManager.TPermissionType.WAIT.equals(type)) {\n            this.invokeParam = invokeParam;\n        }\n        return type;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/app/TakePhotoFragmentActivity.java",
    "content": "package org.devio.takephoto.app;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.app.FragmentActivity;\nimport android.util.Log;\n\nimport org.devio.takephoto.permission.PermissionManager;\nimport org.devio.takephoto.model.InvokeParam;\nimport org.devio.takephoto.model.TContextWrap;\nimport org.devio.takephoto.model.TResult;\nimport org.devio.takephoto.permission.InvokeListener;\nimport org.devio.takephoto.permission.TakePhotoInvocationHandler;\n\n/**\n * 继承这个类来让Activity获取拍照的能力<br>\n * Author: crazycodeboy\n * Date: 2016/9/21 0007 20:10\n * Version:3.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class TakePhotoFragmentActivity extends FragmentActivity implements TakePhoto.TakeResultListener, InvokeListener {\n    private static final String TAG = TakePhotoFragmentActivity.class.getName();\n    private TakePhoto takePhoto;\n    private InvokeParam invokeParam;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        getTakePhoto().onCreate(savedInstanceState);\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        getTakePhoto().onSaveInstanceState(outState);\n        super.onSaveInstanceState(outState);\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        getTakePhoto().onActivityResult(requestCode, resultCode, data);\n        super.onActivityResult(requestCode, resultCode, data);\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        PermissionManager.TPermissionType type = PermissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        PermissionManager.handlePermissionsResult(this, type, invokeParam, this);\n    }\n\n    /**\n     * 获取TakePhoto实例\n     *\n     * @return\n     */\n    public TakePhoto getTakePhoto() {\n        if (takePhoto == null) {\n            takePhoto = (TakePhoto) TakePhotoInvocationHandler.of(this).bind(new TakePhotoImpl(this, this));\n        }\n        return takePhoto;\n    }\n\n    @Override\n    public void takeSuccess(TResult result) {\n        Log.i(TAG, \"takeSuccess：\" + result.getImage().getCompressPath());\n    }\n\n    @Override\n    public void takeFail(TResult result, String msg) {\n        Log.i(TAG, \"takeFail:\" + msg);\n    }\n\n    @Override\n    public void takeCancel() {\n        Log.i(TAG, getResources().getString(org.devio.takephoto.R.string.msg_operation_canceled));\n    }\n\n    @Override\n    public PermissionManager.TPermissionType invoke(InvokeParam invokeParam) {\n        PermissionManager.TPermissionType type = PermissionManager.checkPermission(TContextWrap.of(this), invokeParam.getMethod());\n        if (PermissionManager.TPermissionType.WAIT.equals(type)) {\n            this.invokeParam = invokeParam;\n        }\n        return type;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/app/TakePhotoImpl.java",
    "content": "package org.devio.takephoto.app;\n\nimport android.app.Activity;\nimport android.app.ProgressDialog;\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.widget.Toast;\n\nimport com.darsh.multipleimageselect.helpers.Constants;\nimport com.darsh.multipleimageselect.models.Image;\nimport org.devio.takephoto.compress.CompressImage;\nimport org.devio.takephoto.compress.CompressImageImpl;\nimport org.devio.takephoto.model.MultipleCrop;\nimport org.devio.takephoto.model.TException;\nimport org.devio.takephoto.model.TExceptionType;\nimport org.devio.takephoto.model.TImage;\nimport org.devio.takephoto.model.TIntentWap;\nimport org.devio.takephoto.permission.PermissionManager;\nimport org.devio.takephoto.uitl.TUriParse;\nimport org.devio.takephoto.compress.CompressConfig;\nimport org.devio.takephoto.model.CropOptions;\nimport org.devio.takephoto.model.TContextWrap;\nimport org.devio.takephoto.model.TResult;\nimport org.devio.takephoto.model.TakePhotoOptions;\nimport org.devio.takephoto.uitl.ImageRotateUtil;\nimport org.devio.takephoto.uitl.IntentUtils;\nimport org.devio.takephoto.uitl.TConstant;\nimport org.devio.takephoto.uitl.TFileUtils;\nimport org.devio.takephoto.uitl.TImageFiles;\nimport org.devio.takephoto.uitl.TUtils;\nimport com.soundcloud.android.crop.Crop;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Map;\n\n/**\n * - 支持通过相机拍照获取图片\n * - 支持从相册选择图片\n * - 支持从文件选择图片\n * - 支持多图选择\n * - 支持批量图片裁切\n * - 支持批量图片压缩\n * - 支持对图片进行压缩\n * - 支持对图片进行裁剪\n * - 支持对裁剪及压缩参数自定义\n * - 提供自带裁剪工具(可选)\n * - 支持智能选取及裁剪异常处理\n * - 支持因拍照Activity被回收后的自动恢复\n * Date: 2016/9/21 0007 20:10\n * Version:4.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class TakePhotoImpl implements TakePhoto {\n    private static final String TAG = IntentUtils.class.getName();\n    private TContextWrap contextWrap;\n    private TakeResultListener listener;\n    private Uri outPutUri;\n    private Uri tempUri;\n    private CropOptions cropOptions;\n    private TakePhotoOptions takePhotoOptions;\n    private CompressConfig compressConfig;\n    private MultipleCrop multipleCrop;\n    private PermissionManager.TPermissionType permissionType;\n    private TImage.FromType fromType; //CAMERA图片来源相机，OTHER图片来源其他\n    /**\n     * 是否显示压缩对话框\n     */\n    private boolean showCompressDialog;\n    private ProgressDialog wailLoadDialog;\n\n    public TakePhotoImpl(Activity activity, TakeResultListener listener) {\n        contextWrap = TContextWrap.of(activity);\n        this.listener = listener;\n    }\n\n    public TakePhotoImpl(Fragment fragment, TakeResultListener listener) {\n        contextWrap = TContextWrap.of(fragment);\n        this.listener = listener;\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        if (savedInstanceState != null) {\n            cropOptions = (CropOptions) savedInstanceState.getSerializable(\"cropOptions\");\n            takePhotoOptions = (TakePhotoOptions) savedInstanceState.getSerializable(\"takePhotoOptions\");\n            showCompressDialog = savedInstanceState.getBoolean(\"showCompressDialog\");\n            outPutUri = savedInstanceState.getParcelable(\"outPutUri\");\n            tempUri = savedInstanceState.getParcelable(\"tempUri\");\n            compressConfig = (CompressConfig) savedInstanceState.getSerializable(\"compressConfig\");\n        }\n    }\n\n    @Override\n    public void onSaveInstanceState(Bundle outState) {\n        outState.putSerializable(\"cropOptions\", cropOptions);\n        outState.putSerializable(\"takePhotoOptions\", takePhotoOptions);\n        outState.putBoolean(\"showCompressDialog\", showCompressDialog);\n        outState.putParcelable(\"outPutUri\", outPutUri);\n        outState.putParcelable(\"tempUri\", tempUri);\n        outState.putSerializable(\"compressConfig\", compressConfig);\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        switch (requestCode) {\n            case TConstant.RC_PICK_PICTURE_FROM_GALLERY_CROP:\n                if (resultCode == Activity.RESULT_OK && data != null) {//从相册选择照片并裁剪\n                    try {\n                        onCrop(data.getData(), outPutUri, cropOptions);\n                    } catch (TException e) {\n                        takeResult(TResult.of(TImage.of(outPutUri, fromType)), e.getDetailMessage());\n                        e.printStackTrace();\n                    }\n                } else {\n                    listener.takeCancel();\n                }\n                break;\n            case TConstant.RC_PICK_PICTURE_FROM_GALLERY_ORIGINAL://从相册选择照片不裁剪\n                if (resultCode == Activity.RESULT_OK) {\n                    try {\n                        takeResult(\n                            TResult.of(TImage.of(TUriParse.getFilePathWithUri(data.getData(), contextWrap.getActivity()), fromType)));\n                    } catch (TException e) {\n                        takeResult(TResult.of(TImage.of(data.getData(), fromType)), e.getDetailMessage());\n                        e.printStackTrace();\n                    }\n                } else {\n                    listener.takeCancel();\n                }\n                break;\n            case TConstant.RC_PICK_PICTURE_FROM_DOCUMENTS_ORIGINAL://从文件选择照片不裁剪\n                if (resultCode == Activity.RESULT_OK) {\n                    try {\n                        takeResult(TResult.of(\n                            TImage.of(TUriParse.getFilePathWithDocumentsUri(data.getData(), contextWrap.getActivity()), fromType)));\n                    } catch (TException e) {\n                        takeResult(TResult.of(TImage.of(outPutUri, fromType)), e.getDetailMessage());\n                        e.printStackTrace();\n                    }\n                } else {\n                    listener.takeCancel();\n                }\n                break;\n            case TConstant.RC_PICK_PICTURE_FROM_DOCUMENTS_CROP://从文件选择照片，并裁剪\n                if (resultCode == Activity.RESULT_OK) {\n                    try {\n                        onCrop(data.getData(), outPutUri, cropOptions);\n                    } catch (TException e) {\n                        takeResult(TResult.of(TImage.of(outPutUri, fromType)), e.getDetailMessage());\n                        e.printStackTrace();\n                    }\n                } else {\n                    listener.takeCancel();\n                }\n                break;\n            case TConstant.RC_PICK_PICTURE_FROM_CAPTURE_CROP://拍取照片,并裁剪\n                if (resultCode == Activity.RESULT_OK) {\n                    if (takePhotoOptions != null && takePhotoOptions.isCorrectImage()) {\n                        ImageRotateUtil.of().correctImage(contextWrap.getActivity(), tempUri);\n                    }\n                    try {\n                        onCrop(tempUri, Uri.fromFile(new File(TUriParse.parseOwnUri(contextWrap.getActivity(), outPutUri))), cropOptions);\n                    } catch (TException e) {\n                        takeResult(TResult.of(TImage.of(outPutUri, fromType)), e.getDetailMessage());\n                        e.printStackTrace();\n                    }\n                } else {\n                    listener.takeCancel();\n                }\n                break;\n            case TConstant.RC_PICK_PICTURE_FROM_CAPTURE://拍取照片\n                if (resultCode == Activity.RESULT_OK) {\n                    if (takePhotoOptions != null && takePhotoOptions.isCorrectImage()) {\n                        ImageRotateUtil.of().correctImage(contextWrap.getActivity(), outPutUri);\n                    }\n                    try {\n                        takeResult(TResult.of(TImage.of(TUriParse.getFilePathWithUri(outPutUri, contextWrap.getActivity()), fromType)));\n                    } catch (TException e) {\n                        takeResult(TResult.of(TImage.of(outPutUri, fromType)), e.getDetailMessage());\n                        e.printStackTrace();\n                    }\n                } else {\n                    listener.takeCancel();\n                }\n                break;\n            case TConstant.RC_CROP://裁剪照片返回结果\n            case Crop.REQUEST_CROP://裁剪照片返回结果\n                if (resultCode == Activity.RESULT_OK) {\n                    if (multipleCrop != null) {\n                        cropContinue(true);\n                    } else {\n                        try {\n                            TImage image = TImage.of(TUriParse.getFilePathWithUri(outPutUri, contextWrap.getActivity()), fromType);\n                            image.setCropped(true);\n                            takeResult(TResult.of(image));\n                        } catch (TException e) {\n                            takeResult(TResult.of(TImage.of(outPutUri.getPath(), fromType)), e.getDetailMessage());\n                            e.printStackTrace();\n                        }\n                    }\n                } else if (resultCode == Activity.RESULT_CANCELED) {//裁剪的照片没有保存\n                    if (multipleCrop != null) {\n                        if (data != null) {\n                            Bitmap bitmap = data.getParcelableExtra(\"data\");//获取裁剪的结果数据\n                            TImageFiles.writeToFile(bitmap, outPutUri);//将裁剪的结果写入到文件\n                            cropContinue(true);\n                        } else {\n                            cropContinue(false);\n                        }\n                    } else {\n                        if (data != null) {\n                            Bitmap bitmap = data.getParcelableExtra(\"data\");//获取裁剪的结果数据\n                            TImageFiles.writeToFile(bitmap, outPutUri);//将裁剪的结果写入到文件\n\n                            TImage image = TImage.of(outPutUri.getPath(), fromType);\n                            image.setCropped(true);\n                            takeResult(TResult.of(image));\n                        } else {\n                            listener.takeCancel();\n                        }\n                    }\n                } else {\n                    if (multipleCrop != null) {\n                        cropContinue(false);\n                    } else {\n                        listener.takeCancel();\n                    }\n                }\n                break;\n            case TConstant.RC_PICK_MULTIPLE://多选图片返回结果\n                if (resultCode == Activity.RESULT_OK && data != null) {\n                    ArrayList<Image> images = data.getParcelableArrayListExtra(Constants.INTENT_EXTRA_IMAGES);\n                    if (cropOptions != null) {\n                        try {\n                            onCrop(MultipleCrop.of(TUtils.convertImageToUri(contextWrap.getActivity(), images), contextWrap.getActivity(),\n                                fromType), cropOptions);\n                        } catch (TException e) {\n                            cropContinue(false);\n                            e.printStackTrace();\n                        }\n                    } else {\n                        takeResult(TResult.of(TUtils.getTImagesWithImages(images, fromType)));\n                    }\n\n                } else {\n                    listener.takeCancel();\n                }\n                break;\n            default:\n                break;\n        }\n    }\n\n    @Override\n    public void onPickMultiple(int limit) {\n        if (PermissionManager.TPermissionType.WAIT.equals(permissionType)) {\n            return;\n        }\n        TUtils.startActivityForResult(contextWrap,\n            new TIntentWap(IntentUtils.getPickMultipleIntent(contextWrap, limit), TConstant.RC_PICK_MULTIPLE));\n    }\n\n    @Override\n    public void onPickMultipleWithCrop(int limit, CropOptions options) {\n        this.fromType = TImage.FromType.OTHER;\n        onPickMultiple(limit);\n        this.cropOptions = options;\n    }\n\n    /**\n     * -----crop------\n     **/\n    @Override\n    public void onCrop(Uri imageUri, Uri outPutUri, CropOptions options) throws TException {\n        if (PermissionManager.TPermissionType.WAIT.equals(permissionType)) {\n            return;\n        }\n        this.outPutUri = outPutUri;\n        if (!TImageFiles.checkMimeType(contextWrap.getActivity(), TImageFiles.getMimeType(contextWrap.getActivity(), imageUri))) {\n            Toast.makeText(contextWrap.getActivity(), contextWrap.getActivity().getResources().getText(org.devio.takephoto.R.string.tip_type_not_image),\n                Toast.LENGTH_SHORT).show();\n            throw new TException(TExceptionType.TYPE_NOT_IMAGE);\n        }\n        cropWithNonException(imageUri, outPutUri, options);\n    }\n\n    @Override\n    public void onCrop(MultipleCrop multipleCrop, CropOptions options) throws TException {\n        this.multipleCrop = multipleCrop;\n        onCrop(multipleCrop.getUris().get(0), multipleCrop.getOutUris().get(0), options);\n    }\n\n    private void cropWithNonException(Uri imageUri, Uri outPutUri, CropOptions options) {\n        this.outPutUri = outPutUri;\n        if (options.isWithOwnCrop()) {\n            TUtils.cropWithOwnApp(contextWrap, imageUri, outPutUri, options);\n        } else {\n            TUtils.cropWithOtherAppBySafely(contextWrap, imageUri, outPutUri, options);\n        }\n    }\n\n    private void cropContinue(boolean preSuccess) {\n        Map result = multipleCrop.setCropWithUri(outPutUri, preSuccess);\n        int index = (int) result.get(\"index\");\n        boolean isLast = (boolean) result.get(\"isLast\");\n\n        if (isLast) {\n            if (preSuccess) {\n                takeResult(TResult.of(multipleCrop.gettImages()));\n            } else {\n                takeResult(TResult.of(multipleCrop.gettImages()),\n                    outPutUri.getPath() + contextWrap.getActivity().getResources().getString(org.devio.takephoto.R.string.msg_crop_canceled));\n            }\n        } else {\n            cropWithNonException(multipleCrop.getUris().get(index + 1), multipleCrop.getOutUris().get(index + 1), cropOptions);\n        }\n    }\n\n    @Override\n    public void onPickFromDocuments() {\n        selectPicture(0, false);\n    }\n\n    @Override\n    public void onPickFromGallery() {\n        selectPicture(1, false);\n    }\n\n    private void selectPicture(int defaultIndex, boolean isCrop) {\n        this.fromType = TImage.FromType.OTHER;\n        if (takePhotoOptions != null && takePhotoOptions.isWithOwnGallery()) {\n            onPickMultiple(1);\n            return;\n        }\n        if (PermissionManager.TPermissionType.WAIT.equals(permissionType)) {\n            return;\n        }\n        ArrayList<TIntentWap> intentWapList = new ArrayList<>();\n        intentWapList.add(new TIntentWap(IntentUtils.getPickIntentWithDocuments(),\n            isCrop ? TConstant.RC_PICK_PICTURE_FROM_DOCUMENTS_CROP : TConstant.RC_PICK_PICTURE_FROM_DOCUMENTS_ORIGINAL));\n        intentWapList.add(new TIntentWap(IntentUtils.getPickIntentWithGallery(),\n            isCrop ? TConstant.RC_PICK_PICTURE_FROM_GALLERY_CROP : TConstant.RC_PICK_PICTURE_FROM_GALLERY_ORIGINAL));\n        try {\n            TUtils.sendIntentBySafely(contextWrap, intentWapList, defaultIndex, isCrop);\n        } catch (TException e) {\n            takeResult(TResult.of(TImage.of(\"\", fromType)), e.getDetailMessage());\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onPickFromGalleryWithCrop(Uri outPutUri, CropOptions options) {\n        this.cropOptions = options;\n        this.outPutUri = outPutUri;\n        selectPicture(1, true);\n    }\n\n    @Override\n    public void onPickFromDocumentsWithCrop(Uri outPutUri, CropOptions options) {\n        this.cropOptions = options;\n        this.outPutUri = outPutUri;\n        selectPicture(0, true);\n    }\n\n    @Override\n    public void onPickFromCapture(Uri outPutUri) {\n        this.fromType = TImage.FromType.CAMERA;\n        if (PermissionManager.TPermissionType.WAIT.equals(permissionType)) {\n            return;\n        }\n        if (Build.VERSION.SDK_INT >= 23) {\n            this.outPutUri = TUriParse.convertFileUriToFileProviderUri(contextWrap.getActivity(), outPutUri);\n        } else {\n            this.outPutUri = outPutUri;\n        }\n\n        try {\n            TUtils.captureBySafely(contextWrap,\n                new TIntentWap(IntentUtils.getCaptureIntent(this.outPutUri), TConstant.RC_PICK_PICTURE_FROM_CAPTURE));\n        } catch (TException e) {\n            takeResult(TResult.of(TImage.of(\"\", fromType)), e.getDetailMessage());\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onPickFromCaptureWithCrop(Uri outPutUri, CropOptions options) {\n        this.fromType = TImage.FromType.CAMERA;\n        if (PermissionManager.TPermissionType.WAIT.equals(permissionType)) {\n            return;\n        }\n        this.cropOptions = options;\n        this.outPutUri = outPutUri;\n        if (Build.VERSION.SDK_INT >= 23) {\n            this.tempUri = TUriParse.getTempUri(contextWrap.getActivity());\n        } else {\n            this.tempUri = outPutUri;\n        }\n\n        try {\n            TUtils.captureBySafely(contextWrap,\n                new TIntentWap(IntentUtils.getCaptureIntent(this.tempUri), TConstant.RC_PICK_PICTURE_FROM_CAPTURE_CROP));\n        } catch (TException e) {\n            takeResult(TResult.of(TImage.of(\"\", fromType)), e.getDetailMessage());\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onEnableCompress(CompressConfig config, boolean showCompressDialog) {\n        this.compressConfig = config;\n        this.showCompressDialog = showCompressDialog;\n    }\n\n    @Override\n    public void setTakePhotoOptions(TakePhotoOptions options) {\n        this.takePhotoOptions = options;\n    }\n\n    @Override\n    public void permissionNotify(PermissionManager.TPermissionType type) {\n        this.permissionType = type;\n    }\n\n    private void takeResult(final TResult result, final String... message) {\n        if (null == compressConfig) {\n            handleTakeCallBack(result, message);\n        } else {\n            if (showCompressDialog) {\n                wailLoadDialog = TUtils.showProgressDialog(contextWrap.getActivity(),\n                    contextWrap.getActivity().getResources().getString(org.devio.takephoto.R.string.tip_compress));\n            }\n\n            CompressImageImpl.of(contextWrap.getActivity(), compressConfig, result.getImages(), new CompressImage.CompressListener() {\n                @Override\n                public void onCompressSuccess(ArrayList<TImage> images) {\n                    if (!compressConfig.isEnableReserveRaw()) {\n                        deleteRawFile(images);\n                    }\n                    handleTakeCallBack(result);\n                    if (wailLoadDialog != null && !contextWrap.getActivity().isFinishing()) {\n                        wailLoadDialog.dismiss();\n                    }\n                }\n\n                @Override\n                public void onCompressFailed(ArrayList<TImage> images, String msg) {\n                    if (!compressConfig.isEnableReserveRaw()) {\n                        deleteRawFile(images);\n                    }\n                    handleTakeCallBack(TResult.of(images),\n                        String.format(contextWrap.getActivity().getResources().getString(org.devio.takephoto.R.string.tip_compress_failed),\n                            message.length > 0 ? message[0] : \"\", msg, result.getImage().getCompressPath()));\n                    if (wailLoadDialog != null && !contextWrap.getActivity().isFinishing()) {\n                        wailLoadDialog.dismiss();\n                    }\n                }\n            }).compress();\n        }\n    }\n\n    private void deleteRawFile(ArrayList<TImage> images) {\n        for (TImage image : images) {\n            if (TImage.FromType.CAMERA == fromType) {\n                TFileUtils.delete(image.getOriginalPath());\n                image.setOriginalPath(\"\");\n            }\n        }\n    }\n\n    private void handleTakeCallBack(final TResult result, String... message) {\n        if (message.length > 0) {\n            listener.takeFail(result, message[0]);\n        } else if (multipleCrop != null && multipleCrop.hasFailed) {\n            listener.takeFail(result, contextWrap.getActivity().getResources().getString(org.devio.takephoto.R.string.msg_crop_failed));\n        } else if (compressConfig != null) {\n            boolean hasFailed = false;\n            for (TImage image : result.getImages()) {\n                if (image == null || !image.isCompressed()) {\n                    hasFailed = true;\n                    break;\n                }\n            }\n            if (hasFailed) {\n                listener.takeFail(result, contextWrap.getActivity().getString(org.devio.takephoto.R.string.msg_compress_failed));\n            } else {\n                listener.takeSuccess(result);\n            }\n        } else {\n            listener.takeSuccess(result);\n        }\n        clearParams();\n    }\n\n    private void clearParams() {\n        compressConfig = null;\n        takePhotoOptions = null;\n        cropOptions = null;\n        multipleCrop = null;\n    }\n}"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/compress/CompressConfig.java",
    "content": "package org.devio.takephoto.compress;\n\n\nimport org.devio.takephoto.model.LubanOptions;\n\nimport java.io.Serializable;\n\n/**\n * 压缩配置类\n * Author: JPH\n * Date: 2016/6/7 0007 18:01\n */\npublic class CompressConfig implements Serializable {\n\n    /**\n     * 长或宽不超过的最大像素,单位px\n     */\n    private int maxPixel = 1200;\n    /**\n     * 压缩到的最大大小，单位B\n     */\n    private int maxSize = 100 * 1024;\n\n    /**\n     * 是否启用像素压缩\n     */\n    private boolean enablePixelCompress = true;\n    /**\n     * 是否启用质量压缩\n     */\n    private boolean enableQualityCompress = true;\n\n    /**\n     * 是否保留原文件\n     */\n    private boolean enableReserveRaw = true;\n\n    /**\n     * Luban压缩配置\n     */\n    private LubanOptions lubanOptions;\n\n    public static CompressConfig ofDefaultConfig() {\n        return new CompressConfig();\n    }\n\n    public static CompressConfig ofLuban(LubanOptions options) {\n        return new CompressConfig(options);\n    }\n\n    private CompressConfig() {\n    }\n\n    private CompressConfig(LubanOptions options) {\n        this.lubanOptions = options;\n    }\n\n    public LubanOptions getLubanOptions() {\n        return lubanOptions;\n    }\n\n    public int getMaxPixel() {\n        return maxPixel;\n    }\n\n    public CompressConfig setMaxPixel(int maxPixel) {\n        this.maxPixel = maxPixel;\n        return this;\n    }\n\n    public int getMaxSize() {\n        return maxSize;\n    }\n\n    public void setMaxSize(int maxSize) {\n        this.maxSize = maxSize;\n    }\n\n    public boolean isEnablePixelCompress() {\n        return enablePixelCompress;\n    }\n\n    public void enablePixelCompress(boolean enablePixelCompress) {\n        this.enablePixelCompress = enablePixelCompress;\n    }\n\n    public boolean isEnableQualityCompress() {\n        return enableQualityCompress;\n    }\n\n    public void enableQualityCompress(boolean enableQualityCompress) {\n        this.enableQualityCompress = enableQualityCompress;\n    }\n\n    public boolean isEnableReserveRaw() {\n        return enableReserveRaw;\n    }\n\n    public void enableReserveRaw(boolean enableReserveRaw) {\n        this.enableReserveRaw = enableReserveRaw;\n    }\n\n    public static class Builder {\n        private CompressConfig config;\n\n        public Builder() {\n            config = new CompressConfig();\n        }\n\n        public Builder setMaxSize(int maxSize) {\n            config.setMaxSize(maxSize);\n            return this;\n        }\n\n        public Builder setMaxPixel(int maxPixel) {\n            config.setMaxPixel(maxPixel);\n            return this;\n        }\n\n        public Builder enablePixelCompress(boolean enablePixelCompress) {\n            config.enablePixelCompress(enablePixelCompress);\n            return this;\n        }\n\n        public Builder enableQualityCompress(boolean enableQualityCompress) {\n            config.enableQualityCompress(enableQualityCompress);\n            return this;\n        }\n\n        public Builder enableReserveRaw(boolean enableReserveRaw) {\n            config.enableReserveRaw(enableReserveRaw);\n            return this;\n        }\n\n        public CompressConfig create() {\n            return config;\n        }\n    }\n}\n\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/compress/CompressImage.java",
    "content": "package org.devio.takephoto.compress;\n\nimport org.devio.takephoto.model.TImage;\n\nimport java.util.ArrayList;\n\n/**\n * 压缩照片2.0\n * <p>\n * Author JPH\n * Date 2015-08-26 下午1:44:26\n */\npublic interface CompressImage {\n    void compress();\n\n    /**\n     * 压缩结果监听器\n     */\n    interface CompressListener {\n        /**\n         * 压缩成功\n         *\n         * @param images 已经压缩图片\n         */\n        void onCompressSuccess(ArrayList<TImage> images);\n\n        /**\n         * 压缩失败\n         *\n         * @param images 压缩失败的图片\n         * @param msg    失败的原因\n         */\n        void onCompressFailed(ArrayList<TImage> images, String msg);\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/compress/CompressImageImpl.java",
    "content": "package org.devio.takephoto.compress;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport org.devio.takephoto.model.TImage;\n\nimport java.io.File;\nimport java.util.ArrayList;\n\n/**\n * 压缩照片\n * <p>\n * Date: 2016/9/21 0007 20:10\n * Version:3.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class CompressImageImpl implements CompressImage {\n    private CompressImageUtil compressImageUtil;\n    private ArrayList<TImage> images;\n    private CompressImage.CompressListener listener;\n\n    public static CompressImage of(Context context, CompressConfig config, ArrayList<TImage> images,\n        CompressImage.CompressListener listener) {\n        if (config.getLubanOptions() != null) {\n            return new CompressWithLuBan(context, config, images, listener);\n        } else {\n            return new CompressImageImpl(context, config, images, listener);\n        }\n    }\n\n    private CompressImageImpl(Context context, CompressConfig config, ArrayList<TImage> images, CompressImage.CompressListener listener) {\n        compressImageUtil = new CompressImageUtil(context, config);\n        this.images = images;\n        this.listener = listener;\n    }\n\n    @Override\n    public void compress() {\n        if (images == null || images.isEmpty()) {\n            listener.onCompressFailed(images, \" images is null\");\n        }\n        for (TImage image : images) {\n            if (image == null) {\n                listener.onCompressFailed(images, \" There are pictures of compress  is null.\");\n                return;\n            }\n        }\n        compress(images.get(0));\n    }\n\n    private void compress(final TImage image) {\n        if (TextUtils.isEmpty(image.getOriginalPath())) {\n            continueCompress(image, false);\n            return;\n        }\n\n        File file = new File(image.getOriginalPath());\n        if (file == null || !file.exists() || !file.isFile()) {\n            continueCompress(image, false);\n            return;\n        }\n\n        compressImageUtil.compress(image.getOriginalPath(), new CompressImageUtil.CompressListener() {\n            @Override\n            public void onCompressSuccess(String imgPath) {\n                image.setCompressPath(imgPath);\n                continueCompress(image, true);\n            }\n\n            @Override\n            public void onCompressFailed(String imgPath, String msg) {\n                continueCompress(image, false, msg);\n            }\n        });\n    }\n\n    private void continueCompress(TImage image, boolean preSuccess, String... message) {\n        image.setCompressed(preSuccess);\n        int index = images.indexOf(image);\n        boolean isLast = index == images.size() - 1;\n        if (isLast) {\n            handleCompressCallBack(message);\n        } else {\n            compress(images.get(index + 1));\n        }\n    }\n\n    private void handleCompressCallBack(String... message) {\n        if (message.length > 0) {\n            listener.onCompressFailed(images, message[0]);\n            return;\n        }\n\n        for (TImage image : images) {\n            if (!image.isCompressed()) {\n                listener.onCompressFailed(images, image.getCompressPath() + \" is compress failures\");\n                return;\n            }\n        }\n        listener.onCompressSuccess(images);\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/compress/CompressImageUtil.java",
    "content": "package org.devio.takephoto.compress;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.Config;\nimport android.graphics.BitmapFactory;\nimport android.os.Handler;\n\nimport org.devio.takephoto.uitl.TFileUtils;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\n\n/**\n * 压缩照片\n *\n * @author JPH\n *         Date 2015-08-26 下午1:44:26\n *         Version:1.0.3\n */\npublic class CompressImageUtil {\n    private CompressConfig config;\n    private Context context;\n    Handler mhHandler = new Handler();\n\n    public CompressImageUtil(Context context, CompressConfig config) {\n        this.context = context;\n        this.config = config == null ? CompressConfig.ofDefaultConfig() : config;\n    }\n\n    public void compress(String imagePath, CompressListener listener) {\n        if (config.isEnablePixelCompress()) {\n            try {\n                compressImageByPixel(imagePath, listener);\n            } catch (FileNotFoundException e) {\n                listener.onCompressFailed(imagePath, String.format(\"图片压缩失败,%s\", e.toString()));\n                e.printStackTrace();\n            }\n        } else {\n            compressImageByQuality(BitmapFactory.decodeFile(imagePath), imagePath, listener);\n        }\n    }\n\n    /**\n     * 多线程压缩图片的质量\n     *\n     * @param bitmap  内存中的图片\n     * @param imgPath 图片的保存路径\n     * @author JPH\n     * @date 2014-12-5下午11:30:43\n     */\n    private void compressImageByQuality(final Bitmap bitmap, final String imgPath, final CompressListener listener) {\n        if (bitmap == null) {\n            sendMsg(false, imgPath, \"像素压缩失败,bitmap is null\", listener);\n            return;\n        }\n        new Thread(new Runnable() {//开启多线程进行压缩处理\n            @Override\n            public void run() {\n                // TODO Auto-generated method stub\n                ByteArrayOutputStream baos = new ByteArrayOutputStream();\n                int options = 100;\n                bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);//质量压缩方法，把压缩后的数据存放到baos中 (100表示不压缩，0表示压缩到最小)\n                while (baos.toByteArray().length > config.getMaxSize()) {//循环判断如果压缩后图片是否大于指定大小,大于继续压缩\n                    baos.reset();//重置baos即让下一次的写入覆盖之前的内容\n                    options -= 5;//图片质量每次减少5\n                    if (options <= 5) {\n                        options = 5;//如果图片质量小于5，为保证压缩后的图片质量，图片最底压缩质量为5\n                    }\n                    bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);//将压缩后的图片保存到baos中\n                    if (options == 5) {\n                        break;//如果图片的质量已降到最低则，不再进行压缩\n                    }\n                }\n                //\t\t\t\tif(bitmap!=null&&!bitmap.isRecycled()){\n                //\t\t\t\t\tbitmap.recycle();//回收内存中的图片\n                //\t\t\t\t}\n                try {\n                    File thumbnailFile = getThumbnailFile(new File(imgPath));\n                    FileOutputStream fos = new FileOutputStream(thumbnailFile);//将压缩后的图片保存的本地上指定路径中\n                    fos.write(baos.toByteArray());\n                    fos.flush();\n                    fos.close();\n                    sendMsg(true, thumbnailFile.getPath(), null, listener);\n                } catch (Exception e) {\n                    sendMsg(false, imgPath, \"质量压缩失败\", listener);\n                    e.printStackTrace();\n                }\n            }\n        }).start();\n    }\n\n    /**\n     * 按比例缩小图片的像素以达到压缩的目的\n     *\n     * @param imgPath\n     * @return\n     * @author JPH\n     * @date 2014-12-5下午11:30:59\n     */\n    private void compressImageByPixel(String imgPath, CompressListener listener) throws FileNotFoundException {\n        if (imgPath == null) {\n            sendMsg(false, imgPath, \"要压缩的文件不存在\", listener);\n            return;\n        }\n        BitmapFactory.Options newOpts = new BitmapFactory.Options();\n        newOpts.inJustDecodeBounds = true;//只读边,不读内容\n        BitmapFactory.decodeFile(imgPath, newOpts);\n        newOpts.inJustDecodeBounds = false;\n        int width = newOpts.outWidth;\n        int height = newOpts.outHeight;\n        float maxSize = config.getMaxPixel();\n        int be = 1;\n        if (width >= height && width > maxSize) {//缩放比,用高或者宽其中较大的一个数据进行计算\n            be = (int) (newOpts.outWidth / maxSize);\n            be++;\n        } else if (width < height && height > maxSize) {\n            be = (int) (newOpts.outHeight / maxSize);\n            be++;\n        }\n        newOpts.inSampleSize = be;//设置采样率\n        newOpts.inPreferredConfig = Config.ARGB_8888;//该模式是默认的,可不设\n        newOpts.inPurgeable = true;// 同时设置才会有效\n        newOpts.inInputShareable = true;//。当系统内存不够时候图片自动被回收\n        Bitmap bitmap = BitmapFactory.decodeFile(imgPath, newOpts);\n        if (config.isEnableQualityCompress()) {\n            compressImageByQuality(bitmap, imgPath, listener);//压缩好比例大小后再进行质量压缩\n        } else {\n            File thumbnailFile = getThumbnailFile(new File(imgPath));\n            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(thumbnailFile));\n\n            listener.onCompressSuccess(thumbnailFile.getPath());\n        }\n    }\n\n    /**\n     * 发送压缩结果的消息\n     *\n     * @param isSuccess 压缩是否成功\n     * @param imagePath\n     * @param message\n     */\n    private void sendMsg(final boolean isSuccess, final String imagePath, final String message, final CompressListener listener) {\n        mhHandler.post(new Runnable() {\n            @Override\n            public void run() {\n                if (isSuccess) {\n                    listener.onCompressSuccess(imagePath);\n                } else {\n                    listener.onCompressFailed(imagePath, message);\n                }\n            }\n        });\n    }\n\n    private File getThumbnailFile(File file) {\n        if (file == null || !file.exists()) {\n            return file;\n        }\n        return TFileUtils.getPhotoCacheDir(context, file);\n    }\n\n    /**\n     * 压缩结果监听器\n     */\n    public interface CompressListener {\n        /**\n         * 压缩成功\n         *\n         * @param imgPath 压缩图片的路径\n         */\n        void onCompressSuccess(String imgPath);\n\n        /**\n         * 压缩失败\n         *\n         * @param imgPath 压缩失败的图片\n         * @param msg     失败的原因\n         */\n        void onCompressFailed(String imgPath, String msg);\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/compress/CompressWithLuBan.java",
    "content": "package org.devio.takephoto.compress;\n\nimport android.content.Context;\n\nimport org.devio.takephoto.model.LubanOptions;\nimport org.devio.takephoto.model.TImage;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport me.shaohui.advancedluban.Luban;\nimport me.shaohui.advancedluban.OnCompressListener;\nimport me.shaohui.advancedluban.OnMultiCompressListener;\n\n/**\n * 压缩照片,采用luban\n * Author: crazycodeboy\n * Date: 2016/11/5 0007 20:10\n * Version:4.0.0\n * 技术博文：http://www.devio.org/\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class CompressWithLuBan implements CompressImage {\n    private ArrayList<TImage> images;\n    private CompressListener listener;\n    private Context context;\n    private LubanOptions options;\n    private ArrayList<File> files = new ArrayList<>();\n\n    public CompressWithLuBan(Context context, CompressConfig config, ArrayList<TImage> images, CompressListener listener) {\n        options = config.getLubanOptions();\n        this.images = images;\n        this.listener = listener;\n        this.context = context;\n    }\n\n    @Override\n    public void compress() {\n        if (images == null || images.isEmpty()) {\n            listener.onCompressFailed(images, \" images is null\");\n            return;\n        }\n        for (TImage image : images) {\n            if (image == null) {\n                listener.onCompressFailed(images, \" There are pictures of compress  is null.\");\n                return;\n            }\n            files.add(new File(image.getOriginalPath()));\n        }\n        if (images.size() == 1) {\n            compressOne();\n        } else {\n            compressMulti();\n        }\n    }\n\n    private void compressOne() {\n        Luban.compress(context, files.get(0))\n            .putGear(Luban.CUSTOM_GEAR)\n            .setMaxHeight(options.getMaxHeight())\n            .setMaxWidth(options.getMaxWidth())\n            .setMaxSize(options.getMaxSize() / 1000)\n            .launch(new OnCompressListener() {\n                @Override\n                public void onStart() {\n\n                }\n\n                @Override\n                public void onSuccess(File file) {\n                    TImage image = images.get(0);\n                    image.setCompressPath(file.getPath());\n                    image.setCompressed(true);\n                    listener.onCompressSuccess(images);\n                }\n\n                @Override\n                public void onError(Throwable e) {\n                    listener.onCompressFailed(images, e.getMessage() + \" is compress failures\");\n                }\n            });\n    }\n\n    private void compressMulti() {\n        Luban.compress(context, files)\n            .putGear(Luban.CUSTOM_GEAR)\n            .setMaxSize(options.getMaxSize() / 1000)                // limit the final image size（unit：Kb）\n            .setMaxHeight(options.getMaxHeight())             // limit image height\n            .setMaxWidth(options.getMaxWidth())\n            .launch(new OnMultiCompressListener() {\n                @Override\n                public void onStart() {\n\n                }\n\n                @Override\n                public void onSuccess(List<File> fileList) {\n                    handleCompressCallBack(fileList);\n                }\n\n                @Override\n                public void onError(Throwable e) {\n                    listener.onCompressFailed(images, e.getMessage() + \" is compress failures\");\n                }\n            });\n    }\n\n    private void handleCompressCallBack(List<File> files) {\n        for (int i = 0, j = images.size(); i < j; i++) {\n            TImage image = images.get(i);\n            image.setCompressed(true);\n            image.setCompressPath(files.get(i).getPath());\n        }\n        listener.onCompressSuccess(images);\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/model/CropOptions.java",
    "content": "package org.devio.takephoto.model;\n\nimport java.io.Serializable;\n\n/**\n * 裁剪配置类\n * Author: JPH\n * Date: 2016/7/27 13:19\n */\npublic class CropOptions implements Serializable {\n    /**\n     * 使用TakePhoto自带的裁切工具进行裁切\n     */\n    private boolean withOwnCrop;\n    private int aspectX;\n    private int aspectY;\n    private int outputX;\n    private int outputY;\n\n    private CropOptions() {\n    }\n\n    public int getAspectX() {\n        return aspectX;\n    }\n\n    public void setAspectX(int aspectX) {\n        this.aspectX = aspectX;\n    }\n\n    public int getAspectY() {\n        return aspectY;\n    }\n\n    public void setAspectY(int aspectY) {\n        this.aspectY = aspectY;\n    }\n\n    public int getOutputX() {\n        return outputX;\n    }\n\n    public void setOutputX(int outputX) {\n        this.outputX = outputX;\n    }\n\n    public int getOutputY() {\n        return outputY;\n    }\n\n    public void setOutputY(int outputY) {\n        this.outputY = outputY;\n    }\n\n    public boolean isWithOwnCrop() {\n        return withOwnCrop;\n    }\n\n    public void setWithOwnCrop(boolean withOwnCrop) {\n        this.withOwnCrop = withOwnCrop;\n    }\n\n    public static class Builder {\n        private CropOptions options;\n\n        public Builder() {\n            options = new CropOptions();\n        }\n\n        public Builder setAspectX(int aspectX) {\n            options.setAspectX(aspectX);\n            return this;\n        }\n\n        public Builder setAspectY(int aspectY) {\n            options.setAspectY(aspectY);\n            return this;\n        }\n\n        public Builder setOutputX(int outputX) {\n            options.setOutputX(outputX);\n            return this;\n        }\n\n        public Builder setOutputY(int outputY) {\n            options.setOutputY(outputY);\n            return this;\n        }\n\n        public Builder setWithOwnCrop(boolean withOwnCrop) {\n            options.setWithOwnCrop(withOwnCrop);\n            return this;\n        }\n\n        public CropOptions create() {\n            return options;\n        }\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/model/InvokeParam.java",
    "content": "package org.devio.takephoto.model;\n\nimport java.lang.reflect.Method;\n\n/**\n * Created by penn on 16/9/22.\n */\npublic class InvokeParam {\n    private Object proxy;\n    private Method method;\n    private Object[] args;\n\n    public InvokeParam(Object proxy, Method method, Object[] args) {\n        this.proxy = proxy;\n        this.method = method;\n        this.args = args;\n    }\n\n    public Object getProxy() {\n        return proxy;\n    }\n\n    public void setProxy(Object proxy) {\n        this.proxy = proxy;\n    }\n\n    public Method getMethod() {\n        return method;\n    }\n\n    public void setMethod(Method method) {\n        this.method = method;\n    }\n\n    public Object[] getArgs() {\n        return args;\n    }\n\n    public void setArgs(Object[] args) {\n        this.args = args;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/model/LubanOptions.java",
    "content": "package org.devio.takephoto.model;\n\nimport java.io.Serializable;\n\n/**\n * Luban配置类\n * Author: crazycodeboy\n * Date: 2016/11/5 0007 20:10\n * Version:4.0.1\n * 技术博文：http://www.devio.org/\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class LubanOptions implements Serializable {\n    /**\n     * 压缩到的最大大小，单位B\n     */\n    private int maxSize;\n    private int maxHeight;\n    private int maxWidth;\n\n    private LubanOptions() {\n    }\n\n    public int getMaxSize() {\n        return maxSize;\n    }\n\n    public void setMaxSize(int maxSize) {\n        this.maxSize = maxSize;\n    }\n\n    public int getMaxHeight() {\n        return maxHeight;\n    }\n\n    public void setMaxHeight(int maxHeight) {\n        this.maxHeight = maxHeight;\n    }\n\n    public int getMaxWidth() {\n        return maxWidth;\n    }\n\n    public void setMaxWidth(int maxWidth) {\n        this.maxWidth = maxWidth;\n    }\n\n    public static class Builder {\n        private LubanOptions options;\n\n        public Builder() {\n            options = new LubanOptions();\n        }\n\n        public Builder setMaxSize(int maxSize) {\n            options.setMaxSize(maxSize);\n            return this;\n        }\n\n        public Builder setMaxHeight(int maxHeight) {\n            options.setMaxHeight(maxHeight);\n            return this;\n        }\n\n        public Builder setMaxWidth(int maxWidth) {\n            options.setMaxWidth(maxWidth);\n            return this;\n        }\n\n        public LubanOptions create() {\n            return options;\n        }\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/model/MultipleCrop.java",
    "content": "package org.devio.takephoto.model;\n\nimport android.app.Activity;\nimport android.net.Uri;\n\nimport org.devio.takephoto.uitl.TImageFiles;\nimport org.devio.takephoto.uitl.TUtils;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Author: JPH\n * Date: 2016/8/11 17:01\n */\npublic class MultipleCrop {\n    private ArrayList<Uri> uris;\n    private ArrayList<Uri> outUris;\n    private ArrayList<TImage> tImages;\n    private TImage.FromType fromType;\n    public boolean hasFailed;//是否有裁切失败的标识\n\n    public static MultipleCrop of(ArrayList<Uri> uris, Activity activity, TImage.FromType fromType) throws TException {\n        return new MultipleCrop(uris, activity, fromType);\n    }\n\n    public static MultipleCrop of(ArrayList<Uri> uris, ArrayList<Uri> outUris, TImage.FromType fromType) {\n        return new MultipleCrop(uris, outUris, fromType);\n    }\n\n    private MultipleCrop(ArrayList<Uri> uris, Activity activity, TImage.FromType fromType) throws TException {\n        this.uris = uris;\n        ArrayList<Uri> outUris = new ArrayList<>();\n        for (Uri uri : uris) {\n            outUris.add(Uri.fromFile(TImageFiles.getTempFile(activity, uri)));//生成临时裁切输出路径\n        }\n        this.outUris = outUris;\n        this.tImages = TUtils.getTImagesWithUris(outUris, fromType);\n        this.fromType = fromType;\n    }\n\n    private MultipleCrop(ArrayList<Uri> uris, ArrayList<Uri> outUris, TImage.FromType fromType) {\n        this.uris = uris;\n        this.outUris = outUris;\n        this.tImages = TUtils.getTImagesWithUris(outUris, fromType);\n        this.fromType = fromType;\n    }\n\n    public ArrayList<Uri> getUris() {\n        return uris;\n    }\n\n    public void setUris(ArrayList<Uri> uris) {\n        this.uris = uris;\n    }\n\n    public ArrayList<Uri> getOutUris() {\n        return outUris;\n    }\n\n    public void setOutUris(ArrayList<Uri> outUris) {\n        this.outUris = outUris;\n    }\n\n    public ArrayList<TImage> gettImages() {\n        return tImages;\n    }\n\n    public void settImages(ArrayList<TImage> tImages) {\n        this.tImages = tImages;\n    }\n\n    /**\n     * 为被裁切的图片设置已被裁切的标识\n     *\n     * @param uri 被裁切的图片\n     * @return 该图片是否是最后一张\n     */\n    public Map setCropWithUri(Uri uri, boolean cropped) {\n        if (!cropped) {\n            hasFailed = true;\n        }\n        int index = outUris.indexOf(uri);\n        tImages.get(index).setCropped(cropped);\n        Map result = new HashMap();\n        result.put(\"index\", index);\n        result.put(\"isLast\", index == outUris.size() - 1 ? true : false);\n        return result;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/model/TContextWrap.java",
    "content": "package org.devio.takephoto.model;\n\nimport android.app.Activity;\nimport android.support.v4.app.Fragment;\n\n/**\n * Author: JPH\n * Date: 2016/8/11 17:01\n */\npublic class TContextWrap {\n    private Activity activity;\n    private Fragment fragment;\n\n    public static TContextWrap of(Activity activity) {\n        return new TContextWrap(activity);\n    }\n\n    public static TContextWrap of(Fragment fragment) {\n        return new TContextWrap(fragment);\n    }\n\n    private TContextWrap(Activity activity) {\n        this.activity = activity;\n    }\n\n    private TContextWrap(Fragment fragment) {\n        this.fragment = fragment;\n        this.activity = fragment.getActivity();\n    }\n\n    public Activity getActivity() {\n        return activity;\n    }\n\n    public void setActivity(Activity activity) {\n        this.activity = activity;\n    }\n\n    public Fragment getFragment() {\n        return fragment;\n    }\n\n    public void setFragment(Fragment fragment) {\n        this.fragment = fragment;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/model/TException.java",
    "content": "package org.devio.takephoto.model;\n\n/**\n * Author: JPH\n * Date: 2016/7/26 10:53\n */\npublic class TException extends Exception {\n    String detailMessage;\n\n    public TException(TExceptionType exceptionType) {\n        super(exceptionType.getStringValue());\n        this.detailMessage = exceptionType.getStringValue();\n    }\n\n    public String getDetailMessage() {\n        return detailMessage;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/model/TExceptionType.java",
    "content": "package org.devio.takephoto.model;\n\n/**\n * Author: JPH\n * Date: 2016/7/26 11:01\n */\npublic enum TExceptionType {\n    TYPE_NOT_IMAGE(\"选择的文件不是图片\"), TYPE_WRITE_FAIL(\"保存选择的的文件失败\"), TYPE_URI_NULL(\"所选照片的Uri 为null\"), TYPE_URI_PARSE_FAIL(\"从Uri中获取文件路径失败\"),\n    TYPE_NO_MATCH_PICK_INTENT(\"没有匹配到选择图片的Intent\"), TYPE_NO_MATCH_CROP_INTENT(\"没有匹配到裁切图片的Intent\"), TYPE_NO_CAMERA(\"没有相机\"),\n    TYPE_NO_FIND(\"选择的文件没有找到\");\n\n    String stringValue;\n\n    TExceptionType(String stringValue) {\n        this.stringValue = stringValue;\n    }\n\n    public String getStringValue() {\n        return stringValue;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/model/TImage.java",
    "content": "package org.devio.takephoto.model;\n\nimport android.net.Uri;\n\nimport java.io.Serializable;\n\n/**\n * TakePhoto 操作成功返回的处理结果\n * <p>\n * Author: JPH\n * Date: 2016/8/11 17:01\n */\npublic class TImage implements Serializable {\n    private String originalPath;\n    private String compressPath;\n    private FromType fromType;\n    private boolean cropped;\n    private boolean compressed;\n\n    public static TImage of(String path, FromType fromType) {\n        return new TImage(path, fromType);\n    }\n\n    public static TImage of(Uri uri, FromType fromType) {\n        return new TImage(uri, fromType);\n    }\n\n    private TImage(String path, FromType fromType) {\n        this.originalPath = path;\n        this.fromType = fromType;\n    }\n\n    private TImage(Uri uri, FromType fromType) {\n        this.originalPath = uri.getPath();\n        this.fromType = fromType;\n    }\n\n    public String getOriginalPath() {\n        return originalPath;\n    }\n\n    public void setOriginalPath(String originalPath) {\n        this.originalPath = originalPath;\n    }\n\n    public String getCompressPath() {\n        return compressPath;\n    }\n\n    public void setCompressPath(String compressPath) {\n        this.compressPath = compressPath;\n    }\n\n    public FromType getFromType() {\n        return fromType;\n    }\n\n    public void setFromType(FromType fromType) {\n        this.fromType = fromType;\n    }\n\n    public boolean isCropped() {\n        return cropped;\n    }\n\n    public void setCropped(boolean cropped) {\n        this.cropped = cropped;\n    }\n\n    public boolean isCompressed() {\n        return compressed;\n    }\n\n    public void setCompressed(boolean compressed) {\n        this.compressed = compressed;\n    }\n\n    public enum FromType {\n        CAMERA, OTHER\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/model/TIntentWap.java",
    "content": "package org.devio.takephoto.model;\n\nimport android.content.Intent;\n\n/**\n * Author: JPH\n * Date: 2016/7/26 14:23\n */\npublic class TIntentWap {\n    private Intent intent;\n    private int requestCode;\n\n    public TIntentWap() {\n    }\n\n    public TIntentWap(Intent intent, int requestCode) {\n        this.intent = intent;\n        this.requestCode = requestCode;\n    }\n\n    public Intent getIntent() {\n        return intent;\n    }\n\n    public void setIntent(Intent intent) {\n        this.intent = intent;\n    }\n\n    public int getRequestCode() {\n        return requestCode;\n    }\n\n    public void setRequestCode(int requestCode) {\n        this.requestCode = requestCode;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/model/TResult.java",
    "content": "package org.devio.takephoto.model;\n\nimport java.util.ArrayList;\n\n/**\n * TakePhoto 操作成功返回的处理结果\n * Author: JPH\n * Date: 2016/8/11 17:01\n */\npublic class TResult {\n    private ArrayList<TImage> images;\n    private TImage image;\n\n    public static TResult of(TImage image) {\n        ArrayList<TImage> images = new ArrayList<>(1);\n        images.add(image);\n        return new TResult(images);\n    }\n\n    public static TResult of(ArrayList<TImage> images) {\n        return new TResult(images);\n    }\n\n    private TResult(ArrayList<TImage> images) {\n        this.images = images;\n        if (images != null && !images.isEmpty()) {\n            this.image = images.get(0);\n        }\n    }\n\n    public ArrayList<TImage> getImages() {\n        return images;\n    }\n\n    public void setImages(ArrayList<TImage> images) {\n        this.images = images;\n    }\n\n    public TImage getImage() {\n        return image;\n    }\n\n    public void setImage(TImage image) {\n        this.image = image;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/model/TakePhotoOptions.java",
    "content": "package org.devio.takephoto.model;\n\nimport java.io.Serializable;\n\n/**\n * Author: crazycodeboy\n * Date: 2016/11/5 0007 20:10\n * Version:4.0.0\n * 技术博文：http://www.devio.org/\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class TakePhotoOptions implements Serializable {\n    /**\n     * 是否使用TakePhoto自带的相册进行图片选择，默认不使用，但选择多张图片会使用\n     */\n    private boolean withOwnGallery;\n    /**\n     * 是对拍的照片进行旋转角度纠正\n     */\n    private boolean correctImage;\n\n    private TakePhotoOptions() {\n    }\n\n    public boolean isWithOwnGallery() {\n        return withOwnGallery;\n    }\n\n    public void setWithOwnGallery(boolean withOwnGallery) {\n        this.withOwnGallery = withOwnGallery;\n    }\n\n    public boolean isCorrectImage() {\n        return correctImage;\n    }\n\n    public void setCorrectImage(boolean correctImage) {\n        this.correctImage = correctImage;\n    }\n\n    public static class Builder {\n        private TakePhotoOptions options;\n\n        public Builder() {\n            this.options = new TakePhotoOptions();\n        }\n\n        public Builder setWithOwnGallery(boolean withOwnGallery) {\n            options.setWithOwnGallery(withOwnGallery);\n            return this;\n        }\n\n        public Builder setCorrectImage(boolean isCorrectImage) {\n            options.setCorrectImage(isCorrectImage);\n            return this;\n        }\n\n        public TakePhotoOptions create() {\n            return options;\n        }\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/permission/InvokeListener.java",
    "content": "package org.devio.takephoto.permission;\n\nimport org.devio.takephoto.model.InvokeParam;\n\n/**\n * 授权管理回调\n */\npublic interface InvokeListener {\n    PermissionManager.TPermissionType invoke(InvokeParam invokeParam);\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/permission/PermissionManager.java",
    "content": "package org.devio.takephoto.permission;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android.content.pm.PackageManager;\nimport android.support.annotation.NonNull;\nimport android.support.v4.app.ActivityCompat;\nimport android.support.v4.content.ContextCompat;\nimport android.text.TextUtils;\nimport android.widget.Toast;\n\nimport org.devio.takephoto.app.TakePhoto;\nimport org.devio.takephoto.model.InvokeParam;\nimport org.devio.takephoto.model.TContextWrap;\nimport org.devio.takephoto.uitl.TConstant;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\n\n/**\n * Created by penn on 16/9/22.\n */\npublic class PermissionManager {\n    public enum TPermission {\n        STORAGE(Manifest.permission.WRITE_EXTERNAL_STORAGE), CAMERA(Manifest.permission.CAMERA);\n        String stringValue;\n\n        TPermission(String stringValue) {\n            this.stringValue = stringValue;\n        }\n\n        public String stringValue() {\n            return stringValue;\n        }\n    }\n\n\n    public enum TPermissionType {\n        GRANTED(\"已授权\"), DENIED(\"未授权\"), WAIT(\"等待授权\"), NOT_NEED(\"无需授权\"), ONLY_CAMERA_DENIED(\"没有拍照权限\"), ONLY_STORAGE_DENIED(\"没有读写SD卡权限\");\n        String stringValue;\n\n        TPermissionType(String stringValue) {\n            this.stringValue = stringValue;\n        }\n\n        public String stringValue() {\n            return stringValue;\n        }\n    }\n\n\n    private final static String[] methodNames =\n        {\"onPickFromCapture\", \"onPickFromCaptureWithCrop\", \"onPickMultiple\", \"onPickMultipleWithCrop\", \"onPickFromDocuments\",\n            \"onPickFromDocumentsWithCrop\", \"onPickFromGallery\", \"onPickFromGalleryWithCrop\", \"onCrop\"};\n\n    /**\n     * 检查当前应用是否被授予相应权限\n     *\n     * @param contextWrap\n     * @param method\n     * @return\n     */\n    public static TPermissionType checkPermission(@NonNull TContextWrap contextWrap, @NonNull Method method) {\n        String methodName = method.getName();\n        boolean contain = false;\n        for (int i = 0, j = methodNames.length; i < j; i++) {\n            if (TextUtils.equals(methodName, methodNames[i])) {\n                contain = true;\n                break;\n            }\n        }\n        if (!contain) {\n            return TPermissionType.NOT_NEED;\n        }\n\n        boolean cameraGranted = true, storageGranted =\n            ContextCompat.checkSelfPermission(contextWrap.getActivity(), TPermission.STORAGE.stringValue())\n                == PackageManager.PERMISSION_GRANTED ? true : false;\n\n        if (TextUtils.equals(methodName, \"onPickFromCapture\") || TextUtils.equals(methodName, \"onPickFromCaptureWithCrop\")) {\n            cameraGranted = ContextCompat.checkSelfPermission(contextWrap.getActivity(), TPermission.CAMERA.stringValue())\n                == PackageManager.PERMISSION_GRANTED ? true : false;\n        }\n\n        boolean granted = storageGranted && cameraGranted;\n        if (!granted) {\n            ArrayList<String> permissions = new ArrayList<>();\n            if (!storageGranted) {\n                permissions.add(TPermission.STORAGE.stringValue());\n            }\n            if (!cameraGranted) {\n                permissions.add(TPermission.CAMERA.stringValue());\n            }\n            requestPermission(contextWrap, permissions.toArray(new String[permissions.size()]));\n        }\n        return granted ? TPermissionType.GRANTED : TPermissionType.WAIT;\n    }\n\n    public static void requestPermission(@NonNull TContextWrap contextWrap, @NonNull String[] permissions) {\n        if (contextWrap.getFragment() != null) {\n            contextWrap.getFragment().requestPermissions(permissions, TConstant.PERMISSION_REQUEST_TAKE_PHOTO);\n        } else {\n            ActivityCompat.requestPermissions(contextWrap.getActivity(), permissions, TConstant.PERMISSION_REQUEST_TAKE_PHOTO);\n        }\n    }\n\n    public static TPermissionType onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        if (requestCode == TConstant.PERMISSION_REQUEST_TAKE_PHOTO) {\n            boolean cameraGranted = true, storageGranted = true;\n            for (int i = 0, j = permissions.length; i < j; i++) {\n                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {\n                    if (TextUtils.equals(TPermission.STORAGE.stringValue(), permissions[i])) {\n                        storageGranted = false;\n                    } else if (TextUtils.equals(TPermission.CAMERA.stringValue(), permissions[i])) {\n                        cameraGranted = false;\n                    }\n                }\n            }\n            if (cameraGranted && storageGranted) {\n                return TPermissionType.GRANTED;\n            }\n            if (!cameraGranted && storageGranted) {\n                return TPermissionType.ONLY_CAMERA_DENIED;\n            }\n            if (!storageGranted && cameraGranted) {\n                return TPermissionType.ONLY_STORAGE_DENIED;\n            }\n            if (!storageGranted && !cameraGranted) {\n                return TPermissionType.DENIED;\n            }\n        }\n        return TPermissionType.WAIT;\n    }\n\n    public static void handlePermissionsResult(Activity activity, TPermissionType type, InvokeParam invokeParam,\n        TakePhoto.TakeResultListener listener) {\n        String tip = null;\n        switch (type) {\n            case DENIED:\n                listener.takeFail(null, tip = activity.getResources().getString(org.devio.takephoto.R.string.tip_permission_camera_storage));\n                break;\n            case ONLY_CAMERA_DENIED:\n                listener.takeFail(null, tip = activity.getResources().getString(org.devio.takephoto.R.string.tip_permission_camera));\n                break;\n            case ONLY_STORAGE_DENIED:\n                listener.takeFail(null, tip = activity.getResources().getString(org.devio.takephoto.R.string.tip_permission_storage));\n                break;\n            case GRANTED:\n                try {\n                    invokeParam.getMethod().invoke(invokeParam.getProxy(), invokeParam.getArgs());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    listener.takeFail(null, tip = activity.getResources().getString(org.devio.takephoto.R.string.tip_permission_camera_storage));\n                }\n                break;\n            default:\n                break;\n        }\n        if (tip != null) {\n            Toast.makeText(activity, tip, Toast.LENGTH_LONG).show();\n        }\n\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/permission/TakePhotoInvocationHandler.java",
    "content": "package org.devio.takephoto.permission;\n\nimport org.devio.takephoto.app.TakePhoto;\nimport org.devio.takephoto.model.InvokeParam;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\n\npublic class TakePhotoInvocationHandler implements InvocationHandler {\n    private TakePhoto delegate;\n    private InvokeListener listener;\n\n    public static TakePhotoInvocationHandler of(InvokeListener listener) {\n        return new TakePhotoInvocationHandler(listener);\n    }\n\n    private TakePhotoInvocationHandler(InvokeListener listener) {\n        this.listener = listener;\n    }\n\n    /**\n     * 绑定委托对象并返回一个代理类\n     *\n     * @param delegate\n     * @return\n     */\n    public Object bind(TakePhoto delegate) {\n        this.delegate = delegate;\n        return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);\n    }\n\n    @Override\n    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n        PermissionManager.TPermissionType type = listener.invoke(new InvokeParam(proxy, method, args));\n        if (proxy instanceof TakePhoto) {\n            if (!PermissionManager.TPermissionType.NOT_NEED.equals(type)) {\n                ((TakePhoto) proxy).permissionNotify(type);\n            }\n        }\n        return method.invoke(delegate, args);\n    }\n}"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/uitl/ImageRotateUtil.java",
    "content": "package org.devio.takephoto.uitl;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Matrix;\nimport android.media.ExifInterface;\nimport android.net.Uri;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\n/**\n * 图片旋转角度修正工具类\n * Author: crazycodeboy\n * Date: 2016/9/21 0007 20:10\n * Version:3.0.0\n * 技术博文：http://www.devio.org\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class ImageRotateUtil {\n\n    public static ImageRotateUtil of() {\n        return new ImageRotateUtil();\n    }\n\n    private ImageRotateUtil() {\n    }\n\n    /**\n     * 纠正照片的旋转角度\n     *\n     * @param path\n     */\n    public void correctImage(Context context, Uri path) {\n\n        String imagePath = TUriParse.parseOwnUri(context, path);\n        int degree;\n        if ((degree = getBitmapDegree(imagePath)) != 0) {\n            Bitmap bitmap = BitmapFactory.decodeFile(imagePath);\n            if (bitmap == null) {\n                return;\n            }\n            Bitmap resultBitmap = rotateBitmapByDegree(bitmap, degree);\n            if (resultBitmap == null) {\n                return;\n            }\n            try {\n                resultBitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(new File(imagePath)));\n            } catch (FileNotFoundException e) {\n                e.printStackTrace();\n            } catch (OutOfMemoryError e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    /**\n     * 读取图片的旋转的角度\n     *\n     * @param path 图片绝对路径\n     * @return 图片的旋转角度\n     */\n    private int getBitmapDegree(String path) {\n        int degree = 0;\n        try {\n            // 从指定路径下读取图片，并获取其EXIF信息\n            ExifInterface exifInterface = new ExifInterface(path);\n            // 获取图片的旋转信息\n            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);\n            switch (orientation) {\n                case ExifInterface.ORIENTATION_ROTATE_90:\n                    degree = 90;\n                    break;\n                case ExifInterface.ORIENTATION_ROTATE_180:\n                    degree = 180;\n                    break;\n                case ExifInterface.ORIENTATION_ROTATE_270:\n                    degree = 270;\n                    break;\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return degree;\n    }\n\n    /**\n     * 将图片按照某个角度进行旋转\n     *\n     * @param bm     需要旋转的图片\n     * @param degree 旋转角度\n     * @return 旋转后的图片\n     */\n    private Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {\n        Bitmap returnBm = null;\n\n        // 根据旋转角度，生成旋转矩阵\n        Matrix matrix = new Matrix();\n        matrix.postRotate(degree);\n        try {\n            // 将原始图片按照旋转矩阵进行旋转，并得到新的图片\n            returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);\n        } catch (OutOfMemoryError e) {\n        }\n        if (returnBm == null) {\n            returnBm = bm;\n        }\n        if (bm != returnBm) {\n            bm.recycle();\n        }\n        return returnBm;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/uitl/IntentUtils.java",
    "content": "package org.devio.takephoto.uitl;\n\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.provider.MediaStore;\nimport android.util.Log;\n\nimport com.darsh.multipleimageselect.activities.AlbumSelectActivity;\nimport com.darsh.multipleimageselect.helpers.Constants;\nimport org.devio.takephoto.model.CropOptions;\nimport org.devio.takephoto.model.TContextWrap;\n\n/**\n * Intent工具类用于生成拍照、\n * 从相册选择照片，裁剪照片所需的Intent\n * Author: JPH\n * Date: 2016/6/7 0007 13:41\n */\npublic class IntentUtils {\n    private static final String TAG = IntentUtils.class.getName();\n\n    /**\n     * 获取图片多选的Intent\n     *\n     * @param limit 最多选择图片张数的限制\n     */\n    public static Intent getPickMultipleIntent(TContextWrap contextWrap, int limit) {\n        Intent intent = new Intent(contextWrap.getActivity(), AlbumSelectActivity.class);\n        intent.putExtra(Constants.INTENT_EXTRA_LIMIT, limit > 0 ? limit : 1);\n        return intent;\n    }\n\n    /**\n     * 获取裁剪照片的Intent\n     *\n     * @param targetUri 要裁剪的照片\n     * @param outPutUri 裁剪完成的照片\n     * @param options   裁剪配置\n     * @return\n     */\n    public static Intent getCropIntentWithOtherApp(Uri targetUri, Uri outPutUri, CropOptions options) {\n        boolean isReturnData = TUtils.isReturnData();\n        Log.w(TAG, \"getCaptureIntentWithCrop:isReturnData:\" + (isReturnData ? \"true\" : \"false\"));\n        Intent intent = new Intent(\"com.android.camera.action.CROP\");\n        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);\n        intent.setDataAndType(targetUri, \"image/*\");\n        intent.putExtra(\"crop\", \"true\");\n        if (options.getAspectX() * options.getAspectY() > 0) {\n            intent.putExtra(\"aspectX\", options.getAspectX());\n            intent.putExtra(\"aspectY\", options.getAspectY());\n        }\n        if (options.getOutputX() * options.getOutputY() > 0) {\n            intent.putExtra(\"outputX\", options.getOutputX());\n            intent.putExtra(\"outputY\", options.getOutputY());\n        }\n        intent.putExtra(\"scale\", true);\n        intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutUri);\n        intent.putExtra(\"return-data\", isReturnData);\n        intent.putExtra(\"outputFormat\", Bitmap.CompressFormat.JPEG.toString());\n        intent.putExtra(\"noFaceDetection\", true); // no face detection\n        return intent;\n    }\n\n    /**\n     * 获取拍照的Intent\n     *\n     * @return\n     */\n    public static Intent getCaptureIntent(Uri outPutUri) {\n        Intent intent = new Intent();\n        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);\n        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照\n        intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutUri);//将拍取的照片保存到指定URI\n        return intent;\n    }\n\n    /**\n     * 获取选择照片的Intent\n     *\n     * @return\n     */\n    public static Intent getPickIntentWithGallery() {\n        Intent intent = new Intent();\n        intent.setAction(Intent.ACTION_PICK);//Pick an item from the data\n        intent.setType(\"image/*\");//从所有图片中进行选择\n        return intent;\n    }\n\n    /**\n     * 获取从文件中选择照片的Intent\n     *\n     * @return\n     */\n    public static Intent getPickIntentWithDocuments() {\n        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);\n        intent.setType(\"image/*\");\n        return intent;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/uitl/TConstant.java",
    "content": "package org.devio.takephoto.uitl;\n\nimport android.content.Context;\n\n/**\n * 常量类\n *\n * @author JPH\n *         Date 2016/6/7 0007 9:39\n */\npublic class TConstant {\n\n\n    /**\n     * request Code 裁剪照片\n     **/\n    public final static int RC_CROP = 1001;\n    /**\n     * request Code 从相机获取照片并裁剪\n     **/\n    public final static int RC_PICK_PICTURE_FROM_CAPTURE_CROP = 1002;\n    /**\n     * request Code 从相机获取照片不裁剪\n     **/\n    public final static int RC_PICK_PICTURE_FROM_CAPTURE = 1003;\n    /**\n     * request Code 从文件中选择照片\n     **/\n    public final static int RC_PICK_PICTURE_FROM_DOCUMENTS_ORIGINAL = 1004;\n    /**\n     * request Code 从文件中选择照片并裁剪\n     **/\n    public final static int RC_PICK_PICTURE_FROM_DOCUMENTS_CROP = 1005;\n    /**\n     * request Code 从相册选择照\n     **/\n    public final static int RC_PICK_PICTURE_FROM_GALLERY_ORIGINAL = 1006;\n    /**\n     * request Code 从相册选择照片并裁剪\n     **/\n    public final static int RC_PICK_PICTURE_FROM_GALLERY_CROP = 1007;\n    /**\n     * request Code 选择多张照片\n     **/\n    public final static int RC_PICK_MULTIPLE = 1008;\n\n\n    /**\n     * requestCode 请求权限\n     **/\n    public final static int PERMISSION_REQUEST_TAKE_PHOTO = 2000;\n\n    public final static String getFileProviderName(Context context) {\n        return context.getPackageName() + \".fileprovider\";\n    }\n}"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/uitl/TFileUtils.java",
    "content": "package org.devio.takephoto.uitl;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport java.io.File;\n\n/**\n * Author: crazycodeboy\n * Date: 2016/11/5 0007 20:10\n * Version:4.0.0\n * 技术博文：http://www.devio.org/\n * GitHub:https://github.com/crazycodeboy\n * Email:crazycodeboy@gmail.com\n */\npublic class TFileUtils {\n    private static final String TAG = \"TFileUtils\";\n    private static String DEFAULT_DISK_CACHE_DIR = \"takephoto_cache\";\n\n    public static File getPhotoCacheDir(Context context, File file) {\n        File cacheDir = context.getCacheDir();\n        if (cacheDir != null) {\n            File mCacheDir = new File(cacheDir, DEFAULT_DISK_CACHE_DIR);\n            if (!mCacheDir.mkdirs() && (!mCacheDir.exists() || !mCacheDir.isDirectory())) {\n                return file;\n            } else {\n                return new File(mCacheDir, file.getName());\n            }\n        }\n        if (Log.isLoggable(TAG, Log.ERROR)) {\n            Log.e(TAG, \"default disk cache dir is null\");\n        }\n        return file;\n    }\n\n    public static void delete(String path) {\n        try {\n            if (path == null) {\n                return;\n            }\n            File file = new File(path);\n            if (!file.delete()) {\n                file.deleteOnExit();\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/uitl/TImageFiles.java",
    "content": "package org.devio.takephoto.uitl;\n\nimport android.app.Activity;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.webkit.MimeTypeMap;\nimport android.widget.Toast;\n\nimport org.devio.takephoto.model.TException;\nimport org.devio.takephoto.model.TExceptionType;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.UUID;\n\n/**\n * ImageFiles工具类\n *\n * @author JPH\n *         Date 2016/6/7 0007 9:39\n */\npublic class TImageFiles {\n    private static final String TAG = IntentUtils.class.getName();\n\n    /**\n     * 将bitmap写入到文件\n     *\n     * @param bitmap\n     */\n    public static void writeToFile(Bitmap bitmap, Uri imageUri) {\n        if (bitmap == null) {\n            return;\n        }\n        File file = new File(imageUri.getPath());\n        ByteArrayOutputStream bos = new ByteArrayOutputStream();\n        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);\n        FileOutputStream fos = null;\n        try {\n            fos = new FileOutputStream(file);\n            fos.write(bos.toByteArray());\n            bos.flush();\n            fos.flush();\n        } catch (java.io.IOException e) {\n            e.printStackTrace();\n        } finally {\n            if (fos != null) {\n                try {\n                    fos.close();\n                    if (bos != null) {\n                        bos.close();\n                    }\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n\n    /**\n     * InputStream 转File\n     */\n    public static void inputStreamToFile(InputStream is, File file) throws TException {\n        if (file == null) {\n            Log.i(TAG, \"inputStreamToFile:file not be null\");\n            throw new TException(TExceptionType.TYPE_WRITE_FAIL);\n        }\n        FileOutputStream fos = null;\n        try {\n            fos = new FileOutputStream(file);\n            byte[] buffer = new byte[1024 * 10];\n            int i;\n            while ((i = is.read(buffer)) != -1) {\n                fos.write(buffer, 0, i);\n            }\n        } catch (IOException e) {\n            Log.e(TAG, \"InputStream 写入文件出错:\" + e.toString());\n            throw new TException(TExceptionType.TYPE_WRITE_FAIL);\n        } finally {\n            try {\n                fos.flush();\n                fos.close();\n                is.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    /**\n     * 获取临时文件\n     *\n     * @param context\n     * @param photoUri\n     * @return\n     */\n    public static File getTempFile(Activity context, Uri photoUri) throws TException {\n        String minType = getMimeType(context, photoUri);\n        if (!checkMimeType(context, minType)) {\n            throw new TException(TExceptionType.TYPE_NOT_IMAGE);\n        }\n        File filesDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);\n        if (!filesDir.exists()) {\n            filesDir.mkdirs();\n        }\n        File photoFile = new File(filesDir, UUID.randomUUID().toString() + \".\" + minType);\n        return photoFile;\n    }\n\n    /**\n     * 检查文件类型是否是图片\n     *\n     * @param minType\n     * @return\n     */\n    public static boolean checkMimeType(Context context, String minType) {\n        boolean isPicture =\n            TextUtils.isEmpty(minType) ? false : \".jpg|.gif|.png|.bmp|.jpeg|.webp|\".contains(minType.toLowerCase()) ? true : false;\n        if (!isPicture) {\n            Toast.makeText(context, context.getResources().getText(org.devio.takephoto.R.string.tip_type_not_image), Toast.LENGTH_SHORT).show();\n        }\n        return isPicture;\n    }\n\n    /**\n     * To find out the extension of required object in given uri\n     * Solution by http://stackoverflow.com/a/36514823/1171484\n     */\n    public static String getMimeType(Activity context, Uri uri) {\n        String extension;\n        //Check uri format to avoid null\n        if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {\n            //If scheme is a content\n            extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(context.getContentResolver().getType(uri));\n            if (TextUtils.isEmpty(extension)) {\n                extension = MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(new File(uri.getPath())).toString());\n            }\n        } else {\n            //If scheme is a File\n            //This will replace white spaces with %20 and also other special characters. This will avoid returning null values on file\n            // name with spaces and special characters.\n            extension = MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(new File(uri.getPath())).toString());\n            if (TextUtils.isEmpty(extension)) {\n                extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(context.getContentResolver().getType(uri));\n            }\n        }\n        if (TextUtils.isEmpty(extension)) {\n            extension = getMimeTypeByFileName(TUriParse.getFileWithUri(uri, context).getName());\n        }\n        return extension;\n    }\n\n    public static String getMimeTypeByFileName(String fileName) {\n        return fileName.substring(fileName.lastIndexOf(\".\"), fileName.length());\n    }\n}"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/uitl/TUriParse.java",
    "content": "package org.devio.takephoto.uitl;\n\nimport android.app.Activity;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.provider.MediaStore;\nimport android.support.v4.content.FileProvider;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport org.devio.takephoto.model.TException;\nimport org.devio.takephoto.model.TExceptionType;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\n\n\n/**\n * Uri解析工具类\n * Author: JPH\n * Date: 2015/8/26 0026 16:23\n */\npublic class TUriParse {\n    private static final String TAG = IntentUtils.class.getName();\n\n    /**\n     * 将scheme为file的uri转成FileProvider 提供的content uri\n     *\n     * @param context\n     * @param uri\n     * @return\n     */\n    public static Uri convertFileUriToFileProviderUri(Context context, Uri uri) {\n        if (uri == null) {\n            return null;\n        }\n        if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {\n            return getUriForFile(context, new File(uri.getPath()));\n        }\n        return uri;\n\n    }\n\n    /**\n     * 获取一个临时的Uri, 文件名随机生成\n     *\n     * @param context\n     * @return\n     */\n    public static Uri getTempUri(Context context) {\n        String timeStamp = new SimpleDateFormat(\"yyyyMMdd_HHmmss\", Locale.getDefault()).format(new Date());\n        File file = new File(Environment.getExternalStorageDirectory(), \"/images/\" + timeStamp + \".jpg\");\n        if (!file.getParentFile().exists()) {\n            file.getParentFile().mkdirs();\n        }\n        return getUriForFile(context, file);\n    }\n\n    /**\n     * 获取一个临时的Uri, 通过传入字符串路径\n     *\n     * @param context\n     * @param path\n     * @return\n     */\n    public static Uri getTempUri(Context context, String path) {\n        File file = new File(path);\n        return getTempUri(context, file);\n    }\n\n    /**\n     * 获取一个临时的Uri, 通过传入File对象\n     *\n     * @param context\n     * @return\n     */\n    public static Uri getTempUri(Context context, File file) {\n        if (!file.getParentFile().exists()) {\n            file.getParentFile().mkdirs();\n        }\n        return getUriForFile(context, file);\n    }\n\n    /**\n     * 创建一个用于拍照图片输出路径的Uri (FileProvider)\n     *\n     * @param context\n     * @return\n     */\n    public static Uri getUriForFile(Context context, File file) {\n        return FileProvider.getUriForFile(context, TConstant.getFileProviderName(context), file);\n    }\n\n    /**\n     * 将TakePhoto 提供的Uri 解析出文件绝对路径\n     *\n     * @param uri\n     * @return\n     */\n    public static String parseOwnUri(Context context, Uri uri) {\n        if (uri == null) {\n            return null;\n        }\n        String path;\n        if (TextUtils.equals(uri.getAuthority(), TConstant.getFileProviderName(context))) {\n            path = new File(uri.getPath().replace(\"camera_photos/\", \"\")).getAbsolutePath();\n        } else {\n            path = uri.getPath();\n        }\n        return path;\n    }\n\n    /**\n     * 通过URI获取文件的路径\n     *\n     * @param uri\n     * @param activity\n     * @return Author JPH\n     * Date 2016/6/6 0006 20:01\n     */\n    public static String getFilePathWithUri(Uri uri, Activity activity) throws TException {\n        if (uri == null) {\n            Log.w(TAG, \"uri is null,activity may have been recovered?\");\n            throw new TException(TExceptionType.TYPE_URI_NULL);\n        }\n        File picture = getFileWithUri(uri, activity);\n        String picturePath = picture == null ? null : picture.getPath();\n        if (TextUtils.isEmpty(picturePath)) {\n            throw new TException(TExceptionType.TYPE_URI_PARSE_FAIL);\n        }\n        if (!TImageFiles.checkMimeType(activity, TImageFiles.getMimeType(activity, uri))) {\n            throw new TException(TExceptionType.TYPE_NOT_IMAGE);\n        }\n        return picturePath;\n    }\n\n    /**\n     * 通过URI获取文件\n     *\n     * @param uri\n     * @param activity\n     * @return Author JPH\n     * Date 2016/10/25\n     */\n    public static File getFileWithUri(Uri uri, Activity activity) {\n        String picturePath = null;\n        String scheme = uri.getScheme();\n        if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {\n            String[] filePathColumn = {MediaStore.Images.Media.DATA};\n            Cursor cursor = activity.getContentResolver().query(uri, filePathColumn, null, null, null);//从系统表中查询指定Uri对应的照片\n            cursor.moveToFirst();\n            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);\n            if (columnIndex >= 0) {\n                picturePath = cursor.getString(columnIndex);  //获取照片路径\n            } else if (TextUtils.equals(uri.getAuthority(), TConstant.getFileProviderName(activity))) {\n                picturePath = parseOwnUri(activity, uri);\n            }\n            cursor.close();\n        } else if (ContentResolver.SCHEME_FILE.equals(scheme)) {\n            picturePath = uri.getPath();\n        }\n        return TextUtils.isEmpty(picturePath) ? null : new File(picturePath);\n    }\n\n    /**\n     * 通过从文件中得到的URI获取文件的路径\n     *\n     * @param uri\n     * @param activity\n     * @return Author JPH\n     * Date 2016/6/6 0006 20:01\n     */\n    public static String getFilePathWithDocumentsUri(Uri uri, Activity activity) throws TException {\n        if (uri == null) {\n            Log.e(TAG, \"uri is null,activity may have been recovered?\");\n            return null;\n        }\n        if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()) && uri.getPath().contains(\"document\")) {\n            File tempFile = TImageFiles.getTempFile(activity, uri);\n            try {\n                TImageFiles.inputStreamToFile(activity.getContentResolver().openInputStream(uri), tempFile);\n                return tempFile.getPath();\n            } catch (FileNotFoundException e) {\n                e.printStackTrace();\n                throw new TException(TExceptionType.TYPE_NO_FIND);\n            }\n        } else {\n            return getFilePathWithUri(uri, activity);\n        }\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/java/org/devio/takephoto/uitl/TUtils.java",
    "content": "package org.devio.takephoto.uitl;\n\nimport android.app.Activity;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.support.v4.content.FileProvider;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport com.darsh.multipleimageselect.models.Image;\nimport org.devio.takephoto.model.CropOptions;\nimport org.devio.takephoto.model.TException;\nimport org.devio.takephoto.model.TExceptionType;\nimport org.devio.takephoto.model.TImage;\nimport org.devio.takephoto.model.TIntentWap;\nimport org.devio.takephoto.R;\nimport org.devio.takephoto.model.TContextWrap;\nimport com.soundcloud.android.crop.Crop;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 工具类\n * Author: JPH\n * Date: 2016/7/26 10:04\n */\npublic class TUtils {\n    private static final String TAG = IntentUtils.class.getName();\n\n\n    /**\n     * 将Image集合转换成Uri集合\n     *\n     * @param images\n     * @return\n     */\n    public static ArrayList<Uri> convertImageToUri(Context context, ArrayList<Image> images) throws TException {\n        ArrayList<Uri> uris = new ArrayList();\n        for (Image image : images) {\n            uris.add(FileProvider.getUriForFile(context, TConstant.getFileProviderName(context), new File(image.path)));\n        }\n        return uris;\n    }\n\n    /**\n     * 将Image集合转换成TImage集合\n     *\n     * @param images\n     * @return\n     */\n    public static ArrayList<TImage> getTImagesWithImages(ArrayList<Image> images, TImage.FromType fromType) {\n        ArrayList<TImage> tImages = new ArrayList();\n        for (Image image : images) {\n            tImages.add(TImage.of(image.path, fromType));\n        }\n        return tImages;\n    }\n\n    /**\n     * 将Uri集合转换成TImage集合\n     *\n     * @param uris\n     * @return\n     */\n    public static ArrayList<TImage> getTImagesWithUris(ArrayList<Uri> uris, TImage.FromType fromType) {\n        ArrayList<TImage> tImages = new ArrayList();\n        for (Uri uri : uris) {\n            tImages.add(TImage.of(uri, fromType));\n        }\n        return tImages;\n    }\n\n    /**\n     * @param contextWrap\n     * @param intentWap\n     */\n    public static void startActivityForResult(TContextWrap contextWrap, TIntentWap intentWap) {\n        if (contextWrap.getFragment() != null) {\n            contextWrap.getFragment().startActivityForResult(intentWap.getIntent(), intentWap.getRequestCode());\n        } else {\n            contextWrap.getActivity().startActivityForResult(intentWap.getIntent(), intentWap.getRequestCode());\n        }\n    }\n\n    /**\n     * 安全地发送Intent\n     *\n     * @param contextWrap\n     * @param intentWapList 要发送的Intent以及候选Intent\n     * @param defaultIndex  默认发送的Intent\n     * @param isCrop        是否为裁切照片的Intent\n     * @throws TException\n     */\n    public static void sendIntentBySafely(TContextWrap contextWrap, List<TIntentWap> intentWapList, int defaultIndex, boolean isCrop)\n        throws TException {\n        if (defaultIndex + 1 > intentWapList.size()) {\n            throw new TException(isCrop ? TExceptionType.TYPE_NO_MATCH_PICK_INTENT : TExceptionType.TYPE_NO_MATCH_CROP_INTENT);\n        }\n        TIntentWap intentWap = intentWapList.get(defaultIndex);\n        List result = contextWrap.getActivity().getPackageManager().queryIntentActivities(intentWap.getIntent(), PackageManager.MATCH_ALL);\n        if (result.isEmpty()) {\n            sendIntentBySafely(contextWrap, intentWapList, ++defaultIndex, isCrop);\n        } else {\n            startActivityForResult(contextWrap, intentWap);\n        }\n    }\n\n    /**\n     * 拍照前检查是否有相机\n     **/\n    public static void captureBySafely(TContextWrap contextWrap, TIntentWap intentWap) throws TException {\n        List result = contextWrap.getActivity().getPackageManager().queryIntentActivities(intentWap.getIntent(), PackageManager.MATCH_ALL);\n        if (result.isEmpty()) {\n            Toast.makeText(contextWrap.getActivity(), contextWrap.getActivity().getResources().getText(R.string.tip_no_camera),\n                Toast.LENGTH_SHORT).show();\n            throw new TException(TExceptionType.TYPE_NO_CAMERA);\n        } else {\n            startActivityForResult(contextWrap, intentWap);\n        }\n    }\n\n    /**\n     * 通过第三方工具裁切照片，当没有第三方裁切工具时，会自动使用自带裁切工具进行裁切\n     *\n     * @param contextWrap\n     * @param imageUri\n     * @param outPutUri\n     * @param options\n     */\n    public static void cropWithOtherAppBySafely(TContextWrap contextWrap, Uri imageUri, Uri outPutUri, CropOptions options) {\n        Intent nativeCropIntent = IntentUtils.getCropIntentWithOtherApp(imageUri, outPutUri, options);\n        List result = contextWrap.getActivity().getPackageManager().queryIntentActivities(nativeCropIntent, PackageManager.MATCH_ALL);\n        if (result.isEmpty()) {\n            cropWithOwnApp(contextWrap, imageUri, outPutUri, options);\n        } else {\n            //            try {\n            //                imageUri=Uri.fromFile(new File(TUriParse.getFilePathWithDocumentsUri(imageUri,contextWrap.getActivity())));\n            //            } catch (TException e) {\n            //                e.printStackTrace();\n            //            }\n            startActivityForResult(contextWrap,\n                new TIntentWap(IntentUtils.getCropIntentWithOtherApp(imageUri, outPutUri, options), TConstant.RC_CROP));\n        }\n    }\n\n    /**\n     * 通过TakePhoto自带的裁切工具裁切图片\n     *\n     * @param contextWrap\n     * @param imageUri\n     * @param outPutUri\n     * @param options\n     */\n    public static void cropWithOwnApp(TContextWrap contextWrap, Uri imageUri, Uri outPutUri, CropOptions options) {\n        if (options.getAspectX() * options.getAspectY() > 0) {\n            if (contextWrap.getFragment() != null) {\n                Crop.of(imageUri, outPutUri)\n                    .withAspect(options.getAspectX(), options.getAspectY())\n                    .start(contextWrap.getActivity(), contextWrap.getFragment());\n            } else {\n                Crop.of(imageUri, outPutUri).withAspect(options.getAspectX(), options.getAspectY()).start(contextWrap.getActivity());\n            }\n        } else if (options.getOutputX() * options.getOutputY() > 0) {\n            if (contextWrap.getFragment() != null) {\n                Crop.of(imageUri, outPutUri)\n                    .withMaxSize(options.getOutputX(), options.getOutputY())\n                    .start(contextWrap.getActivity(), contextWrap.getFragment());\n            } else {\n                Crop.of(imageUri, outPutUri).withMaxSize(options.getOutputX(), options.getOutputY()).start(contextWrap.getActivity());\n            }\n        } else {\n            if (contextWrap.getFragment() != null) {\n                Crop.of(imageUri, outPutUri).asSquare().start(contextWrap.getActivity(), contextWrap.getFragment());\n            } else {\n                Crop.of(imageUri, outPutUri).asSquare().start(contextWrap.getActivity());\n            }\n        }\n    }\n\n    /**\n     * 是否裁剪之后返回数据\n     **/\n    public static boolean isReturnData() {\n        String release = Build.VERSION.RELEASE;\n        int sdk = Build.VERSION.SDK_INT;\n        Log.i(TAG, \"release:\" + release + \"sdk:\" + sdk);\n        String manufacturer = android.os.Build.MANUFACTURER;\n        if (!TextUtils.isEmpty(manufacturer)) {\n            if (manufacturer.toLowerCase().contains(\"lenovo\")) {//对于联想的手机返回数据\n                return true;\n            }\n        }\n        //        if (sdk>=21){//5.0或以上版本要求返回数据\n        //            return  true;\n        //        }\n        return false;\n    }\n\n    /**\n     * 显示圆形进度对话框\n     *\n     * @param activity\n     * @param progressTitle 显示的标题\n     * @return\n     * @author JPH\n     * Date 2014-12-12 下午7:04:09\n     */\n    public static ProgressDialog showProgressDialog(final Activity activity, String... progressTitle) {\n        if (activity == null || activity.isFinishing()) {\n            return null;\n        }\n        String title = activity.getResources().getString(R.string.tip_tips);\n        if (progressTitle != null && progressTitle.length > 0) {\n            title = progressTitle[0];\n        }\n        ProgressDialog progressDialog = new ProgressDialog(activity);\n        progressDialog.setTitle(title);\n        progressDialog.setCancelable(false);\n        progressDialog.show();\n        return progressDialog;\n    }\n}\n"
  },
  {
    "path": "takephoto_library/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "takephoto_library/src/main/res/values/strings.xml",
    "content": "<resources>\n    <!--TakePhoto-->\n    <string name=\"tip_type_not_image\">选择的不是图片</string>\n    <string name=\"tip_no_camera\">没有相机</string>\n    <string name=\"tip_tips\">提示</string>\n    <string name=\"tip_compress\">正在压缩照片...</string>\n    <string name=\"tip_compress_failed\">\"%1$s 图片压缩失败:%2$s picturePath:%3$s\"</string>\n    <string name=\"msg_crop_failed\">\"有裁切失败的图片\"</string>\n    <string name=\"msg_compress_failed\">\"有压缩失败的图片\"</string>\n    <string name=\"msg_crop_canceled\">\" 取消裁切\"</string>\n    <string name=\"msg_operation_canceled\">\"操作被取消\"</string>\n    <string name=\"tip_permission_camera\">没有使用相机的权限，请在权限管理中开启</string>\n    <string name=\"tip_permission_storage\">没有使用SD卡的权限，请在权限管理中开启</string>\n    <string name=\"tip_permission_camera_storage\">没有使用相机和SD卡的权限，请在权限管理中开启</string>\n\n    <!--custom multipleimageselect -->\n    <string name=\"album_view\">选择图片</string>\n    <string name=\"image_view\">单击选择</string>\n\n    <string name=\"add\">确定</string>\n    <string name=\"selected\">已选</string>\n    <string name=\"limit_exceeded\">最多能选 %d 张</string>\n\n</resources>\n"
  },
  {
    "path": "takephoto_library/src/main/res/values-en/strings.xml",
    "content": "<resources>\n    <!--TakePhoto-->\n    <string name=\"tip_type_not_image\">Choose not pictures</string>\n    <string name=\"tip_no_camera\">No camera</string>\n    <string name=\"tip_tips\">Tips</string>\n    <string name=\"tip_compress\">Being compressed...</string>\n    <string name=\"tip_compress_failed\">\"%1$s Picture compression failure:%2$s picturePath:%3$s\"</string>\n    <string name=\"msg_crop_failed\">\"There are pictures of crop failures.\"</string>\n    <string name=\"msg_compress_failed\">\"There are pictures of compress failures.\"</string>\n    <string name=\"msg_crop_canceled\">\" canceled crop\"</string>\n    <string name=\"msg_operation_canceled\">\"Operation canceled.\"</string>\n    <string name=\"tip_permission_camera\">No permission to use the camera, open the rights management</string>\n    <string name=\"tip_permission_storage\">No permission to use the SD card, open the rights management</string>\n    <string name=\"tip_permission_camera_storage\">No permission to use the camera and SD card, open the rights management</string>\n\n</resources>\n"
  },
  {
    "path": "takephoto_library/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "takephoto_library/src/main/res/xml/file_paths.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <paths>\n        <root-path\n            path=\"\"\n            name=\"camera_photos\" />\n    </paths>\n</resources>"
  }
]