├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── app ├── .gitignore ├── build.gradle ├── libs │ └── itextpdf-5.5.8.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zzg │ │ └── myprint_master │ │ └── ExampleInstrumentedTest.java │ ├── assets │ └── images │ │ └── ic_launcher.png │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── zzg │ │ │ └── myprint_master │ │ │ ├── MainActivity.java │ │ │ ├── MyPrintDiscoverySession.java │ │ │ ├── MyPrintService.java │ │ │ ├── PDFCheck.java │ │ │ └── PhotoVerPdf.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_launcher_background.xml │ │ ├── scan.jpg │ │ └── test_print_img.jpg │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── file_paths.xml │ │ └── network_security_config.xml │ └── test │ └── java │ └── com │ └── zzg │ └── myprint_master │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 15 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "29.0.0" 6 | defaultConfig { 7 | applicationId "com.zzg.myprint_master" 8 | minSdkVersion 19 9 | targetSdkVersion 29 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | compileOptions { 22 | sourceCompatibility JavaVersion.VERSION_1_8 23 | targetCompatibility JavaVersion.VERSION_1_8 24 | } 25 | dataBinding{ 26 | enabled true 27 | } 28 | } 29 | 30 | dependencies { 31 | implementation fileTree(include: ['*.jar'], dir: 'libs') 32 | implementation 'androidx.appcompat:appcompat:1.1.0' 33 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 34 | implementation files('libs\\itextpdf-5.5.8.jar') 35 | testImplementation 'junit:junit:4.12' 36 | androidTestImplementation 'androidx.test:runner:1.2.0' 37 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 38 | // implementation 'androidx.print:print:1.0.0' 39 | implementation 'androidx.print:print:latest.release' 40 | //权限 41 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' 42 | implementation 'io.reactivex.rxjava2:rxjava:2.0.1' 43 | implementation 'com.github.tbruyelle:rxpermissions:0.10.2' 44 | //布局注解 45 | implementation 'com.jakewharton:butterknife:10.0.0' 46 | annotationProcessor 'com.jakewharton:butterknife-compiler:10.0.0' 47 | implementation 'androidx.recyclerview:recyclerview:1.1.0-beta04' 48 | 49 | compile 'com.github.1em0nsOft:LemonBubble4Android:1.0.13' 50 | 51 | } 52 | -------------------------------------------------------------------------------- /app/libs/itextpdf-5.5.8.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhangzhenguo-git/MyPrint_master/bfb2c4a906083fd6362c22583c43d90ccdae17be/app/libs/itextpdf-5.5.8.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/zzg/myprint_master/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zzg.myprint_master; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.InstrumentationRegistry; 6 | import androidx.test.runner.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getTargetContext(); 24 | 25 | assertEquals("com.zzg.myprint_master", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/assets/images/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhangzhenguo-git/MyPrint_master/bfb2c4a906083fd6362c22583c43d90ccdae17be/app/src/assets/images/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/zzg/myprint_master/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zzg.myprint_master; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | import androidx.databinding.DataBindingUtil; 5 | import androidx.print.PrintHelper; 6 | 7 | import android.Manifest; 8 | import android.bluetooth.BluetoothManager; 9 | import android.content.Context; 10 | import android.content.Intent; 11 | import android.graphics.Bitmap; 12 | import android.graphics.BitmapFactory; 13 | import android.graphics.pdf.PdfDocument; 14 | import android.os.Build; 15 | import android.os.Bundle; 16 | import android.os.CancellationSignal; 17 | import android.os.Environment; 18 | import android.os.Handler; 19 | import android.os.Message; 20 | import android.os.ParcelFileDescriptor; 21 | import android.print.PageRange; 22 | import android.print.PrintAttributes; 23 | import android.print.PrintDocumentAdapter; 24 | import android.print.PrintDocumentInfo; 25 | import android.print.PrintJob; 26 | import android.print.PrintManager; 27 | import android.print.pdf.PrintedPdfDocument; 28 | import android.util.Log; 29 | import android.view.View; 30 | import android.webkit.WebChromeClient; 31 | import android.webkit.WebSettings; 32 | import android.webkit.WebView; 33 | import android.webkit.WebViewClient; 34 | import android.widget.Button; 35 | import android.widget.Toast; 36 | 37 | //import com.aspose.words.Document; 38 | //import com.aspose.words.SaveFormat; 39 | import com.tbruyelle.rxpermissions2.Permission; 40 | import com.tbruyelle.rxpermissions2.RxPermissions; 41 | import com.zzg.myprint_master.databinding.ActivityMainBinding; 42 | 43 | import net.lemonsoft.lemonbubble.LemonBubble; 44 | import net.lemonsoft.lemonbubble.LemonBubbleInfo; 45 | import net.lemonsoft.lemonbubble.LemonBubbleView; 46 | import net.lemonsoft.lemonbubble.interfaces.LemonBubbleMaskOnTouchContext; 47 | 48 | import java.io.File; 49 | import java.io.FileInputStream; 50 | import java.io.FileNotFoundException; 51 | import java.io.FileOutputStream; 52 | import java.io.IOException; 53 | import java.io.InputStream; 54 | import java.io.OutputStream; 55 | 56 | import io.reactivex.functions.Consumer; 57 | 58 | public class MainActivity extends AppCompatActivity { 59 | private Context context; 60 | private ActivityMainBinding binding; 61 | private int con = 0; 62 | private Handler handler; 63 | 64 | @Override 65 | protected void onCreate(Bundle savedInstanceState) { 66 | super.onCreate(savedInstanceState); 67 | binding = DataBindingUtil.setContentView(this, R.layout.activity_main); 68 | context = MainActivity.this; 69 | openPermissions(); 70 | } 71 | 72 | private void myClick() { 73 | binding.btPhoto.setOnClickListener(new View.OnClickListener() { 74 | @Override 75 | public void onClick(View view) { 76 | doPhotoPrint(); 77 | } 78 | }); 79 | binding.btAssetsPrintPhoto.setOnClickListener(new View.OnClickListener() { 80 | @Override 81 | public void onClick(View view) { 82 | doAssetsPhotoPrint(); 83 | } 84 | }); 85 | binding.btSDPrintPhoto.setOnClickListener(new View.OnClickListener() { 86 | @Override 87 | public void onClick(View view) { 88 | doSDPhotoPrint(); 89 | } 90 | }); 91 | binding.btPrintUrlHTML.setOnClickListener(new View.OnClickListener() { 92 | @Override 93 | public void onClick(View view) { 94 | doHTMLPrint(0); 95 | } 96 | }); 97 | binding.btPrintHTML.setOnClickListener(new View.OnClickListener() { 98 | @Override 99 | public void onClick(View view) { 100 | doHTMLPrint(1); 101 | } 102 | }); 103 | binding.btPrintContainImgHTML.setOnClickListener(new View.OnClickListener() { 104 | @Override 105 | public void onClick(View view) { 106 | doHTMLPrint(2); 107 | } 108 | }); 109 | binding.btPrintCustom.setOnClickListener(new View.OnClickListener() { 110 | @Override 111 | public void onClick(View view) { 112 | String wordFilePath = Environment.getExternalStorageDirectory() + "/测试文件打印1.docx"; 113 | String pdfFilePath = Environment.getExternalStorageDirectory() + "/测试文件打印.pdf"; 114 | doPrint(pdfFilePath); 115 | } 116 | }); 117 | 118 | } 119 | 120 | /** 121 | * 打印png转pdf资源文件 122 | */ 123 | private void doPhotoPrint() { 124 | PhotoVerPdf photoVerPdf = new PhotoVerPdf(); 125 | if (photoVerPdf.ready()) { 126 | doPrint(Environment.getExternalStorageDirectory() + "/测试图片打印.pdf"); 127 | } else { 128 | LemonBubble.showError(MainActivity.this,"转换失败",1000); 129 | } 130 | } 131 | 132 | /** 133 | * 打印assets资源图片 134 | */ 135 | private void doAssetsPhotoPrint() { 136 | PrintHelper printHelper = new PrintHelper(context); 137 | //此属性会自动调整图像的大小,可以更好的把要打印的图像调整到合适的打印区域 138 | printHelper.setScaleMode(PrintHelper.SCALE_MODE_FIT); 139 | //此属性会自动等比例调整图像大小,使图像充满整个打印区域,即让图像充满整个纸张 140 | //缺点是,打印图像的(上下左右边缘会有一部分打印不出来) 141 | // printHelper.setScaleMode(PrintHelper.SCALE_MODE_FILL); 142 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.scan); 143 | printHelper.printBitmap("TestPrint", bitmap); 144 | } 145 | 146 | /** 147 | * 打印sd卡资源图片 148 | */ 149 | private void doSDPhotoPrint() { 150 | PrintHelper printHelper = new PrintHelper(context); 151 | //此属性会自动调整图像的大小,可以更好的把要打印的图像调整到合适的打印区域 152 | printHelper.setScaleMode(PrintHelper.SCALE_MODE_FIT); 153 | //此属性会自动等比例调整图像大小,使图像充满整个打印区域,即让图像充满整个纸张 154 | //缺点是,打印图像的(上下左右边缘会有一部分打印不出来) 155 | // printHelper.setScaleMode(PrintHelper.SCALE_MODE_FILL); 156 | File fileSDImg = new File(Environment.getExternalStorageDirectory() + "/测试图片打印.png"); 157 | 158 | try { 159 | FileInputStream inputStream = new FileInputStream(fileSDImg); 160 | Bitmap bitmap = BitmapFactory.decodeStream(inputStream); 161 | printHelper.printBitmap("TestPrint", bitmap); 162 | } catch (FileNotFoundException e) { 163 | e.printStackTrace(); 164 | } 165 | 166 | } 167 | 168 | 169 | /** 170 | * HTML打印 171 | */ 172 | private void doHTMLPrint(int printType) { 173 | WebView webView = new WebView(context); 174 | webView.setWebViewClient(new WebViewClient() { 175 | public boolean shouldOverrideUrlLoading(WebView webView1, String url) { 176 | return false; 177 | } 178 | 179 | //调用打印任务的入口 180 | //注意,调用打印方法时,一定要先让页面加载完成,否则会出现打印不完整或空白。 181 | @Override 182 | public void onPageFinished(WebView view, String url) { 183 | Log.d("执行", url); 184 | //首先创建一个打印管理器对象并实例化 185 | PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE); 186 | //获取打印适配器实例 187 | PrintDocumentAdapter pDAdapter = webView.createPrintDocumentAdapter(); 188 | //使用名称和适配起来打印名称 189 | String jobName = getString(R.string.app_name) + "Document"; 190 | printManager.print(jobName, pDAdapter, new PrintAttributes.Builder().build()); 191 | // printListener(printManager); 192 | } 193 | }); 194 | // 创建要加载的代码 195 | //baseUrl:网页地址,data:请求的某段代码,mimeType:加载网页的类型,encode:编码格式,historyUrl:可用历史记录 196 | //在线打印 197 | // String htmlUrl="http://43.248.49.204:8080/2020/03/31/MjAwMzMxNjczNzQzNTUw.html"; 198 | String htmlUrl = "https://developer.huawei.com/consumer/cn/"; 199 | //指定html字符串打印 200 | String htmlDocument = "

Test Content测试打印,测试打印

Testing, testing, testing...测试测试测试测试

"; 201 | if (printType == 0) { 202 | webView.loadUrl(htmlUrl); 203 | } else if (printType == 1) { 204 | webView.loadDataWithBaseURL(null, htmlDocument, "text/HTML", "UTF-8", null); 205 | } else if (printType == 2) { 206 | //如果希望打印的页面含有图片,那就把要显示的图片放入工程的assets/目录下, 207 | webView.loadDataWithBaseURL("file:///android_asset/images/ic_launcher.png", htmlDocument, "text/HTML", "UTF-8", null); 208 | } 209 | } 210 | 211 | /** 212 | * 自定义打印 213 | */ 214 | private void doPrint(String filePath) { 215 | if (!PDFCheck.check(filePath)) { 216 | LemonBubble.showError(MainActivity.this, "文件下载失败", 2000); 217 | return; 218 | } 219 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 220 | PrintManager printManager = (PrintManager) MainActivity.this.getSystemService(Context.PRINT_SERVICE); 221 | String jobName = getString(R.string.app_name) + "Document"; 222 | try { 223 | printManager.print(jobName, new MyPrintDocumentAdapter(MainActivity.this, filePath), null); 224 | } catch (RuntimeException e) { 225 | } catch (Exception e) { 226 | } 227 | } else { 228 | Toast.makeText(context, "Android 版本过低不支持自定义打印", Toast.LENGTH_SHORT).show(); 229 | } 230 | } 231 | 232 | /** 233 | * 创建打印适配器 234 | */ 235 | private class MyPrintDocumentAdapter extends PrintDocumentAdapter { 236 | private Context mContext; 237 | private String mFilePath; 238 | private PrintedPdfDocument mPdfDocument; 239 | 240 | public PdfDocument myPdfDocument; 241 | public int totalpages = 1;//设置一共打印一张纸 242 | 243 | public MyPrintDocumentAdapter(Context context, String filePath) { 244 | this.mContext = context; 245 | this.mFilePath = filePath; 246 | } 247 | 248 | //当打印进程开始,该方法就将被调用, 249 | @Override 250 | public void onStart() { 251 | super.onStart(); 252 | } 253 | 254 | //当用户改变了打印输出时,比方说页面尺寸,或者页面的方向时, 255 | // 该函数将被调用。以此会给我们的应用重新计划打印页面的布局, 256 | // 另外该方法必须返回打印文档包含多少页面。 257 | @Override 258 | public void onLayout(PrintAttributes printAttributes, 259 | PrintAttributes printAttributes1, 260 | CancellationSignal cancellationSignal, 261 | LayoutResultCallback layoutResultCallback, 262 | Bundle bundle) { 263 | // //使用请求的页属性创建新的pdfdocument 264 | // mPdfDocument=new PrintedPdfDocument(mContext,printAttributes1); 265 | // 响应取消请求 266 | if (cancellationSignal.isCanceled()) { 267 | layoutResultCallback.onLayoutCancelled(); 268 | return; 269 | } 270 | // 将打印信息返回到打印框架 271 | PrintDocumentInfo info = new PrintDocumentInfo 272 | .Builder("name") 273 | .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) 274 | .build(); 275 | layoutResultCallback.onLayoutFinished(info, true); 276 | } 277 | 278 | //此函数被调用后,会将打印页面渲染成一个待打印的文件,该函数 279 | // 可以在onLayout被调用后调用一次或多次 280 | @Override 281 | public void onWrite(PageRange[] pageRanges, 282 | ParcelFileDescriptor parcelFileDescriptor, 283 | CancellationSignal cancellationSignal, 284 | WriteResultCallback writeResultCallback) { 285 | InputStream input = null; 286 | OutputStream output = null; 287 | try { 288 | input = new FileInputStream(mFilePath); 289 | output = new FileOutputStream(parcelFileDescriptor.getFileDescriptor()); 290 | byte[] buf = new byte[1024]; 291 | int bytesRead; 292 | while ((bytesRead = input.read(buf)) > 0) { 293 | output.write(buf, 0, bytesRead); 294 | } 295 | writeResultCallback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES}); 296 | } catch (FileNotFoundException e) { 297 | } catch (Exception e) { 298 | } finally { 299 | try { 300 | output.close(); 301 | } catch (IOException e) { 302 | } 303 | try { 304 | input.close(); 305 | } catch (IOException e) { 306 | } 307 | } 308 | Toast.makeText(mContext, "已准备好打印,点击右上角蓝色图标开始打印", Toast.LENGTH_SHORT).show(); 309 | } 310 | } 311 | 312 | /** 313 | * 打开权限 314 | */ 315 | private void openPermissions() { 316 | final RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity or Fragment instance 317 | rxPermissions.requestEachCombined( 318 | Manifest.permission.WRITE_EXTERNAL_STORAGE, 319 | Manifest.permission.READ_EXTERNAL_STORAGE 320 | ).subscribe(new Consumer() { 321 | @Override 322 | public void accept(Permission permission) throws Exception { 323 | if (permission.granted) { 324 | Log.d("执行", "权限都通过了"); 325 | myClick(); 326 | } else if (permission.shouldShowRequestPermissionRationale) { 327 | Log.d("执行", "至少有一个权限被拒绝了"); 328 | openPermissions(); 329 | } else { 330 | Log.d("执行", "转到设置"); 331 | } 332 | } 333 | }); 334 | } 335 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zzg/myprint_master/MyPrintDiscoverySession.java: -------------------------------------------------------------------------------- 1 | package com.zzg.myprint_master; 2 | 3 | import android.print.PrintAttributes; 4 | import android.print.PrinterCapabilitiesInfo; 5 | import android.print.PrinterId; 6 | import android.print.PrinterInfo; 7 | import android.printservice.PrinterDiscoverySession; 8 | import android.util.Log; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * @author Zhangzhenguo 15 | * @create 2020/10/9 16 | * @Email 18311371235@163.com 17 | * @Describe 18 | */ 19 | public class MyPrintDiscoverySession extends PrinterDiscoverySession { 20 | private static final String TAG = "MyPrintDiscoverySession"; 21 | private final MyPrintService myPrintService; 22 | 23 | public MyPrintDiscoverySession(MyPrintService myPrintService) { 24 | Log.d(TAG, "MyPrintDiscoverySession()"); 25 | this.myPrintService = myPrintService; 26 | } 27 | 28 | @Override 29 | public void onStartPrinterDiscovery(List priorityList) { 30 | Log.d(TAG, "onStartPrinterDiscovery()"); 31 | List printers = this.getPrinters(); 32 | String name = "printer1"; 33 | PrinterInfo myprinter = new PrinterInfo 34 | .Builder(myPrintService.generatePrinterId(name), name, PrinterInfo.STATUS_IDLE) 35 | .build(); 36 | printers.add(myprinter); 37 | addPrinters(printers); 38 | } 39 | 40 | @Override 41 | public void onStopPrinterDiscovery() { 42 | Log.d(TAG, "onStopPrinterDiscovery()"); 43 | } 44 | 45 | /** 46 | * 确定这些打印机存在 47 | * 48 | * @param printerIds 49 | */ 50 | @Override 51 | public void onValidatePrinters(List printerIds) { 52 | Log.d(TAG, "onValidatePrinters()"); 53 | } 54 | 55 | /** 56 | * 选择打印机时调用该方法更新打印机的状态,能力 57 | * 58 | * @param printerId 59 | */ 60 | @Override 61 | public void onStartPrinterStateTracking(PrinterId printerId) { 62 | Log.d(TAG, "onStartPrinterStateTracking()"); 63 | PrinterInfo printer = findPrinterInfo(printerId); 64 | if (printer != null) { 65 | PrinterCapabilitiesInfo capabilities = 66 | new PrinterCapabilitiesInfo.Builder(printerId) 67 | .setMinMargins(new PrintAttributes.Margins(200, 200, 200, 200)) 68 | .addMediaSize(PrintAttributes.MediaSize.ISO_A4, true) 69 | //.addMediaSize(PrintAttributes.MediaSize.ISO_A5, false) 70 | .addResolution(new PrintAttributes.Resolution("R1", "200x200", 200, 200), false) 71 | .addResolution(new PrintAttributes.Resolution("R2", "300x300", 300, 300), true) 72 | .setColorModes(PrintAttributes.COLOR_MODE_COLOR 73 | | PrintAttributes.COLOR_MODE_MONOCHROME, 74 | PrintAttributes.COLOR_MODE_MONOCHROME) 75 | .build(); 76 | 77 | printer = new PrinterInfo.Builder(printer) 78 | .setCapabilities(capabilities) 79 | .setStatus(PrinterInfo.STATUS_IDLE) 80 | // .setDescription("fake print 1!") 81 | .build(); 82 | List printers = new ArrayList(); 83 | 84 | printers.add(printer); 85 | addPrinters(printers); 86 | } 87 | } 88 | 89 | @Override 90 | public void onStopPrinterStateTracking(PrinterId printerId) { 91 | Log.d(TAG, "onStopPrinterStateTracking()"); 92 | } 93 | 94 | @Override 95 | public void onDestroy() { 96 | Log.d(TAG, "onDestroy()"); 97 | } 98 | 99 | private PrinterInfo findPrinterInfo(PrinterId printerId) { 100 | List printers = getPrinters(); 101 | final int printerCount = getPrinters().size(); 102 | for (int i = 0; i < printerCount; i++) { 103 | PrinterInfo printer = printers.get(i); 104 | if (printer.getId().equals(printerId)) { 105 | return printer; 106 | } 107 | } 108 | return null; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/com/zzg/myprint_master/MyPrintService.java: -------------------------------------------------------------------------------- 1 | package com.zzg.myprint_master; 2 | 3 | import android.os.ParcelFileDescriptor; 4 | import android.print.PrintJobInfo; 5 | import android.printservice.PrintDocument; 6 | import android.printservice.PrintJob; 7 | import android.printservice.PrintService; 8 | import android.printservice.PrinterDiscoverySession; 9 | import android.util.Log; 10 | 11 | import java.io.File; 12 | import java.io.FileInputStream; 13 | import java.io.FileOutputStream; 14 | import java.io.IOException; 15 | 16 | /** 17 | * @author Zhangzhenguo 18 | * @create 2020/10/9 19 | * @Email 18311371235@163.com 20 | * @Describe 21 | */ 22 | class MyPrintService extends PrintService { 23 | private static final String TAG = "MyPrintService"; 24 | 25 | @Override 26 | protected PrinterDiscoverySession onCreatePrinterDiscoverySession() { 27 | Log.d(TAG, "onCreatePrinterDiscoverySession()"); 28 | return new MyPrintDiscoverySession(this); 29 | } 30 | 31 | @Override 32 | protected void onRequestCancelPrintJob(PrintJob printJob) { 33 | Log.d(TAG, "onRequestCancelPrintJob()"); 34 | printJob.cancel(); 35 | } 36 | 37 | @Override 38 | protected void onPrintJobQueued(PrintJob printJob) { 39 | Log.d(TAG, "onPrintJobQueued()"); 40 | PrintJobInfo printjobinfo = printJob.getInfo(); 41 | PrintDocument printdocument = printJob.getDocument(); 42 | if (printJob.isQueued()) { 43 | return; 44 | } 45 | printJob.start(); 46 | 47 | String filename = "docu.pdf"; 48 | File outfile = new File(this.getFilesDir(), filename); 49 | outfile.delete(); 50 | FileInputStream file = new ParcelFileDescriptor.AutoCloseInputStream(printdocument.getData()); 51 | //创建一个长度为1024的内存空间 52 | byte[] bbuf = new byte[1024]; 53 | //用于保存实际读取的字节数 54 | int hasRead = 0; 55 | //使用循环来重复读取数据 56 | try { 57 | FileOutputStream outStream = new FileOutputStream(outfile); 58 | while ((hasRead = file.read(bbuf)) > 0) { 59 | //将字节数组转换为字符串输出 60 | //System.out.print(new String(bbuf, 0, hasRead)); 61 | outStream.write(bbuf); 62 | } 63 | outStream.close(); 64 | } catch (IOException e) { 65 | e.printStackTrace(); 66 | }finally { 67 | //关闭文件输出流,放在finally块里更安全 68 | try { 69 | file.close(); 70 | } catch (IOException e) { 71 | e.printStackTrace(); 72 | } 73 | } 74 | 75 | printJob.complete(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/zzg/myprint_master/PDFCheck.java: -------------------------------------------------------------------------------- 1 | package com.zzg.myprint_master; 2 | import android.util.Log; 3 | 4 | import com.itextpdf.text.Document; 5 | import com.itextpdf.text.pdf.PdfReader; 6 | 7 | /** 8 | * @author Zhangzhenguo 9 | * @create 2020/7/2 10 | * @Email 18311371235@163.com 11 | * @Describe 12 | */ 13 | public class PDFCheck { 14 | /** 15 | * 利用itext打开pdf文档 16 | * 17 | * 判断pdf 是否损坏 18 | * 19 | */ 20 | public static boolean check(String file) { 21 | boolean flag1 = false; 22 | int n = 0; 23 | try { 24 | Document document = new Document(new PdfReader(file).getPageSize(1)); 25 | document.open(); 26 | PdfReader reader = new PdfReader(file); 27 | n = reader.getNumberOfPages(); 28 | if (n != 0) 29 | flag1 = true; 30 | document.close(); 31 | } catch (Exception e) { 32 | Log.d("PDFCheck",e.getMessage()); 33 | } 34 | return flag1; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/zzg/myprint_master/PhotoVerPdf.java: -------------------------------------------------------------------------------- 1 | package com.zzg.myprint_master; 2 | 3 | import com.itextpdf.text.Document; 4 | 5 | import java.io.File; 6 | import java.io.FileNotFoundException; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | 10 | import android.annotation.SuppressLint; 11 | import android.os.Environment; 12 | 13 | import com.itextpdf.text.Document; 14 | import com.itextpdf.text.DocumentException; 15 | import com.itextpdf.text.Image; 16 | import com.itextpdf.text.pdf.PdfWriter; 17 | 18 | /** 19 | * @author Zhangzhenguo 20 | * @create 2020/10/9 21 | * @Email 18311371235@163.com 22 | * @Describe 23 | */ 24 | 25 | public class PhotoVerPdf { 26 | 27 | /** 28 | * 图片转换pdf 29 | * @return 30 | */ 31 | public boolean ready() { 32 | //创建一个文档对象 33 | Document doc = new Document(); 34 | try { 35 | File fileName=new File(Environment.getExternalStorageDirectory()+"/测试图片打印.pdf"); 36 | //定义输出文件的位置 37 | PdfWriter.getInstance(doc, new FileOutputStream(fileName.getAbsoluteFile())); 38 | //开启文档 39 | doc.open(); 40 | //设定字体 为的是支持中文 41 | //BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); 42 | // Font FontChinese = new Font(bfChinese, 12, Font.NORMAL); 43 | //向文档中加入图片 44 | // for (int i = 1; i < 32; i++) { 45 | //取得图片~~~图片格式: 46 | // Image jpg1 = Image.getInstance("/sdcard/myImage/" + i + ".png"); 47 | Image jpg1 = Image.getInstance(Environment.getExternalStorageDirectory()+ "/测试图片打印.png"); 48 | //原来的图片的路径 49 | //获得图片的高度 50 | float heigth = jpg1.getHeight(); 51 | float width = jpg1.getWidth(); 52 | // System.out.println("heigth" + i + "----" + heigth); 53 | // System.out.println("width" + i + "-----" + width); 54 | //合理压缩,h>w,按w压缩,否则按w压缩 55 | //int percent=getPercent(heigth, width); 56 | //统一按照宽度压缩 57 | int percent = getPercent2(heigth, width); 58 | //设置图片居中显示 59 | jpg1.setAlignment(Image.MIDDLE); 60 | //直接设置图片的大小~~~~~~~第三种解决方案,按固定比例压缩 61 | //jpg1.scaleAbsolute(210.0f, 297.0f); 62 | //按百分比显示图片的比例 63 | jpg1.scalePercent(percent);//表示是原来图像的比例; 64 | //可设置图像高和宽的比例 65 | //jpg1.scalePercent(50, 100); 66 | doc.add(jpg1); 67 | // } 68 | //关闭文档并释放资源 69 | doc.close(); 70 | if (fileName.exists()){ 71 | return true; 72 | } 73 | } catch (FileNotFoundException e) { 74 | e.printStackTrace(); 75 | } catch (DocumentException e) { 76 | e.printStackTrace(); 77 | } catch (IOException e) { 78 | e.printStackTrace(); 79 | } 80 | return false; 81 | } 82 | // /** 83 | // * 第一种解决方案 84 | // * 在不改变图片形状的同时,判断,如果h>w,则按h压缩,否则在w>h或w=h的情况下,按宽度压缩 85 | // * @param h 86 | // * @param w 87 | // * @return 88 | // */ 89 | // 90 | // public int getPercent(float h,float w) 91 | // { 92 | // int p=0; 93 | // float p2=0.0f; 94 | // if(h>w) 95 | // { 96 | // p2=297/h*100; 97 | // } 98 | // else 99 | // { 100 | // p2=210/w*100; 101 | // } 102 | // p=Math.round(p2); 103 | // return p; 104 | // } 105 | 106 | /** 107 | * 第二种解决方案,统一按照宽度压缩 108 | * 这样来的效果是,所有图片的宽度是相等的,自我认为给客户的效果是最好的 109 | * 110 | * @param h 111 | * @param w 112 | */ 113 | private int getPercent2(float h, float w) { 114 | int p = 0; 115 | float p2 = 0.0f; 116 | p2 = 530 / w * 100; 117 | p = Math.round(p2); 118 | return p; 119 | } 120 | /** 121 | * 第三种解决方案,就是直接压缩,不安像素比例,全部压缩到固定值,如210*297 122 | * 123 | * @param args 124 | */ 125 | public void main3(String[] args) { 126 | PhotoVerPdf pt=new PhotoVerPdf(); 127 | pt.ready(); 128 | } 129 | } 130 | 131 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/scan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhangzhenguo-git/MyPrint_master/bfb2c4a906083fd6362c22583c43d90ccdae17be/app/src/main/res/drawable/scan.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/test_print_img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhangzhenguo-git/MyPrint_master/bfb2c4a906083fd6362c22583c43d90ccdae17be/app/src/main/res/drawable/test_print_img.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 13 | 14 | 18 | 24 |