瀏覽代碼

PDFTool(Android) - 新增打印服务适配,修复部分弹窗存在黑色背景问题,新增水印配置

liuxiaolong 1 月之前
父節點
當前提交
7715b93d61
共有 22 個文件被更改,包括 537 次插入32 次删除
  1. 6 4
      ComPDFKit_Tools/build.gradle
  2. 4 1
      ComPDFKit_Tools/src/main/assets/tools_default_configuration.json
  3. 12 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/contextmenu/provider/ContextMenuView.java
  4. 4 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/CPDFConfigurationUtils.java
  5. 23 13
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/CPDFDocumentFragment.java
  6. 14 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/config/CPDFWatermarkConfig.java
  7. 2 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/config/GlobalConfig.java
  8. 9 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/dialog/CAlertDialog.java
  9. 9 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/dialog/CGotoPageDialog.java
  10. 3 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/dialog/CLoadingDialog.java
  11. 314 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/print/CPDFPrintAdpater.java
  12. 107 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/print/CPDFPrintUtils.java
  13. 1 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfview/CPDFViewCtrl.java
  14. 16 2
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/security/watermark/CWatermarkEditDialog.java
  15. 2 1
      ComPDFKit_Tools/src/main/res/values-zh-rCN/tools_strings.xml
  16. 2 1
      ComPDFKit_Tools/src/main/res/values/tools_strings.xml
  17. 2 1
      PDFViewer/build.gradle
  18. 1 1
      PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/FunSamplesActivity.java
  19. 1 1
      PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/samples/WatermarkSamplesImpl.java
  20. 1 1
      compdfkit-tools-mavencentral.gradle
  21. 3 3
      config.gradle
  22. 1 0
      settings.gradle

+ 6 - 4
ComPDFKit_Tools/build.gradle

@@ -52,11 +52,13 @@ dependencies {
 
     api fileTree(include: ['*.jar'], dir: 'libs')
     // use this
-    api project(path:':ComPDFKit_Repo:compdfkit')
-    api project(path:':ComPDFKit_Repo:compdfkit-ui')
+//    api project(path:':ComPDFKit_Repo:compdfkit')
+//    api project(path:':ComPDFKit_Repo:compdfkit-ui')
+//    api project(path: ':ComPDFKit')
+//    api project(path: ':ComPDFKit-UI')
     // or use
-//    api ('com.compdf:compdfkit:2.2.1')
-//    api ('com.compdf:compdfkit-ui:2.2.1')
+    api ('com.compdf:compdfkit:2.2.2-SNAPSHOT')
+    api ('com.compdf:compdfkit-ui:2.2.2-SNAPSHOT')
     api 'com.github.bumptech.glide:glide:4.15.1'
     annotationProcessor 'com.github.bumptech.glide:compiler:4.15.1'
     api 'androidx.documentfile:documentfile:1.0.1'

+ 4 - 1
ComPDFKit_Tools/src/main/assets/tools_default_configuration.json

@@ -264,6 +264,9 @@
   },
   "global" : {
     "themeMode" : "system",
-    "fileSaveExtraFontSubset" : true
+    "fileSaveExtraFontSubset" : true,
+    "watermark": {
+      "saveAsNewFile" : false
+    }
   }
 }

+ 12 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/contextmenu/provider/ContextMenuView.java

@@ -60,4 +60,16 @@ public class ContextMenuView extends LinearLayout {
         }
         return this;
     }
+
+    public ContextMenuView addItem(String title, OnClickListener clickListener){
+        View view = LayoutInflater.from(getContext()).inflate(R.layout.tools_context_menu_item_layout, null);
+        AppCompatTextView textView = (AppCompatTextView) view;
+        textView.setId(View.generateViewId());
+        textView.setText(title);
+        textView.setOnClickListener(clickListener);
+        if (llContent != null) {
+            llContent.addView(view);
+        }
+        return this;
+    }
 }

+ 4 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/CPDFConfigurationUtils.java

@@ -728,6 +728,10 @@ public class CPDFConfigurationUtils {
         globalConfig.themeMode = GlobalConfig.CThemeMode.fromString(jsonObject.optString("themeMode", "light"));
         globalConfig.fileSaveExtraFontSubset = jsonObject.optBoolean("fileSaveExtraFontSubset", true);
 
+        JSONObject watermark = jsonObject.optJSONObject("watermark");
+        if (watermark != null){
+            globalConfig.watermark.saveAsNewFile = watermark.optBoolean("saveAsNewFile",true);
+        }
         return globalConfig;
     }
 }

+ 23 - 13
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/CPDFDocumentFragment.java

@@ -59,6 +59,7 @@ import com.compdfkit.tools.common.utils.activitycontracts.CSelectPDFDocumentResu
 import com.compdfkit.tools.common.utils.annotation.CPDFAnnotationManager;
 import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
 import com.compdfkit.tools.common.utils.dialog.CLoadingDialog;
+import com.compdfkit.tools.common.utils.print.CPDFPrintUtils;
 import com.compdfkit.tools.common.utils.threadpools.CThreadPoolUtils;
 import com.compdfkit.tools.common.utils.viewutils.CViewUtils;
 import com.compdfkit.tools.common.utils.window.CPopupMenuWindow;
@@ -489,7 +490,7 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
     }
 
     private void restoreEdit() {
-        restoreEdit(pdfView,pdfToolBar.getMode() == CPreviewMode.Edit);
+        restoreEdit(pdfView, pdfToolBar.getMode() == CPreviewMode.Edit);
     }
 
     protected void initEditBar() {
@@ -837,7 +838,7 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
         }
     }
 
-    public void showBOTA(){
+    public void showBOTA() {
         pdfView.getCPdfReaderView().removeAllAnnotFocus();
         if (pdfView.getCPdfReaderView().getEditManager().isEditMode()) {
             curEditMode = pdfView.getCPdfReaderView().getLoadType();
@@ -864,11 +865,11 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
         dialogFragment.show(getChildFragmentManager(), "annotationList");
     }
 
-    public void showPageEdit(boolean enterEditMode){
+    public void showPageEdit(boolean enterEditMode) {
         showPageEdit(pdfView, enterEditMode, this::restoreEdit);
     }
 
-    public void showSecurityDialog(){
+    public void showSecurityDialog() {
         CPDFDocument document = pdfView.getCPdfReaderView().getPDFDocument();
         if (document == null) {
             return;
@@ -888,25 +889,34 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
         showSettingEncryptionDialog();
     }
 
-    public void showAddWatermarkDialog(){
+    public void showAddWatermarkDialog() {
+        showAddWatermarkDialog(cpdfConfiguration.globalConfig.watermark.saveAsNewFile);
+    }
+
+    public void showAddWatermarkDialog(boolean saveAsNewFile) {
         CWatermarkEditDialog watermarkEditDialog = CWatermarkEditDialog.newInstance();
         watermarkEditDialog.setDocument(pdfView.getCPdfReaderView().getPDFDocument());
         watermarkEditDialog.setSaveFileExtraFontSubset(pdfView.isSaveFileExtraFontSubset());
         watermarkEditDialog.setPageIndex(pdfView.currentPageIndex);
-        watermarkEditDialog.setCompleteListener((pdfFile) -> {
-            pdfView.getCPdfReaderView().reloadPages();
+        watermarkEditDialog.setSaveAsNewFile(saveAsNewFile);
+        watermarkEditDialog.setCompleteListener((saveAsNewFile1, pdfFile) -> {
             watermarkEditDialog.dismiss();
+            CToastUtil.showLongToast(getContext(), R.string.tools_watermark_add_success);
+            if (!saveAsNewFile1) {
+                pdfView.getCPdfReaderView().reloadPages();
+                return;
+            }
+            pdfView.getCPdfReaderView().reloadPages();
             if (TextUtils.isEmpty(pdfFile)) {
                 CToastUtil.showLongToast(getContext(), R.string.tools_watermark_add_failed);
                 return;
             }
             pdfView.openPDF(pdfFile);
-            CToastUtil.showLongToast(getContext(), R.string.tools_watermark_add_success);
         });
         watermarkEditDialog.show(getChildFragmentManager(), "watermarkEditDialog");
     }
 
-    public void showFlattenedDialog(){
+    public void showFlattenedDialog() {
         if (Build.VERSION.SDK_INT < CPermissionUtil.VERSION_R) {
             multiplePermissionResultLauncher.launch(CPermissionUtil.STORAGE_PERMISSIONS, result -> {
                 if (CPermissionUtil.hasStoragePermissions(getContext())) {
@@ -922,7 +932,7 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
         }
     }
 
-    public void enterSnipMode(){
+    public void enterSnipMode() {
         CPDFReaderView readerView = pdfView.getCPdfReaderView();
         readerView.removeAllAnnotFocus();
         if (readerView.getContextMenuShowListener() != null) {
@@ -939,7 +949,7 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
         readerView.setTouchMode(CPDFReaderView.TouchMode.SCREENSHOT);
     }
 
-    public void exitSnipMode(){
+    public void exitSnipMode() {
         CPDFReaderView readerView = pdfView.getCPdfReaderView();
         readerView.removeAllAnnotFocus();
         if (readerView.getContextMenuShowListener() != null) {
@@ -950,14 +960,14 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
             view.clearScreenShotRect();
         }
         CPDFReaderView.ViewMode viewMode = readerView.getViewMode();
-        if(viewMode == CPDFReaderView.ViewMode.PDFEDIT){
+        if (viewMode == CPDFReaderView.ViewMode.PDFEDIT) {
             readerView.setTouchMode(CPDFReaderView.TouchMode.EDIT);
             CPDFEditManager editManager = readerView.getEditManager();
             if (editManager != null && !editManager.isEditMode()) {
                 editManager.enable();
                 editManager.beginEdit(CPDFEditPage.LoadTextImage | CPDFEditPage.LoadPath);
             }
-        }else {
+        } else {
             readerView.setTouchMode(CPDFReaderView.TouchMode.BROWSE);
         }
         screenManager.fillScreenChange();

+ 14 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/config/CPDFWatermarkConfig.java

@@ -0,0 +1,14 @@
+package com.compdfkit.tools.common.pdf.config;
+
+import java.io.Serializable;
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2025/2/7
+ * description:
+ */
+public class CPDFWatermarkConfig implements Serializable {
+    public boolean saveAsNewFile = true;
+
+}

+ 2 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/config/GlobalConfig.java

@@ -33,4 +33,6 @@ public class GlobalConfig  implements Serializable {
      */
     public boolean fileSaveExtraFontSubset = true;
 
+    public CPDFWatermarkConfig watermark = new CPDFWatermarkConfig();
+
 }

+ 9 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/dialog/CAlertDialog.java

@@ -9,6 +9,8 @@
 
 package com.compdfkit.tools.common.utils.dialog;
 
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.view.View;
@@ -66,7 +68,13 @@ public class CAlertDialog extends CBasicThemeDialogFragment {
     protected int layoutId() {
         return R.layout.tools_alert_dialog;
     }
-
+    @Override
+    public void onStart() {
+        super.onStart();
+        if (getDialog() != null) {
+            getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+        }
+    }
     @Override
     protected void onCreateView(View rootView) {
         tvTitle = rootView.findViewById(R.id.tv_title);

+ 9 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/dialog/CGotoPageDialog.java

@@ -11,6 +11,8 @@ package com.compdfkit.tools.common.utils.dialog;
 
 import android.app.Dialog;
 import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.text.Editable;
 import android.text.InputType;
@@ -66,7 +68,13 @@ public class CGotoPageDialog extends CBasicThemeDialogFragment {
     protected int layoutId() {
         return R.layout.tools_bota_bookmark_input_dialog;
     }
-
+    @Override
+    public void onStart() {
+        super.onStart();
+        if (getDialog() != null) {
+            getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+        }
+    }
     @Override
     protected void onCreateView(View rootView) {
         if (getDialog() != null && getDialog().getWindow() != null) {

+ 3 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/dialog/CLoadingDialog.java

@@ -9,6 +9,8 @@
 
 package com.compdfkit.tools.common.utils.dialog;
 
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.view.View;
 
@@ -39,6 +41,7 @@ public class CLoadingDialog extends CBasicThemeDialogFragment {
         setCancelable(false);
         if (getDialog() != null) {
             getDialog().setCanceledOnTouchOutside(false);
+            getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
         }
     }
 

+ 314 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/print/CPDFPrintAdpater.java

@@ -0,0 +1,314 @@
+package com.compdfkit.tools.common.utils.print;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.pdf.PdfDocument;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentInfo;
+import android.print.pdf.PrintedPdfDocument;
+import android.util.SparseIntArray;
+
+import androidx.print.PrintHelper;
+
+
+import com.compdfkit.tools.BuildConfig;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * @classname:ProPrintAdapter
+ * @author:luozhipeng
+ * @date:2019-10-11 21:59
+ * @description: 打印机适配类
+ */
+public class CPDFPrintAdpater extends PrintDocumentAdapter {
+    private static final int MILS_PER_INCH = 1000;
+    /****** 是否显示打印的文档页码测试信息 ******/
+    private static final boolean isShowTestPage = BuildConfig.DEBUG;
+    /****** 打印清晰度: 1.5:标清;2.3:高清;3:超清 ******/
+    public static final float SD = 1.5f;
+    public static final float HQ = 2.3f;
+    public static final float FHQ = 3.0f;
+    private float resolutionScale = SD;
+    /****** 是否绘制注释 ******/
+    private boolean isDrawAnnot = true;
+    private Context context;
+    private String jobName;
+    private int totalpages;
+    private PrintAttributes currentAttributes;
+    private IPrintCallback iPrintCallback;
+    private final Stack<AsyncTask> mStack = new Stack<>();
+
+    public CPDFPrintAdpater(Context context, int totalpages, String jobName, IPrintCallback iPrintCallback) {
+        this.context = context.getApplicationContext();
+        this.totalpages = totalpages;
+        this.jobName = jobName;
+        this.iPrintCallback = iPrintCallback;
+    }
+
+    public CPDFPrintAdpater(Context context, int totalpages, String jobName, float resolutionScale, boolean isDrawAnnot, IPrintCallback iPrintCallback) {
+        this.resolutionScale = resolutionScale;
+        this.isDrawAnnot = isDrawAnnot;
+        this.context = context.getApplicationContext();
+        this.totalpages = totalpages;
+        this.jobName = jobName;
+        this.iPrintCallback = iPrintCallback;
+    }
+
+    public void setResolutionScale(float resolutionScale) {
+        this.resolutionScale = resolutionScale;
+    }
+
+    public void setDrawAnnot(boolean drawAnnot) {
+        isDrawAnnot = drawAnnot;
+    }
+
+    @Override
+    public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) {
+        currentAttributes = newAttributes;
+
+        // Respond to cancellation request
+        if (cancellationSignal.isCanceled()) {
+            callback.onLayoutCancelled();
+            return;
+        }
+
+        if (totalpages > 0) {
+            //构建文档配置信息
+            PrintDocumentInfo info = new PrintDocumentInfo
+                    .Builder(jobName)
+                    .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                    .setPageCount(totalpages)
+                    .build();
+            // Content layout reflow is complete
+            callback.onLayoutFinished(info, true);
+        } else {
+            // Otherwise report an error to the print framework
+            callback.onLayoutFailed("Page count calculation failed.");
+        }
+    }
+
+    @SuppressLint("StaticFieldLeak")
+    @Override
+    public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {
+        final AsyncTask<Void, Void, Throwable> asyncTask = new AsyncTask<Void, Void, Throwable>() {
+            final SparseIntArray writtenPages = new SparseIntArray();
+
+            @Override
+            protected Throwable doInBackground(Void... voids) {
+                PrintedPdfDocument mPdfDocument = null;
+                try {
+                    // check for cancellation
+                    if (isCancelled() || cancellationSignal.isCanceled()) {
+                        return null;
+                    }
+
+                    // Create a new PdfDocument with the requested page attributes
+                    mPdfDocument = new PrintedPdfDocument(context, currentAttributes);
+
+                    for (int i = 0; i < totalpages; i++) {
+                        // Check to see if this page is in the output range.
+                        if (containsPage(pageRanges, i)) {
+                            // check for cancellation
+                            if (isCancelled() || cancellationSignal.isCanceled()) {
+                                return null;
+                            }
+
+                            final PdfDocument.Page page = mPdfDocument.startPage(i);
+
+                            // Draw page content for printing
+                            drawPage(page, i);
+
+                            // Rendering is complete, so page can be finalized.
+                            mPdfDocument.finishPage(page);
+
+                            writtenPages.append(writtenPages.size(), i);
+                        }
+                    }
+
+                    // check for cancellation
+                    if (isCancelled() || cancellationSignal.isCanceled()) {
+                        return null;
+                    }
+
+                    // Write the document.
+                    mPdfDocument.writeTo(new FileOutputStream(destination.getFileDescriptor()));
+                    return null;
+                } catch (Exception e) {
+                    return e;
+                } finally {
+                    if (null != mPdfDocument) {
+                        mPdfDocument.close();
+                    }
+                }
+            }
+
+            @Override
+            protected void onPostExecute(Throwable throwable) {
+                super.onPostExecute(throwable);
+                try {
+                    if (cancellationSignal.isCanceled()) {
+                        // Cancelled.
+                        callback.onWriteCancelled();
+                    } else if (null == throwable) {
+                        PageRange[] writtenPageRange = computeWrittenPageRanges(writtenPages);
+                        // Signal the print framework the document is complete
+                        callback.onWriteFinished(writtenPageRange);
+                    } else {
+                        // Failed.
+                        callback.onWriteFailed(throwable.getMessage());
+                    }
+                } finally {
+                    writtenPages.clear();
+                    try {
+                        destination.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        };
+        mStack.push(asyncTask);
+        asyncTask.execute();
+    }
+
+    @Override
+    public void onFinish() {
+        try {
+            while (!mStack.empty()) {
+                try {
+                    AsyncTask asyncTask = mStack.pop();
+                    if ((null != asyncTask) && !asyncTask.isCancelled()) {
+                        asyncTask.cancel(true);
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        } finally {
+            if (null != iPrintCallback) {
+                iPrintCallback.onFinish();
+            }
+            super.onFinish();
+        }
+    }
+
+    /**
+     * @param :[pageRanges, page]
+     *                      pageRanges书面页面的PageRange数组。
+     *                      numPage要检查PageRange数组的页码。
+     * @return : boolean 如果页面包含在PageRange数组中,则为true。否则为假。
+     * @methodName :containsPage created by luozhipeng on 2019-10-11 20:59.
+     * @description :检查给定的页码是否包含在PageRange数组中。
+     */
+    private boolean containsPage(PageRange[] pageRanges, int numPage) {
+        for (PageRange pr : pageRanges) {
+            if ((numPage >= pr.getStart()) && (numPage <= pr.getEnd())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @methodName:drawPage created by luozhipeng on 2019-10-11 21:38.
+     * @description: 页面绘制(渲染)
+     */
+    private void drawPage(PdfDocument.Page page, int pagenumber) {
+        Canvas canvas = page.getCanvas();
+        Bitmap bitmap = null;
+        try {
+            canvas.drawColor(Color.WHITE);
+            int pageWidth = (int) (72 * (float) currentAttributes.getMediaSize().getWidthMils() / MILS_PER_INCH);
+            int pageHeight = (int) (72 * (float) currentAttributes.getMediaSize().getHeightMils() / MILS_PER_INCH);
+
+            if (null != iPrintCallback) {
+                bitmap = iPrintCallback.onWriteBitmap(pagenumber, (int) (pageWidth * resolutionScale), isDrawAnnot);
+            }
+
+            if (null != bitmap) {
+                // 计算页码的缩放比例
+                float scale = Math.min((float) pageWidth / bitmap.getWidth(), (float) pageHeight / bitmap.getHeight());
+                if (scale > 1) {
+                    scale = 1;
+                }
+                // 取得想要缩放的matrix参数
+                Matrix matrix = new Matrix();
+                matrix.postScale(scale, scale);
+
+                // 页码居中
+//                int translateX = Math.abs((int) (bitmap.getWidth() * scale) - pageWidth);
+//                int translateY = Math.abs((int) (bitmap.getHeight() * scale) - pageHeight);
+//                matrix.postTranslate(translateX / 2f, translateY / 2f);
+
+                canvas.drawBitmap(bitmap, matrix, null);
+            }
+
+//            if (isShowTestPage) {
+//                // units are in points (1/72 of an inch)
+//                int titleBaseLine = 72;
+//                int leftMargin = 54;
+//                Paint paint = new Paint();
+//                paint.setColor(Color.RED);
+//                paint.setTextSize(32);
+//                canvas.drawText(String.format(Locale.US, "PageNum: %s;PageWidth: %s", (pagenumber + 1), (int) (pageWidth * resolutionScale)), leftMargin, titleBaseLine, paint);
+//            }
+        } catch (Exception e) {
+            canvas.drawColor(Color.WHITE);
+        } finally {
+            if ((null != bitmap) && !bitmap.isRecycled()) {
+                bitmap.recycle();
+            }
+        }
+    }
+
+    /**
+     * @param :[writtenPages] 一个SparseIntArray,其中包含必须写入的页面。
+     * @return : android.print.PageRange[] 一个包含结果范围的PageRange数组。
+     * @methodName :computeWrittenPageRanges created by luozhipeng on 2019-10-11 21:04.
+     * @description :将所选页面转换为以PageRange数组形式写入的函数。
+     */
+    private PageRange[] computeWrittenPageRanges(SparseIntArray writtenPages) {
+        final List<PageRange> pageRanges = new ArrayList<>();
+
+        int start = -1;
+        int end;
+        final int writtenPageCount = writtenPages.size();
+        for (int i = 0; i < writtenPageCount; i++) {
+            if (start < 0) {
+                start = writtenPages.valueAt(i);
+            }
+            int oldEnd = end = start;
+            while (i < writtenPageCount && (end - oldEnd) <= 1) {
+                oldEnd = end;
+                end = writtenPages.valueAt(i);
+                i++;
+            }
+            @SuppressLint("Range") PageRange pageRange = new PageRange(start, end);
+            pageRanges.add(pageRange);
+            start = -1;
+        }
+
+        PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
+        pageRanges.toArray(pageRangesArray);
+        return pageRangesArray;
+    }
+
+    public interface IPrintCallback extends PrintHelper.OnPrintFinishCallback {
+        Bitmap onWriteBitmap(int pageNum, int pageWidth, boolean isDrawAnnot);
+    }
+}

+ 107 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/print/CPDFPrintUtils.java

@@ -0,0 +1,107 @@
+package com.compdfkit.tools.common.utils.print;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.print.PrintAttributes;
+import android.print.PrintManager;
+
+import androidx.annotation.NonNull;
+import androidx.print.PrintHelper;
+
+
+import com.compdfkit.core.document.CPDFDocument;
+import com.compdfkit.core.page.CPDFPage;
+import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.utils.CToastUtil;
+
+import org.jetbrains.annotations.NotNull;
+
+public class CPDFPrintUtils {
+
+    /**
+     * @param :[context, file, pageCounts, isEncrypted]
+     * @return : void
+     * @methodName :printCurrentDocument created by liujiyuan on 2018/9/13 下午5:31.
+     */
+    public static void printCurrentDocument(@NotNull final Activity activity,CPDFDocument document) {
+        try {
+            if (PrintHelper.systemSupportsPrint()) {
+                PrintManager printManager = (PrintManager) activity.getSystemService(Context.PRINT_SERVICE);
+                PrintAttributes attributes = new PrintAttributes.Builder()
+                        .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
+                        .setResolution(new PrintAttributes.Resolution("id", Context.PRINT_SERVICE, 300, 300))
+                        .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                        .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
+                        .build();
+                CPDFPrintAdpater adapter = getPDFPrintAdapter(activity, document);
+                printManager.print(document.getFileName(), adapter, attributes);
+            } else {
+                CToastUtil.showToast(activity.getApplicationContext(), R.string.tools_print_systemversion_not_support);
+            }
+        } catch (Exception e) {
+            CToastUtil.showToast(activity.getApplicationContext(), R.string.tools_print_not_working);
+        }
+    }
+
+    @NonNull
+    private static CPDFPrintAdpater getPDFPrintAdapter(@NonNull Activity activity, CPDFDocument document) {
+        CPDFPrintAdpater adapter = new CPDFPrintAdpater(activity, document.getPageCount(), document.getFileName(), new CPDFPrintAdpater.IPrintCallback() {
+            @Override
+            public Bitmap onWriteBitmap(int pageNum, int pageWidth, boolean isDrawAnnot) {
+                return pdfToBitmap(document, pageNum, pageWidth, isDrawAnnot);
+            }
+            @Override
+            public void onFinish() {
+
+            }
+        });
+        adapter.setResolutionScale(CPDFPrintAdpater.FHQ);
+        adapter.setDrawAnnot(true);
+        return adapter;
+    }
+
+    private static Bitmap pdfToBitmap(CPDFDocument mCPDFDocument, int pageIndex, int pageWidth_, boolean isDrawAnnot) {
+        Bitmap bitmap = null;
+        if (mCPDFDocument != null) {
+            CPDFPage page = mCPDFDocument.pageAtIndex(pageIndex);
+            if (page != null) {
+                int pageWidth = pageWidth_;
+                if (pageWidth == -1) {
+                    pageWidth = (int) page.getSize().width();
+                }
+                int pageHeight = (int) (page.getSize().height() / page.getSize().width() * pageWidth);
+                float scale = (float) pageWidth / page.getSize().width();
+                if (pageWidth != 0 && pageHeight != 0) {
+                    bitmap = Bitmap.createBitmap(pageWidth, pageHeight, Bitmap.Config.ARGB_8888);
+                }
+
+                if (mCPDFDocument.isValid()) {
+                    mCPDFDocument.renderPageAtIndex(
+                            bitmap,
+                            pageIndex,
+                            pageWidth,
+                            pageHeight,
+                            0,
+                            0,
+                            pageWidth,
+                            pageHeight,
+                            Color.WHITE,
+                            255,
+                            0,
+                            isDrawAnnot,
+                            true
+                    );
+                }
+
+                if (bitmap == null || bitmap.isRecycled()) {
+                    if (pageWidth != 0 && pageHeight != 0) {
+                        bitmap = Bitmap.createBitmap(pageWidth, pageHeight, Bitmap.Config.ARGB_8888);
+                    }
+                }
+            }
+        }
+        return bitmap;
+    }
+}

+ 1 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfview/CPDFViewCtrl.java

@@ -294,7 +294,7 @@ public class CPDFViewCtrl extends ConstraintLayout implements IReaderViewCallbac
         });
     }
 
-    private void setPDFDocument(CPDFDocument cpdfDocument, Object pdf, CPDFDocument.PDFDocumentError error, COnOpenPdfFinishCallback openPdfFinishCallback) {
+    public void setPDFDocument(CPDFDocument cpdfDocument, Object pdf, CPDFDocument.PDFDocumentError error, COnOpenPdfFinishCallback openPdfFinishCallback) {
         CLog.e("ComPDFKit", "CPDFViewCtrl-openPDF:" + error.name());
         // Switch on the result of the open method to handle the different possible outcomes.
         switch (error) {

+ 16 - 2
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/security/watermark/CWatermarkEditDialog.java

@@ -89,6 +89,8 @@ public class CWatermarkEditDialog extends CBasicBottomSheetDialogFragment implem
 
     private String defaultImagePath;
 
+    private boolean saveAsNewFile = true;
+
     protected CMultiplePermissionResultLauncher multiplePermissionResultLauncher = new CMultiplePermissionResultLauncher(this);
 
     public static CWatermarkEditDialog newInstance() {
@@ -110,6 +112,10 @@ public class CWatermarkEditDialog extends CBasicBottomSheetDialogFragment implem
         this.defaultImagePath = defaultImagePath;
     }
 
+    public void setSaveAsNewFile(boolean saveAsNewFile) {
+        this.saveAsNewFile = saveAsNewFile;
+    }
+
     /**
      * If the file save path is not set, clicking [Save] will prompt a dialog for selecting the save path.
      * If a save path is already set, clicking [Save] will directly save the document to the specified directory.
@@ -188,6 +194,14 @@ public class CWatermarkEditDialog extends CBasicBottomSheetDialogFragment implem
                     return;
                 }
             }
+            if (!saveAsNewFile){
+                boolean success = ((CWatermarkPageFragment) fragment).applyWatermark();
+                if (completeListener != null) {
+                    completeListener.complete(false, null);
+                }
+                return;
+            }
+
             if (Build.VERSION.SDK_INT < CPermissionUtil.VERSION_R) {
                 multiplePermissionResultLauncher.launch(CPermissionUtil.STORAGE_PERMISSIONS, result -> {
                     if (CPermissionUtil.hasStoragePermissions(getContext())) {
@@ -276,7 +290,7 @@ public class CWatermarkEditDialog extends CBasicBottomSheetDialogFragment implem
                         document.reload();
                     }
                     if (completeListener != null) {
-                        completeListener.complete(result);
+                        completeListener.complete(true, result);
                     }
                 }
             }.execute();
@@ -339,6 +353,6 @@ public class CWatermarkEditDialog extends CBasicBottomSheetDialogFragment implem
     }
 
     public interface CEditCompleteListener {
-        void complete(String pdfFile);
+        void complete(boolean saveAsNewFile, String pdfFile);
     }
 }

+ 2 - 1
ComPDFKit_Tools/src/main/res/values-zh-rCN/tools_strings.xml

@@ -533,5 +533,6 @@
     <string name="tools_save_path">文件存储路径</string>
     <string name="tools_compressed_successfully">压缩成功</string>
     <string name="compressing_">正在压缩&#8230;</string>
-
+    <string name="tools_print_systemversion_not_support">打印功能支持4.4以上安卓系统,请升级您的系统。</string>
+    <string name="tools_print_not_working">打印机不可用。</string>
 </resources>

+ 2 - 1
ComPDFKit_Tools/src/main/res/values/tools_strings.xml

@@ -546,5 +546,6 @@
     <string name="tools_compressed_successfully">Compressed successfully!</string>
     <string name="compressing_">Compressing&#8230;</string>
 
-
+    <string name="tools_print_systemversion_not_support">Printer feature supports Android System 4.4 at least. Please upgrade your system.</string>
+    <string name="tools_print_not_working">Printer is not available.</string>
 </resources>

+ 2 - 1
PDFViewer/build.gradle

@@ -55,6 +55,7 @@ dependencies {
     implementation 'com.google.android.material:material:1.8.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
     api project(path: ':ComPDFKit_Tools')
+
     // or
-//    implementation ('com.compdf:compdfkit-tools:2.2.1')
+//    implementation ('com.compdf:compdfkit-tools:2.2.2-SNAPSHOT')
 }

+ 1 - 1
PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/FunSamplesActivity.java

@@ -84,7 +84,7 @@ public class FunSamplesActivity extends AppCompatActivity implements View.OnClic
 //        editDialog.setSavePath(saveFile.getAbsolutePath());
 //        editDialog.setDefaultText("ComPDFKit");
 //                editDialog.setDefaultImagePath("xxx.png");
-        editDialog.setCompleteListener(pdfFile -> {
+        editDialog.setCompleteListener((saveAsNewFile, pdfFile) -> {
             if (!TextUtils.isEmpty(pdfFile)){
                 openPDF(pdfFile);
             }

+ 1 - 1
PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/samples/WatermarkSamplesImpl.java

@@ -74,7 +74,7 @@ public class WatermarkSamplesImpl extends OpenPDFSamplesImpl {
                 watermarkEditDialog.setDocument(document);
                 watermarkEditDialog.setSaveFileExtraFontSubset(SettingDatas.isExtraFontSet(fragment.getContext()));
                 watermarkEditDialog.setPageIndex(0);
-                watermarkEditDialog.setCompleteListener(pdfFile -> {
+                watermarkEditDialog.setCompleteListener((saveAsNewFile, pdfFile) -> {
                     watermarkEditDialog.dismiss();
                     if (TextUtils.isEmpty(pdfFile)){
                         CToastUtil.showLongToast(fragment.getContext(), R.string.tools_watermark_add_failed);

+ 1 - 1
compdfkit-tools-mavencentral.gradle

@@ -1,7 +1,7 @@
 apply plugin: 'maven-publish'
 apply plugin: 'signing'
 
-def PUBLISH_VERSION = '2.2.1'
+def PUBLISH_VERSION = '2.2.2-SNAPSHOT'
 def PUBLISH_GROUP_ID = 'com.compdf'
 def PUBLISH_ARTIFACT_ID = 'compdfkit-tools'
 

+ 3 - 3
config.gradle

@@ -3,10 +3,10 @@ ext {
             COMPILESDK: 34,
             MINSDK: 21,
             TARGETSDK: 34,
-            VERSIONCODE: 1018
+            VERSIONCODE: 1019
     ]
     sdk = [
-            COMPDFKIT_SDK_VERSION : "2.2.1",
-            COMPDFKIT_SDK_BUILD_TAG : "build_dev_2.2.1_4aef7ae8_202412101057"
+            COMPDFKIT_SDK_VERSION : "2.2.2",
+            COMPDFKIT_SDK_BUILD_TAG : "build_dev_2.2.2_4aef7ae8_202412101057"
     ]
 }

+ 1 - 0
settings.gradle

@@ -3,6 +3,7 @@ pluginManagement {
         google()
         mavenCentral()
         gradlePluginPortal()
+        maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
     }
 }
 dependencyResolutionManagement {