Browse Source

完成基本水印功能

dengyujia 2 years ago
parent
commit
6c62a5027c

+ 6 - 6
.idea/deploymentTargetDropDown.xml

@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="deploymentTargetDropDown">
-    <targetSelectedWithDropDown>
+    <runningDeviceTargetSelectedWithDropDown>
       <Target>
-        <type value="QUICK_BOOT_TARGET" />
+        <type value="RUNNING_DEVICE_TARGET" />
         <deviceKey>
           <Key>
-            <type value="VIRTUAL_DEVICE_PATH" />
-            <value value="C:\Users\KAD\.android\avd\Pixel_6_Pro_API_33.avd" />
+            <type value="SERIAL_NUMBER" />
+            <value value="9A241FFBA005YG" />
           </Key>
         </deviceKey>
       </Target>
-    </targetSelectedWithDropDown>
-    <timeTargetWasSelectedWithDropDown value="2022-11-16T12:08:26.803971100Z" />
+    </runningDeviceTargetSelectedWithDropDown>
+    <timeTargetWasSelectedWithDropDown value="2022-11-29T09:47:46.949607100Z" />
   </component>
 </project>

+ 146 - 131
app/src/main/java/com/compdfkit/pdfviewer/MainActivity.java

@@ -3,12 +3,14 @@ package com.compdfkit.pdfviewer;
 import androidx.annotation.NonNull;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.widget.Toolbar;
+import androidx.core.content.ContextCompat;
 import androidx.core.view.MenuProvider;
 
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
 import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -23,35 +25,51 @@ import android.view.View;
 import android.widget.ImageView;
 import android.widget.Toast;
 
+import com.compdfkit.core.common.CPDFDocumentException;
 import com.compdfkit.core.document.CPDFDocument;
 import com.compdfkit.core.page.CPDFPage;
 import com.compdfkit.core.utils.ColorUtils;
+import com.compdfkit.core.watermark.CPDFImageWatermark;
 import com.compdfkit.core.watermark.CPDFTextWatermark;
 import com.compdfkit.core.watermark.CPDFWatermark;
+import com.compdfkit.pdfviewer.customview.ImageWatermarkView;
+import com.compdfkit.pdfviewer.customview.TextWatermarkView;
 import com.compdfkit.pdfviewer.customview.WatermarkView;
+import com.compdfkit.pdfviewer.entity.WatermarkSetting;
 import com.compdfkit.pdfviewer.fragments.WatermarkConsoleFragment;
+import com.compdfkit.pdfviewer.tools.CoordinateMapper;
 import com.compdfkit.ui.reader.CPDFReaderView;
 import com.google.android.material.tabs.TabLayout;
 
+import org.w3c.dom.Text;
+
 import java.io.File;
 
 public class MainActivity extends AppCompatActivity implements MenuProvider {
     private ImageView pageImage;
 
     private CPDFDocument document = new CPDFDocument(this);
-
     private WatermarkView watermark;
+    private WatermarkConsoleFragment consoleFragment;
+
+    private int currentPageHeight = 0;
+    private int currentPageWidth = 0;
+
+    private float sizeConvertRate = 0;
+
+    private CPDFPage testPage;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
+        addMenuProvider(this);
 
         Toolbar toolbar = findViewById(R.id.toolbar);
         setSupportActionBar(toolbar);
 
         watermark = findViewById(R.id.watermark_text);
-        WatermarkConsoleFragment consoleFragment = (WatermarkConsoleFragment) getSupportFragmentManager().findFragmentByTag("console_fragment");
+        consoleFragment = (WatermarkConsoleFragment) getSupportFragmentManager().findFragmentByTag("console_fragment");
 
         assert consoleFragment != null;
         consoleFragment.setAssociatedWatermark(watermark);
@@ -61,11 +79,12 @@ public class MainActivity extends AppCompatActivity implements MenuProvider {
         TabLayout tabLayout = findViewById(R.id.tab_layout);
         tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
             @Override
-
             public void onTabSelected(TabLayout.Tab tab) {
                 changeWatermark(tab.getPosition());
 
+                consoleFragment.setAssociatedWatermark(watermark);
                 consoleFragment.changePicker(tab.getPosition());
+                watermark = tab.getPosition() == 0 ? findViewById(R.id.watermark_text) : findViewById(R.id.watermark_image);
             }
 
             @Override
@@ -81,23 +100,42 @@ public class MainActivity extends AppCompatActivity implements MenuProvider {
             startActivity(intent);
         }
 
-        File PDFFile = new File("/storage/emulated/0/TestPDFs/01.pdf");
+        File PDFFile = new File("/storage/emulated/0/TestPDFs/test.pdf");
         Uri PDFUri = Uri.fromFile(PDFFile);
 
         CPDFDocument.PDFDocumentError error = document.open(PDFFile.getAbsolutePath());
 
+        if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorPassword) {
+            error = document.open(PDFUri, "password");
+        } else if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorSuccess) {
+            Toast.makeText(this, "File:" + document.getFileName() + " open success.", Toast.LENGTH_SHORT).show();
+        } else {
+            Toast.makeText(this, "File failed.", Toast.LENGTH_SHORT).show();
+        }
+
         CPDFPage currentPage = document.pageAtIndex(0);
+        testPage = currentPage;
 
         RectF pageSize = document.getPageSize(0);
         float pageW = pageSize.right - pageSize.left;
         float pageH = pageSize.bottom - pageSize.top;
 
         pageImage.post(() -> {
-            int imageWidth = (int) (pageImage.getHeight() / pageH * pageW);
-            Bitmap pageBitmap = Bitmap.createBitmap(imageWidth, pageImage.getHeight(), Bitmap.Config.RGB_565);
+            int imageHeight = pageImage.getHeight();
+            sizeConvertRate = pageImage.getHeight() / pageH;
+            int imageWidth = (int) (sizeConvertRate * pageW);
+
+            TextWatermarkView tempT = (TextWatermarkView) watermark;
+            tempT.setSizeConvertRate(sizeConvertRate);
+            ImageWatermarkView tempI = findViewById(R.id.watermark_image);
+            tempI.setSizeConvertRate(sizeConvertRate);
 
-            currentPage.renderPage(pageBitmap, 0, 0, imageWidth, pageImage.getHeight(), 0xFFFFFFFF, 100, 0, true, true);
-            pageImage.setImageBitmap(pageBitmap);
+            currentPageHeight = pageImage.getHeight();
+            currentPageWidth = imageWidth;
+            Bitmap pageBitmap = Bitmap.createBitmap(imageWidth, pageImage.getHeight(), Bitmap.Config.ARGB_4444);
+
+            currentPage.renderPage(pageBitmap, 0, 0, imageWidth, pageImage.getHeight(), 0xFFFFFFFF, 255, 0, true, true);
+            refreshPageImage(pageBitmap);
 
             pageImage.setOnDragListener(new View.OnDragListener() {
                 float currentSlope;
@@ -112,7 +150,7 @@ public class MainActivity extends AppCompatActivity implements MenuProvider {
                 @Override
                 public boolean onDrag(View view, DragEvent dragEvent) {
 
-                    if (watermark.getCurrentEvent() == 0) {
+                    if (watermark.getCurrentEvent() == WatermarkView.DRAG_EVENT) {
                         float xOffset = 1.0f * watermark.getWidth() / 2;
                         float yOffset = 1.0f * watermark.getHeight() / 2;
 
@@ -122,25 +160,29 @@ public class MainActivity extends AppCompatActivity implements MenuProvider {
 
                         //TODO:需要优化控件越界行为
                         switch (dragEvent.getAction()) {
-                            case DragEvent.ACTION_DRAG_STARTED:
-                                return true;
-                            case DragEvent.ACTION_DRAG_ENTERED:
-                                return true;
                             case DragEvent.ACTION_DRAG_LOCATION:
-                                watermark.setX(dragEvent.getX() + xOutline - xOffset); // dragEvent.getX()
-                                watermark.setY(dragEvent.getY() + yOutline - yOffset); // dragEvent.getY()
-
-                                Log.d("DragTest", "Drag Location: (" + dragEvent.getX() + "," + dragEvent.getY() + ")");
-                                Log.d("DragTest", "Watermark Location: (" + location[0] + "," + location[1] + ")");
+                                watermark.setX(dragEvent.getX() + xOutline - xOffset);
+                                watermark.setY(dragEvent.getY() + yOutline - yOffset);
+
+                                watermark.setPDFXOffset(CoordinateMapper.convertViewXtoPDFXOffset(watermark.getX() - pageImage.getLeft(), xOffset, imageWidth / 2, sizeConvertRate));
+                                watermark.setPDFYOffset(CoordinateMapper.convertViewYtoPDFYOffset(watermark.getY() - pageImage.getTop(), yOffset, imageHeight / 2, sizeConvertRate));
+
+//                                Log.d("DragTest", "Drag Location: (" + dragEvent.getX() + "," + dragEvent.getY() + ")");
+//                                Log.d("DragTest", "Watermark Location: (" + location[0] + "," + location[1] + ")");
+//                                Log.d("DragTest", "Watermark get xy: (" + watermark.getX() + "," + watermark.getY() + ")");
+//                                Log.d("DragTest", "pdf page w h: (" + pageW + "," + pageH + ")");
+//                                Log.d("DragTest", "Watermark get PDF xy: (" + CoordinateMapper.convertViewXtoPDFXOffset(watermark.getX() - pageImage.getLeft(), xOffset, imageWidth / 2, sizeConvertRate)
+//                                        + "," + CoordinateMapper.convertViewYtoPDFYOffset(watermark.getY() - pageImage.getTop(), yOffset, imageHeight / 2, sizeConvertRate) + ")");
                                 return true;
                             case DragEvent.ACTION_DRAG_ENDED:
                                 watermark.setVisibility(View.VISIBLE);
                                 return false;
+                            default:
+                                return true;
                         }
-                        return true;
                     } else {
-                        float xOffset = 1.0f * watermark.getWidth() / 2;/* 1.0f * watermark.getWatermarkLayout().getWidth() / 2;  /* 控件一半宽度 */
-                        float yOffset = 1.0f * watermark.getHeight() / 2;;/*1.0f * watermark.getWatermarkLayout().getHeight() / 2; /* 控件一半高度 */
+                        float xOffset = 1.0f * watermark.getWidth() / 2; /* 控件一半宽度 */
+                        float yOffset = 1.0f * watermark.getHeight() / 2; /* 控件一半高度 */
 
                         float baseSlope = yOffset / xOffset * -1;
 
@@ -149,125 +191,31 @@ public class MainActivity extends AppCompatActivity implements MenuProvider {
                         float centerPointX = watermark.getX() + 1.0f * watermark.getWidth() / 2; /* 控件中心点x = 当前控件位置x + 控件一半宽度 */
                         float centerPointY = watermark.getY() + 1.0f * watermark.getHeight() / 2; /* 控件中心点y = 当前控件位置y + 控件一半高度 */
 
-                        switch (dragEvent.getAction()) {
-                            case DragEvent.ACTION_DRAG_STARTED:
-                                return true;
-                            case DragEvent.ACTION_DRAG_ENTERED:
-                                return true;
-                            case DragEvent.ACTION_DRAG_LOCATION:
-
-                                //TODO:该部分的取坐标存在冗余代码
-                                currentSlope = (dragEvent.getY() + pageImage.getTop() - centerPointY) / (dragEvent.getX() + pageImage.getLeft() - centerPointX) * -1;
-                                currentRotation = Math.atan(currentSlope) * convertRate;
+                        if (dragEvent.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
+                            //TODO:该部分的取坐标存在冗余代码
+                            currentSlope = (dragEvent.getY() + pageImage.getTop() - centerPointY) / (dragEvent.getX() + pageImage.getLeft() - centerPointX) * -1;
+                            currentRotation = Math.atan(currentSlope) * convertRate;
 
-                                if (dragEvent.getY() + pageImage.getTop() < centerPointY && dragEvent.getX() + pageImage.getLeft() < centerPointX)
-                                    currentRotation += 180;
+                            if ((dragEvent.getY() + pageImage.getTop() < centerPointY && dragEvent.getX() + pageImage.getLeft() < centerPointX) || (dragEvent.getY() + pageImage.getTop() > centerPointY && dragEvent.getX() + pageImage.getLeft() < centerPointX)) {
+                                currentRotation += 180;
+                                currentSlope += 3.1415926f;
+                            }
 
-                                if (dragEvent.getY() + pageImage.getTop() > centerPointY && dragEvent.getX() + pageImage.getLeft() < centerPointX)
-                                    currentRotation += 180;
+                            resultRotation = currentRotation - Math.atan(baseSlope) * convertRate;
 
-                                resultRotation = currentRotation - Math.atan(baseSlope) * convertRate;
-
-                                watermark.setRotation((float) resultRotation * -1);
-                                watermark.setRotationRadian((float) Math.atan(currentSlope));
-                                Log.d("RollTest", "Current slope: " + currentSlope + ", Result rotation: " + resultRotation + ", Current rotation: " + currentRotation);
-                                return true;
-                            case DragEvent.ACTION_DRAG_ENDED:
-                                watermark.setVisibility(View.VISIBLE);
-                                return true;
+                            watermark.setRotation((float) resultRotation * -1);
+                            watermark.setRotationRadian((float) (resultRotation / convertRate));
+//                                Log.d("RollTest", "Current slope: " + currentSlope + ", Result rotation: " + resultRotation + ", Current rotation: " + currentRotation);
+                            return true;
                         }
+                        return true;
                     }
-                    return true;
                 }
             });
         });
 
+        Log.d("Render. Watermark Count", "current watermark count:" + document.getWatermarkCount());
 
-        if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorPassword) {
-            error = document.open(PDFUri, "password");
-        } else if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorSuccess) {
-            Toast.makeText(this, "File:" + document.getFileName() + " open success.", Toast.LENGTH_SHORT).show();
-        } else {
-            Toast.makeText(this, "File failed.", Toast.LENGTH_SHORT).show();
-        }
-
-        int watermarkIndex = 0;
-        CPDFWatermark watermarkz = null;
-
-        try {
-            watermarkz = document.getWatermark(watermarkIndex);
-            if (watermarkz != null)
-                watermarkz.clear();
-        } finally {
-            if (watermarkz != null && watermarkz.isValid()) {
-                watermarkz.release();
-            }
-        }
-
-//        Drawable drawable = ContextCompat.getDrawable(this, R.drawable.pdf);
-//
-//        CPDFImageWatermark imgWatermark = (CPDFImageWatermark)
-//                document.createWatermark(CPDFWatermark.Type.WATERMARK_TYPE_IMG);
-//
-//        assert drawable != null;
-//        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
-//        Canvas canvas = new Canvas(bitmap);
-//        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
-//        drawable.draw(canvas);
-//
-//        try {
-//            if (imgWatermark != null && imgWatermark.isValid()) {
-//                imgWatermark.setText("RA"); //设置文本
-//                imgWatermark.setFontName("Helvetica"); //设置字体
-//                imgWatermark.setImage(bitmap, 100, 100);
-//                imgWatermark.setTextRGBColor(ColorUtils.parseColor(new int[] { 102, 204, 255 }));
-//                imgWatermark.setOpacity(0.5f);
-//                imgWatermark.setRotation(0.785f);
-//                imgWatermark.setFontSize(100);
-//                imgWatermark.setFront(false);
-//                imgWatermark.setVertalign(CPDFWatermark.Vertalign.WATERMARK_VERTALIGN_CENTER);
-//                imgWatermark.setHorizalign(CPDFWatermark.Horizalign.WATERMARK_HORIZALIGN_CENTER);
-//                imgWatermark.setVertOffset(0);
-//                imgWatermark.setHorizOffset(0);
-//                imgWatermark.setScale(0.2f);
-//                imgWatermark.setPages("1,3-5");
-//                imgWatermark.setFullScreen(true);
-//                imgWatermark.setHorizontalSpacing(100);
-//                imgWatermark.setVerticalSpacing(100);
-//                imgWatermark.update();
-//            }
-//        } finally {
-//            if (imgWatermark != null && imgWatermark.isValid()) {
-//                imgWatermark.release();
-//            }
-//        }
-
-//        CPDFTextWatermark textWatermark = (CPDFTextWatermark)
-//                document.createWatermark(CPDFWatermark.Type.WATERMARK_TYPE_TEXT);
-//        try {
-//            if (textWatermark != null && textWatermark.isValid()) {
-//                textWatermark.setText("Watermark"); //设置文本
-//                textWatermark.setFontName("Helvetica"); //设置字体
-//                textWatermark.setTextRGBColor(ColorUtils.parseColor(new int[] { 255, 0, 0 }));
-//                textWatermark.setOpacity(1f);
-//                textWatermark.setFontSize(62);
-//                textWatermark.setFront(true);
-//                textWatermark.setVertalign(CPDFWatermark.Vertalign.WATERMARK_VERTALIGN_CENTER);
-//                textWatermark.setHorizalign(CPDFWatermark.Horizalign.WATERMARK_HORIZALIGN_CENTER);
-//                textWatermark.setVertOffset(0);
-//                textWatermark.setHorizOffset(0);
-//                textWatermark.setScale(1.0f);
-//                textWatermark.setPages("0-5");
-//                textWatermark.setFullScreen(false);
-//                textWatermark.setHorizontalSpacing(10);
-//                textWatermark.setVerticalSpacing(10);
-//                textWatermark.update();
-//            }
-//        } finally {
-//            if (textWatermark != null && textWatermark.isValid()) {
-//                textWatermark.release();
-//            }
-//        }
     }
 
     @Override
@@ -293,4 +241,71 @@ public class MainActivity extends AppCompatActivity implements MenuProvider {
     public void refreshPageImage(Bitmap updatePageBitmap) {
         pageImage.setImageBitmap(updatePageBitmap);
     }
+
+    public void finishEditWatermark(MenuItem menuItem) throws CPDFDocumentException {
+        WatermarkSetting setting = consoleFragment.getWatermarkSetting();
+        watermark.completeSetting(setting);
+
+        CPDFWatermark.Type[] types = {CPDFWatermark.Type.WATERMARK_TYPE_TEXT, CPDFWatermark.Type.WATERMARK_TYPE_IMG};
+
+        CPDFWatermark watermark;
+        watermark = document.createWatermark(types[consoleFragment.getMode()]);
+        try {
+            if (watermark != null && watermark.isValid()) {
+                if (setting.getImage() != null)
+                    watermark.setImage(setting.getImage(), (int) (setting.getiWidth() * sizeConvertRate), (int) (setting.getiHeight() * sizeConvertRate));
+                watermark.setText(setting.getText()); //设置文本
+                watermark.setFontName(setting.getFontName()); //设置字体
+                watermark.setTextRGBColor(setting.getTextRGBColor());
+                watermark.setOpacity(setting.getOpacity());
+                watermark.setFontSize(setting.getFontSize());
+                watermark.setFront(true);
+                watermark.setVertalign(CPDFWatermark.Vertalign.WATERMARK_VERTALIGN_CENTER);
+                watermark.setHorizalign(CPDFWatermark.Horizalign.WATERMARK_HORIZALIGN_CENTER);
+                watermark.setVertOffset(setting.getVertOffset());
+                watermark.setHorizOffset(setting.getHorizOffset());
+                watermark.setRotation(setting.getRotation());
+                watermark.setScale(setting.getScale());
+                watermark.setPages(setting.getPages());
+                watermark.setFullScreen(setting.getFullScreen());
+                watermark.setHorizontalSpacing(setting.getHorizontalSpacing());
+                watermark.setVerticalSpacing(setting.getVerticalSpacing());
+                watermark.update();
+            }
+        } finally {
+            if (watermark != null && watermark.isValid()) {
+                watermark.release();
+            }
+        }
+
+        Log.d("Finish. Watermark Count", "current watermark count:" + document.getWatermarkCount());
+
+        if (document.hasChanges()) {
+            boolean res;
+            //Save to original document
+            res = document.save();
+        }
+        document.close();
+
+        File PDFFile = new File("/storage/emulated/0/TestPDFs/test.pdf");
+        Uri PDFUri = Uri.fromFile(PDFFile);
+
+        CPDFDocument.PDFDocumentError error = document.open(PDFFile.getAbsolutePath());
+
+        if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorPassword) {
+            error = document.open(PDFUri, "password");
+        } else if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorSuccess) {
+            Toast.makeText(this, "File:" + document.getFileName() + " open success.", Toast.LENGTH_SHORT).show();
+        } else {
+            Toast.makeText(this, "File failed.", Toast.LENGTH_SHORT).show();
+        }
+
+        CPDFPage currentPage = document.pageAtIndex(0);
+//        currentPage.equals(testPage)
+        Log.d("Finish EditWatermark", "the equal's result:" + (currentPage.equals(testPage)) );
+
+        Bitmap pageBitmap = Bitmap.createBitmap(currentPageWidth, currentPageHeight, Bitmap.Config.ARGB_4444);
+        currentPage.renderPage(pageBitmap, 0, 0, currentPageWidth, currentPageHeight, 0xFFFFFFFF, 255, 0, true, true);
+        refreshPageImage(pageBitmap);
+    }
 }

+ 56 - 5
app/src/main/java/com/compdfkit/pdfviewer/customview/ImageWatermarkView.java

@@ -4,6 +4,11 @@ import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -11,18 +16,20 @@ import android.view.MotionEvent;
 import android.view.View;
 import android.widget.ImageButton;
 import android.widget.ImageView;
+import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
 
 import com.compdfkit.pdfviewer.R;
 import com.compdfkit.pdfviewer.entity.WatermarkSetting;
 
 public class ImageWatermarkView extends WatermarkView {
-    private View WatermarkLayout;
-
     private ImageView watermarkImage;
 
+    private Bitmap initBitmap;
+
     public ImageWatermarkView(@NonNull Context context) {
         this(context, null);
     }
@@ -48,9 +55,27 @@ public class ImageWatermarkView extends WatermarkView {
         currentView = inflater.inflate(R.layout.watermark_image_view, this, true);
 
         watermarkImage = currentView.findViewById(R.id.image_watermark);
+        watermarkImage.post(() -> {
+            Drawable drawable = ContextCompat.getDrawable(currentContext, R.drawable.pdf);
+            assert drawable != null;
+            initBitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_4444);
+            Canvas canvas = new Canvas(initBitmap);
+            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+            drawable.draw(canvas);
+        });
+
         rollingHandle = currentView.findViewById(R.id.watermark_i_handle);
 
         currentView.setOnTouchListener((view, motionEvent) -> {
+            switch (motionEvent.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    break;
+                case MotionEvent.ACTION_UP:
+                    view.performClick();
+                    break;
+                default:
+                    break;
+            }
             ClipData.Item item = new ClipData.Item((CharSequence) view.getTag());
             ClipData dragData = new ClipData(
                     (CharSequence) view.getTag(),
@@ -94,14 +119,40 @@ public class ImageWatermarkView extends WatermarkView {
 
     @Override
     public void setWatermarkScale(float scale) {
-        watermarkImage.setScaleX(scale);
-        watermarkImage.setScaleY(scale);
+        Matrix matrix = new Matrix();
+        matrix.postScale(scale, scale);
+        Bitmap resizeBmp = Bitmap.createBitmap(initBitmap, 0, 0, initBitmap.getWidth(), initBitmap.getHeight(), matrix, true);
+
+        watermarkImage.setImageBitmap(resizeBmp);
     }
 
     @Override
     public WatermarkSetting completeSetting(WatermarkSetting setting) {
-        setting.setImage(null);
+        Matrix matrix = new Matrix();
+        matrix.postScale(1 / sizeConvertRate, 1 / sizeConvertRate);
+        Bitmap resultBitmap = Bitmap.createBitmap(initBitmap, 0, 0, initBitmap.getWidth(), initBitmap.getHeight(), matrix, true);
+
+        setting.setImage(resultBitmap);
+        setting.setiWidth(resultBitmap.getWidth());
+        setting.setiHeight(resultBitmap.getHeight());
+        setting.setHorizOffset(getPDFXOffset());
+        setting.setVertOffset(getPDFYOffset());
         setting.setRotation(rotationRadian);
         return setting;
     }
+
+    @Override
+    public void setSizeConvertRate(float sizeConvertRate) {
+        super.setSizeConvertRate(sizeConvertRate);
+    }
+
+    public void setWatermarkImageFromPath(String imagePath) {
+        if (imagePath != null) {
+            Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
+            initBitmap = bitmap;
+            watermarkImage.setImageBitmap(bitmap);
+        } else {
+            Toast.makeText(currentContext, "获取图片失败", Toast.LENGTH_SHORT).show();
+        }
+    }
 }

+ 83 - 40
app/src/main/java/com/compdfkit/pdfviewer/customview/TextWatermarkView.java

@@ -1,23 +1,26 @@
 package com.compdfkit.pdfviewer.customview;
 
-import android.annotation.SuppressLint;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.res.TypedArray;
 import android.os.Build;
+import android.text.Editable;
+import android.text.TextWatcher;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.widget.EditText;
+import android.widget.Button;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.widget.AppCompatEditText;
+import androidx.constraintlayout.widget.ConstraintLayout;
 
 import com.compdfkit.pdfviewer.R;
 import com.compdfkit.pdfviewer.entity.WatermarkSetting;
@@ -48,58 +51,84 @@ public class TextWatermarkView extends WatermarkView{
         currentContext = context;
         inflater = (LayoutInflater) currentContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
-        TypedArray attribute = currentContext.obtainStyledAttributes(attrs, R.styleable.WatermarkView);
         currentView = inflater.inflate(R.layout.watermark_text_view, this, true);
 
         watermarkText = currentView.findViewById(R.id.text_watermark);
         rollingHandle = currentView.findViewById(R.id.watermark_t_handle);
 
-        currentView.setOnTouchListener((view, motionEvent) -> {
-            ClipData.Item item = new ClipData.Item((CharSequence) view.getTag());
-            ClipData dragData = new ClipData(
-                    (CharSequence) view.getTag(),
-                    new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN },
-                    item);
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-                view.startDragAndDrop(dragData, new DragShadowBuilder(rollingHandle), null, 0);     //自定义DragShadowBuilder
-            }
+        setRollingHandle();
 
-            currentEvent = 0;
-            return true;
+        this.setOnTouchListener(new OnTouchListener() {
+            float x, y;
+            @Override
+            public boolean onTouch(View view, MotionEvent motionEvent) {
+                switch (motionEvent.getAction()) {
+                    case MotionEvent.ACTION_DOWN:
+                        x = motionEvent.getRawX();
+                        y = motionEvent.getRawY();
+                        break;
+                    case MotionEvent.ACTION_MOVE:
+                        if (Math.abs(motionEvent.getRawX() - x) > 6 && Math.abs(motionEvent.getRawY() - y) > 6) {
+                            ClipData.Item item = new ClipData.Item((CharSequence) view.getTag());
+                            ClipData dragData = new ClipData(
+                                    (CharSequence) view.getTag(),
+                                    new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN },
+                                    item);
+                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                                view.startDragAndDrop(dragData, new DragShadowBuilder(rollingHandle), null, 0);     //自定义DragShadowBuilder
+                            }
+                            currentEvent = 0;
+                        }
+                        return true;
+                    case MotionEvent.ACTION_UP:
+                        view.performClick();
+                        break;
+                    default:
+                        break;
+                }
+                return true;
+            }
         });
+    }
+
+    @Override
+    public boolean performClick() {
+        LayoutInflater inflater = LayoutInflater.from(currentContext);
+        final ConstraintLayout textEditorLayout = (ConstraintLayout) inflater.inflate(R.layout.text_editor, null);
+        final AppCompatEditText editText = textEditorLayout.findViewById(R.id.text_editor);
+
+        final Button[] positiveButton = new Button[1];
+
+        editText.setText(watermarkText.getText());
+        AlertDialog.Builder inputDialog = new AlertDialog.Builder(currentContext);
+        inputDialog.setTitle("Text watermark").setView(textEditorLayout);
+        inputDialog.setPositiveButton("Done", (dialogInterface, i) -> watermarkText.setText(editText.getText().toString()));
+
+        editText.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
 
-        watermarkText.setOnClickListener(new OnClickListener() {
-            @SuppressLint("SetTextI18n")
             @Override
-            public void onClick(View view) {
-                final EditText editText = new EditText(currentContext);
-                editText.setText(watermarkText.getText().toString());
-
-                AlertDialog.Builder inputDialog = new AlertDialog.Builder(currentContext);
-                inputDialog.setTitle("Text watermark").setView(editText);
-                inputDialog.setPositiveButton("Done", new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialogInterface, int i) {
-                        watermarkText.setText(editText.getText().toString());
-                    }
-                });
-
-                inputDialog.setNegativeButton("Cancle", new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialogInterface, int i) {}
-                });
-                inputDialog.show();
+            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
+
+            @Override
+            public void afterTextChanged(Editable editable) {
+                positiveButton[0].setEnabled(!editText.getText().toString().equals(""));
             }
         });
 
-        setRollingHandle();
+        inputDialog.setNegativeButton("Cancle", (dialogInterface, i) -> {});
+
+        AlertDialog dialog = inputDialog.create();
+        dialog.show();
+
+        positiveButton[0] = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
+        return super.performClick();
     }
 
     @Override
     public void setRollingHandle() {
-        rollingHandle.setOnTouchListener(new OnTouchListener() {
-            @Override
-            public boolean onTouch(View view, MotionEvent motionEvent) {
+        rollingHandle.setOnTouchListener((View view, MotionEvent motionEvent) -> {
                 currentEvent = 1;
                 ClipData.Item item = new ClipData.Item((CharSequence) view.getTag());
                 ClipData dragData = new ClipData(
@@ -110,7 +139,6 @@ public class TextWatermarkView extends WatermarkView{
                     view.startDragAndDrop(dragData, new DragShadowBuilder(rollingHandle), null, 0);     //自定义DragShadowBuilder
                 }
                 return true;
-            }
         });
     }
 
@@ -129,10 +157,25 @@ public class TextWatermarkView extends WatermarkView{
         watermarkText.setTextColor(color);
     }
 
+    public void setTextDefaultSize(float textDefaultSize) {
+        this.textDefaultSize = textDefaultSize;
+        watermarkText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textDefaultSize);
+        Log.d("Watermark attribute", "Text Watermark: " + watermarkText.getTextSize());
+    }
+
     @Override
     public WatermarkSetting completeSetting(WatermarkSetting setting) {
+        setting.setHorizOffset(getPDFXOffset());
+        setting.setVertOffset(getPDFYOffset());
         setting.setText(watermarkText.getText().toString());
+        setting.setTextRGBColor(watermarkText.getCurrentTextColor());
         setting.setRotation(rotationRadian);
         return setting;
     }
+
+    @Override
+    public void setSizeConvertRate(float sizeConvertRate) {
+        super.setSizeConvertRate(sizeConvertRate);
+        setTextDefaultSize(sizeConvertRate * 62);
+    }
 }

+ 31 - 15
app/src/main/java/com/compdfkit/pdfviewer/customview/WatermarkView.java

@@ -1,29 +1,16 @@
 package com.compdfkit.pdfviewer.customview;
 
-import android.annotation.SuppressLint;
-import android.content.ClipData;
-import android.content.ClipDescription;
 import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.TypedArray;
-import android.os.Build;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.widget.EditText;
 import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
 import androidx.constraintlayout.widget.ConstraintLayout;
 
-import com.compdfkit.pdfviewer.R;
 import com.compdfkit.pdfviewer.entity.WatermarkSetting;
 
 public class WatermarkView extends ConstraintLayout {
@@ -33,9 +20,13 @@ public class WatermarkView extends ConstraintLayout {
     protected ImageButton rollingHandle;
 
     protected float rotationRadian = 0;
+    protected float sizeConvertRate = 0;
 
-    protected static int DRAG_EVENT = 0;
-    protected static int ROLL_EVENT = 1;
+    protected float PDFXOffset = 0;
+    protected float PDFYOffset = 0;
+
+    public static int DRAG_EVENT = 0;
+    public static int ROLL_EVENT = 1;
 
     //TODO:Try to change the event select.
     protected int currentEvent = 0;
@@ -79,4 +70,29 @@ public class WatermarkView extends ConstraintLayout {
     public int getCurrentEvent() {
         return currentEvent;
     }
+
+    public float getPDFXOffset() {
+        return PDFXOffset;
+    }
+
+    public void setPDFXOffset(float PDFXOffset) {
+        this.PDFXOffset = PDFXOffset;
+    }
+
+    public float getPDFYOffset() {
+        return PDFYOffset;
+    }
+
+    public void setPDFYOffset(float PDFYOffset) {
+        this.PDFYOffset = PDFYOffset;
+    }
+
+    public float getSizeConvertRate() {
+        return sizeConvertRate;
+    }
+
+    public void setSizeConvertRate(float sizeConvertRate) {
+        this.sizeConvertRate = sizeConvertRate;
+    }
+
 }

+ 26 - 4
app/src/main/java/com/compdfkit/pdfviewer/entity/WatermarkSetting.java

@@ -13,14 +13,35 @@ public class WatermarkSetting {
     private boolean fullScreen;
     private float horizOffset;
     private float horizontalSpacing;
+    private float vertOffset;
+    private float verticalSpacing;
     private float opacity;
     private String pages;
     private float rotation;
     private float scale;
     private String text;
     private int textRGBColor;
-    private float verticalSpacing;
-    private float vertOffset;
+
+    public WatermarkSetting() {
+        image = null;
+        iWidth = 0;
+        iHeight = 0;
+
+        fontName = "Roboto";
+        fontSize = 63;
+        front = true;
+        fullScreen = false;
+        horizOffset = 0;
+        horizontalSpacing = 100;
+        vertOffset = 0;
+        verticalSpacing = 100;
+        opacity = 50;
+        pages = "0";
+        rotation = 0;
+        scale = 1;
+        text = "Watermark";
+        textRGBColor = 0xFFFF0000;
+    }
 
     public Bitmap getImage() {
         return image;
@@ -59,7 +80,8 @@ public class WatermarkSetting {
     }
 
     public void setFontSize(float fontSize) {
-        this.fontSize = fontSize;
+        float conversionRate = 0.504f;
+        this.fontSize = fontSize * conversionRate;
     }
 
     public boolean isFront() {
@@ -70,7 +92,7 @@ public class WatermarkSetting {
         this.front = front;
     }
 
-    public boolean isFullScreen() {
+    public boolean getFullScreen() {
         return fullScreen;
     }
 

+ 168 - 26
app/src/main/java/com/compdfkit/pdfviewer/fragments/WatermarkConsoleFragment.java

@@ -1,23 +1,42 @@
 package com.compdfkit.pdfviewer.fragments;
 
+import static android.app.Activity.RESULT_OK;
+
+import android.Manifest;
 import android.annotation.SuppressLint;
+import android.content.ContentUris;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.net.Uri;
 import android.os.Bundle;
 
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.widget.AppCompatEditText;
+import androidx.appcompat.widget.AppCompatRadioButton;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
 import androidx.fragment.app.Fragment;
 
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.text.Editable;
+import android.text.TextWatcher;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.CompoundButton;
+import android.widget.Button;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.SeekBar;
-import android.widget.Spinner;
 import android.view.ViewGroup;
 import android.widget.CheckBox;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.compdfkit.pdfviewer.R;
+import com.compdfkit.pdfviewer.customview.ImageWatermarkView;
 import com.compdfkit.pdfviewer.customview.WatermarkView;
 import com.compdfkit.pdfviewer.entity.WatermarkSetting;
 import com.google.android.material.textfield.TextInputEditText;
@@ -26,6 +45,7 @@ import java.util.Objects;
 
 public class WatermarkConsoleFragment extends Fragment {
     private int mode;
+    private boolean isCustomRange = false;
 
     private int tWatermarkOpacity = 50;
     private int tWatermarkSize = 50;
@@ -33,28 +53,34 @@ public class WatermarkConsoleFragment extends Fragment {
     private int iWatermarkOpacity = 50;
     private int iWatermarkSize = 50;
 
-    private WatermarkSetting setting = new WatermarkSetting();
+    private final WatermarkSetting setting = new WatermarkSetting();
 
     private WatermarkView associatedWatermark = null;
 
     private View colorPicker;
     private View imagePicker;
 
+    private TextView imageSelectPathView;
+    private Button imageSelectBtn;
+
     private SeekBar opacitySlider;
     private SeekBar sizeSlider;
 
     private TextView opacityText;
     private TextView sizeText;
 
-    private Spinner rangeSpinner;
+    private TextView rangeMsg;
+    private ImageButton rangeButton;
 
     private CheckBox fullScreenCheck;
 
     private TextInputEditText hSpaceEdit;
     private TextInputEditText vSpaceEdit;
 
-    private int[] colorpickers = { R.id.color_1, R.id.color_2, R.id.color_3, R.id.color_4, R.id.color_5, R.id.color_6, R.id.color_7 };
-    private int[] colors = { 0xFFFF0000, 0xFFFF6600, 0xFFFFDD00, 0xFF00FF33, 0xFF00FFFF, 0xFF0022FF, 0xFF8800FF };
+    private final int[] colorPickers = { R.id.color_1, R.id.color_2, R.id.color_3, R.id.color_4, R.id.color_5, R.id.color_6, R.id.color_7 };
+    private final int[] colors = { 0xFFFF0000, 0xFFFF6600, 0xFFFFDD00, 0xFF00FF33, 0xFF00FFFF, 0xFF0022FF, 0xFF8800FF };
+
+    private String pageRange = "0";
 
     public WatermarkConsoleFragment() {
         // Required empty public constructor
@@ -84,6 +110,10 @@ public class WatermarkConsoleFragment extends Fragment {
         colorPicker = returnView.findViewById(R.id.color_picker);
         imagePicker = returnView.findViewById(R.id.image_picker);
 
+        imageSelectPathView = returnView.findViewById(R.id.image_select_path);
+        imageSelectBtn = returnView.findViewById(R.id.image_select_btn);
+        initImageSelectBtn();
+
         opacityText = returnView.findViewById(R.id.opacity_text);
         opacitySlider = returnView.findViewById(R.id.opacity_slider);
         initOpacitySlider();
@@ -92,8 +122,9 @@ public class WatermarkConsoleFragment extends Fragment {
         sizeSlider = returnView.findViewById(R.id.size_slider);
         initSizeSlider();
 
-        rangeSpinner = returnView.findViewById(R.id.page_range_spinner);
-        initRangeSpinner();
+        rangeMsg = returnView.findViewById(R.id.page_range_msg);
+        rangeButton = returnView.findViewById(R.id.page_range_button);
+        initRangeButton();
 
         fullScreenCheck = returnView.findViewById(R.id.full_screen_checkbox);
         initFullScreenCheck();
@@ -106,18 +137,76 @@ public class WatermarkConsoleFragment extends Fragment {
 
     private void initColorPicker(View returnView) {
         for (int i = 0; i < 7; i++) {
-            ImageView tempColor = returnView.findViewById(colorpickers[i]);
+            ImageView tempColor = returnView.findViewById(colorPickers[i]);
 
             int tempI = i;
-            tempColor.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View view) {
-                    associatedWatermark.setTextWatermarkColor(colors[tempI]);
-                }
-            });
+            tempColor.setOnClickListener(view -> associatedWatermark.setTextWatermarkColor(colors[tempI]));
+        }
+    }
+
+    private void initImageSelectBtn() {
+        imageSelectBtn.setOnClickListener(v -> {
+            //动态申请获取访问 读写磁盘的权限
+            if (ContextCompat.checkSelfPermission(getActivity(),
+                    Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+                ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 101);
+            } else {
+                //打开相册
+                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+                //Intent.ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT"
+                intent.setType("image/*");
+                startActivityForResult(intent, 102); // 打开相册
+            }
+        });
+    }
+
+    @Override
+    //TODO:Replace the deprecated method.
+    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+
+        if (resultCode == RESULT_OK) {
+            handleImageOnKitKat(data);
         }
     }
 
+    private void handleImageOnKitKat(Intent data) {
+        String imagePath = null;
+        Uri uri = data.getData();
+        if (DocumentsContract.isDocumentUri(getActivity(), uri)) {
+            String docId = DocumentsContract.getDocumentId(uri);
+            if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
+                String id = docId.split(":")[1];
+                String selection = MediaStore.Images.Media._ID + "=" + id;
+                imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
+            } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
+                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content: //downloads/public_downloads"), Long.valueOf(docId));
+                imagePath = getImagePath(contentUri, null);
+            }
+        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
+            imagePath = getImagePath(uri, null);
+        } else if ("file".equalsIgnoreCase(uri.getScheme())) {
+            imagePath = uri.getPath();
+        }
+        imageSelectPathView.setText(imagePath);
+        ImageWatermarkView temp = (ImageWatermarkView) associatedWatermark;
+        temp.setWatermarkImageFromPath(imagePath);
+    }
+
+    @SuppressLint("Range")
+    private String getImagePath(Uri uri, String selection) {
+        String path = null;
+
+        Cursor cursor = getActivity().getContentResolver().query(uri, null, selection, null, null);
+        if (cursor != null) {
+            if (cursor.moveToFirst()) {
+                path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
+            }
+            cursor.close();
+        }
+        return path;
+    }
+
     private void initOpacitySlider() {
         opacitySlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
             @SuppressLint("SetTextI18n")
@@ -141,7 +230,6 @@ public class WatermarkConsoleFragment extends Fragment {
 
     private void initSizeSlider() {
         sizeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
-            //TODO: The text's size and opacity should be independent.
             @SuppressLint("SetTextI18n")
             @Override
             public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
@@ -162,12 +250,58 @@ public class WatermarkConsoleFragment extends Fragment {
         });
     }
 
-    private void initRangeSpinner() {
-        String[] mItems = { "All Pages", "Odd Pages", "Even Pages", "Custom Range" };
-        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_dropdown_item, mItems);
-        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        rangeSpinner.setAdapter(adapter);
+    private void initRangeButton() {
+        rangeButton.setOnClickListener(view -> {
+            LayoutInflater inflater = LayoutInflater.from(getActivity());
+            final ConstraintLayout rangeSelectLayout = (ConstraintLayout) inflater.inflate(R.layout.range_selector, null);
+            final Button[] positiveButton = new Button[1];
+
+            AppCompatRadioButton customRadioBtn = rangeSelectLayout.findViewById(R.id.custom_range);
+            customRadioBtn.setChecked(isCustomRange);
+
+            AppCompatEditText rangeEditText = rangeSelectLayout.findViewById(R.id.range_edit);
+            rangeEditText.setEnabled(isCustomRange);
+            if (isCustomRange)
+                rangeEditText.setText(pageRange);
+
+            AlertDialog.Builder inputDialog = new AlertDialog.Builder(getActivity());
+            inputDialog.setTitle("Text watermark").setView(rangeSelectLayout);
+            inputDialog.setPositiveButton("Done", (dialogInterface, i) -> {
+                if (customRadioBtn.isChecked()) {
+                    pageRange = Objects.requireNonNull(rangeEditText.getText()).toString();
+                    rangeMsg.setText(pageRange);
+                } else {
+                    //TODO: Repair the code to set All pages range
+                    rangeMsg.setText("All pages");
+                }
+                isCustomRange = customRadioBtn.isChecked();
+            });
+
+            inputDialog.setNegativeButton("Cancel", (dialogInterface, i) -> {});
 
+            customRadioBtn.setOnCheckedChangeListener((compoundButton, b) -> {
+                rangeEditText.setEnabled(b);
+                if (b && rangeEditText.getText().toString().equals(""))
+                    positiveButton[0].setEnabled(false);
+            });
+
+            rangeEditText.addTextChangedListener(new TextWatcher() {
+                @Override
+                public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
+
+                @Override
+                public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
+
+                @Override
+                public void afterTextChanged(Editable editable) {
+                    positiveButton[0].setEnabled(!rangeEditText.getText().toString().equals(""));
+                }
+            });
+
+            AlertDialog dialog = inputDialog.create();
+            dialog.show();
+            positiveButton[0] = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
+        });
     }
 
     private void initFullScreenCheck() {
@@ -176,7 +310,6 @@ public class WatermarkConsoleFragment extends Fragment {
 
             opacitySlider.setEnabled(!isFullScreen);
             sizeSlider.setEnabled(!isFullScreen);
-            rangeSpinner.setEnabled(!isFullScreen);
 
             hSpaceEdit.setEnabled(isFullScreen);
             vSpaceEdit.setEnabled(isFullScreen);
@@ -197,9 +330,18 @@ public class WatermarkConsoleFragment extends Fragment {
     }
 
     public WatermarkSetting getWatermarkSetting() {
+        setting.setOpacity(opacitySlider.getProgress() * 1.0f / 100);
         setting.setFullScreen(fullScreenCheck.isChecked());
-        setting.setHorizontalSpacing(Float.parseFloat(Objects.requireNonNull(hSpaceEdit.getText()).toString()));
-        setting.setVerticalSpacing(Float.parseFloat(Objects.requireNonNull(vSpaceEdit.getText()).toString()));
+        setting.setPages(pageRange);
+        if (fullScreenCheck.isChecked()) {
+            setting.setHorizontalSpacing(Float.parseFloat(Objects.requireNonNull(hSpaceEdit.getText()).toString()));
+            setting.setVerticalSpacing(Float.parseFloat(Objects.requireNonNull(vSpaceEdit.getText()).toString()));
+        }
         return setting;
     }
+
+    public int getMode() {
+        return mode;
+    }
 }
+

+ 11 - 0
app/src/main/java/com/compdfkit/pdfviewer/tools/CoordinateMapper.java

@@ -0,0 +1,11 @@
+package com.compdfkit.pdfviewer.tools;
+
+public class CoordinateMapper {
+    public static float convertViewXtoPDFXOffset(float viewX, float xOffset, float centerX, float convertRate) {
+        return (viewX + xOffset - centerX) / convertRate;
+    }
+
+    public static float convertViewYtoPDFYOffset(float viewY, float yOffset, float centerY, float convertRate) {
+        return (centerY - (viewY + yOffset)) / convertRate;
+    }
+}

+ 5 - 0
app/src/main/res/drawable/ic_baseline_dark_expand_more_24.xml

@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#FFFFFF"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
+</vector>

+ 5 - 0
app/src/main/res/drawable/ic_baseline_expand_more_24.xml

@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#888888"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
+</vector>

+ 97 - 0
app/src/main/res/layout-land/activity_main.xml

@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity">
+
+    <androidx.appcompat.widget.Toolbar
+        android:id="@+id/toolbar"
+        android:layout_width="match_parent"
+        android:layout_height="30dp"
+        android:background="?attr/colorPrimary"
+        android:minHeight="?actionBarSize"
+        android:elevation="4dp"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:title="Add Watermark"
+        app:titleTextColor="@color/white" />
+
+    <com.google.android.material.tabs.TabLayout
+        android:id="@+id/tab_layout"
+        android:layout_width="match_parent"
+        android:layout_height="30dp"
+        android:elevation="4dp"
+        android:background="?attr/colorPrimary"
+        app:tabTextAppearance="@style/TabLayoutTextStyle"
+        app:tabIndicatorColor="@color/white"
+        app:tabSelectedTextColor="@color/white"
+        app:tabTextColor="@color/purple_200"
+        app:layout_constraintTop_toBottomOf="@+id/toolbar"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent">
+
+        <com.google.android.material.tabs.TabItem
+            android:id="@+id/text_item"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/text"
+            tools:layout_editor_absoluteX="164dp"
+            tools:layout_editor_absoluteY="52dp" />
+
+        <com.google.android.material.tabs.TabItem
+            android:id="@+id/image_item"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/image"
+            tools:layout_editor_absoluteX="164dp"
+            tools:layout_editor_absoluteY="52dp" />
+
+    </com.google.android.material.tabs.TabLayout>
+
+    <ImageView
+        android:id="@+id/page_image"
+        android:layout_width="wrap_content"
+        android:layout_height="0dp"
+        app:layout_constraintTop_toBottomOf="@id/tab_layout"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/console_view"
+        android:contentDescription="@string/page_image" />
+
+    <com.compdfkit.pdfviewer.customview.TextWatermarkView
+        android:id="@+id/watermark_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintTop_toTopOf="@id/page_image"
+        app:layout_constraintBottom_toBottomOf="@id/page_image"
+        app:layout_constraintEnd_toEndOf="@id/page_image"
+        app:layout_constraintStart_toStartOf="@id/page_image"
+        app:image_mode="false" />
+
+    <com.compdfkit.pdfviewer.customview.ImageWatermarkView
+        android:id="@+id/watermark_image"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:visibility="invisible"
+        app:layout_constraintTop_toTopOf="@id/page_image"
+        app:layout_constraintBottom_toBottomOf="@id/page_image"
+        app:layout_constraintEnd_toEndOf="@id/page_image"
+        app:layout_constraintStart_toStartOf="@id/page_image"
+        app:image_mode="false" />
+
+    <androidx.fragment.app.FragmentContainerView
+        android:name="com.compdfkit.pdfviewer.fragments.WatermarkConsoleFragment"
+        android:id="@+id/console_view"
+        android:layout_width="wrap_content"
+        android:layout_height="0dp"
+        android:elevation="4dp"
+        android:tag="console_fragment"
+        app:layout_constraintTop_toBottomOf="@id/tab_layout"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        tools:layout="@layout/fragment_watermark_console" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 350 - 0
app/src/main/res/layout-land/fragment_watermark_console.xml

@@ -0,0 +1,350 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="350dp"
+    android:layout_height="match_parent"
+    android:background="@color/white"
+    android:padding="10dp"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    tools:context=".fragments.WatermarkConsoleFragment">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/picker"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toTopOf="@+id/opacity_icon"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent" >
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/color_picker"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:visibility="visible"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent" >
+
+            <ImageView
+                android:id="@+id/color_selected"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:contentDescription="@string/opacity_icon"
+                android:src="@drawable/circle"
+                app:layout_constraintHorizontal_chainStyle="spread_inside"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/color_1"
+                app:layout_constraintStart_toStartOf="parent" />
+
+            <ImageView
+                android:id="@+id/color_1"
+                android:layout_width="35dp"
+                android:layout_height="35dp"
+                android:contentDescription="@string/opacity_icon"
+                android:src="@drawable/ic_baseline_circle1_24"
+                app:layout_constraintHorizontal_chainStyle="spread_inside"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/color_2"
+                app:layout_constraintStart_toEndOf="@id/color_selected" />
+
+            <ImageView
+                android:id="@+id/color_2"
+                android:layout_width="35dp"
+                android:layout_height="35dp"
+                android:contentDescription="@string/opacity_icon"
+                android:src="@drawable/ic_baseline_circle2_24"
+                app:layout_constraintHorizontal_chainStyle="spread_inside"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/color_3"
+                app:layout_constraintStart_toEndOf="@id/color_1" />
+
+            <ImageView
+                android:id="@+id/color_3"
+                android:layout_width="35dp"
+                android:layout_height="35dp"
+                android:contentDescription="@string/opacity_icon"
+                android:src="@drawable/ic_baseline_circle3_24"
+                app:layout_constraintHorizontal_chainStyle="spread_inside"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/color_4"
+                app:layout_constraintStart_toEndOf="@id/color_2" />
+
+            <ImageView
+                android:id="@+id/color_4"
+                android:layout_width="35dp"
+                android:layout_height="35dp"
+                android:contentDescription="@string/opacity_icon"
+                android:src="@drawable/ic_baseline_circle4_24"
+                app:layout_constraintHorizontal_chainStyle="spread_inside"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/color_5"
+                app:layout_constraintStart_toEndOf="@id/color_3" />
+
+            <ImageView
+                android:id="@+id/color_5"
+                android:layout_width="35dp"
+                android:layout_height="35dp"
+                android:contentDescription="@string/opacity_icon"
+                android:src="@drawable/ic_baseline_circle5_24"
+                app:layout_constraintHorizontal_chainStyle="spread_inside"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/color_6"
+                app:layout_constraintStart_toEndOf="@id/color_4" />
+
+            <ImageView
+                android:id="@+id/color_6"
+                android:layout_width="35dp"
+                android:layout_height="35dp"
+                android:contentDescription="@string/opacity_icon"
+                android:src="@drawable/ic_baseline_circle6_24"
+                app:layout_constraintHorizontal_chainStyle="spread_inside"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/color_7"
+                app:layout_constraintStart_toEndOf="@id/color_5" />
+
+            <ImageView
+                android:id="@+id/color_7"
+                android:layout_width="35dp"
+                android:layout_height="35dp"
+                android:contentDescription="@string/opacity_icon"
+                android:src="@drawable/ic_baseline_circle7_24"
+                app:layout_constraintHorizontal_chainStyle="spread_inside"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toEndOf="@id/color_6" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/image_picker"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:padding="5dp"
+            android:visibility="invisible"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent" >
+
+            <TextView
+                android:id="@+id/image_select_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/image"
+                android:textSize="20sp"
+                android:textColor="#3C4045"
+                android:padding="7dp"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent" />
+
+            <TextView
+                android:id="@+id/image_select_path"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:padding="3dp"
+                android:text="@string/default_image"
+                app:layout_constraintTop_toTopOf="@id/image_select_text"
+                app:layout_constraintBottom_toBottomOf="@id/image_select_text"
+                app:layout_constraintStart_toEndOf="@id/image_select_text"
+                app:layout_constraintEnd_toStartOf="@id/image_select_btn" />
+
+            <Button
+                android:id="@+id/image_select_btn"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Select"
+                android:textColor="@color/white"
+                android:backgroundTint="@color/purple_500"
+                app:layout_constraintTop_toTopOf="@+id/image_select_text"
+                app:layout_constraintBottom_toBottomOf="@id/image_select_text"
+                app:layout_constraintEnd_toEndOf="parent"
+                tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <ImageView
+        android:id="@+id/opacity_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:contentDescription="@string/opacity_icon"
+        android:src="@drawable/ic_baseline_opacity_20"
+        android:padding="10dp"
+        app:layout_constraintHorizontal_chainStyle="spread_inside"
+        app:layout_constraintEnd_toStartOf="@+id/opacity_slider"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/picker"
+        app:layout_constraintBottom_toTopOf="@+id/size_icon"/>
+
+    <androidx.appcompat.widget.AppCompatSeekBar
+        android:id="@+id/opacity_slider"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:progress="50"
+        android:theme="@style/SeekBarColor"
+        app:layout_constraintTop_toTopOf="@id/opacity_icon"
+        app:layout_constraintBottom_toBottomOf="@id/opacity_icon"
+        app:layout_constraintStart_toEndOf="@+id/opacity_icon"
+        app:layout_constraintEnd_toStartOf="@id/opacity_text"/>
+
+    <TextView
+        android:id="@+id/opacity_text"
+        android:layout_width="40dp"
+        android:layout_height="wrap_content"
+        android:text="@string/default_opacity"
+        app:layout_constraintTop_toTopOf="@id/opacity_icon"
+        app:layout_constraintBottom_toBottomOf="@id/opacity_icon"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/opacity_slider" />
+
+
+    <ImageView
+        android:id="@+id/size_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:contentDescription="@string/opacity_icon"
+        android:src="@drawable/ic_baseline_format_size_20"
+        android:padding="10dp"
+        app:layout_constraintHorizontal_chainStyle="spread_inside"
+        app:layout_constraintEnd_toStartOf="@+id/size_slider"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/opacity_icon"
+        app:layout_constraintBottom_toTopOf="@+id/page_range_text"/>
+
+    <androidx.appcompat.widget.AppCompatSeekBar
+        android:id="@+id/size_slider"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:progress="50"
+        android:theme="@style/SeekBarColor"
+        app:layout_constraintTop_toTopOf="@id/size_icon"
+        app:layout_constraintBottom_toBottomOf="@id/size_icon"
+        app:layout_constraintStart_toEndOf="@+id/size_icon"
+        app:layout_constraintEnd_toStartOf="@id/size_text"/>
+
+    <TextView
+        android:id="@+id/size_text"
+        android:layout_width="40dp"
+        android:layout_height="wrap_content"
+        android:text="@string/default_scale"
+        app:layout_constraintTop_toTopOf="@id/size_icon"
+        app:layout_constraintBottom_toBottomOf="@id/size_icon"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/size_slider" />
+
+
+    <TextView
+        android:id="@+id/page_range_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/page_range"
+        android:textSize="20sp"
+        android:textColor="#3C4045"
+        android:padding="12dp"
+        app:layout_constraintTop_toBottomOf="@+id/size_icon"
+        app:layout_constraintBottom_toTopOf="@id/full_screen_checkbox"
+        app:layout_constraintStart_toStartOf="parent" />
+
+<!--    <androidx.appcompat.widget.AppCompatSpinner-->
+<!--        android:id="@+id/page_range_spinner"-->
+<!--        android:layout_width="wrap_content"-->
+<!--        android:layout_height="wrap_content"-->
+<!--        android:spinnerMode="dialog"-->
+<!--        app:layout_constraintBottom_toBottomOf="@id/page_range_text"-->
+<!--        app:layout_constraintEnd_toEndOf="parent"-->
+<!--        app:layout_constraintTop_toTopOf="@id/page_range_text"-->
+<!--        tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />-->
+
+    <ImageButton
+        android:id="@+id/page_range_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="?attr/actionModeCopyDrawable"
+        app:layout_constraintBottom_toBottomOf="@id/page_range_text"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="@id/page_range_text"/>
+
+
+    <CheckBox
+        android:id="@+id/full_screen_checkbox"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="10dp"
+        android:text="@string/full_screen"
+        app:layout_constraintHorizontal_chainStyle="spread_inside"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/page_range_text"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/full_screen_space"
+        tools:ignore="TouchTargetSizeCheck" />
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/full_screen_space"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintTop_toTopOf="@id/full_screen_checkbox"
+        app:layout_constraintBottom_toBottomOf="@id/full_screen_checkbox"
+        app:layout_constraintStart_toEndOf="@id/full_screen_checkbox"
+        app:layout_constraintEnd_toEndOf="parent">
+
+        <com.google.android.material.textfield.TextInputEditText
+            android:id="@+id/horizontal_space"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:hint="@string/default_space"
+            android:text="@string/default_space"
+            android:enabled="false"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@id/horizontal_space_mm"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:ignore="TouchTargetSizeCheck,DuplicateSpeakableTextCheck" />
+
+        <TextView
+            android:id="@+id/horizontal_space_mm"
+            android:layout_width="40dp"
+            android:layout_height="wrap_content"
+            android:text="@string/mm"
+            app:layout_constraintTop_toTopOf="@id/horizontal_space"
+            app:layout_constraintBottom_toBottomOf="@id/horizontal_space"
+            app:layout_constraintStart_toEndOf="@+id/horizontal_space"
+            app:layout_constraintEnd_toStartOf="@id/vertical_space"/>
+
+        <com.google.android.material.textfield.TextInputEditText
+            android:id="@+id/vertical_space"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:hint="@string/default_space"
+            android:text="@string/default_space"
+            android:enabled="false"
+            app:layout_constraintBottom_toBottomOf="@id/horizontal_space"
+            app:layout_constraintEnd_toStartOf="@id/vertical_space_mm"
+            app:layout_constraintStart_toEndOf="@id/horizontal_space_mm"
+            app:layout_constraintTop_toTopOf="@id/horizontal_space"
+            tools:ignore="TouchTargetSizeCheck" />
+
+        <TextView
+            android:id="@+id/vertical_space_mm"
+            android:layout_width="40dp"
+            android:layout_height="wrap_content"
+            android:text="@string/mm"
+            app:layout_constraintTop_toTopOf="@id/horizontal_space"
+            app:layout_constraintBottom_toBottomOf="@id/horizontal_space"
+            app:layout_constraintStart_toEndOf="@+id/vertical_space"
+            app:layout_constraintEnd_toEndOf="parent" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 18 - 5
app/src/main/res/layout/fragment_watermark_console.xml

@@ -257,15 +257,26 @@
         app:layout_constraintBottom_toTopOf="@id/full_screen_checkbox"
         app:layout_constraintStart_toStartOf="parent" />
 
-    <androidx.appcompat.widget.AppCompatSpinner
-        android:id="@+id/page_range_spinner"
+    <TextView
+        android:id="@+id/page_range_msg"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/all_pages"
+        android:textColor="@color/black"
+        app:layout_constraintTop_toTopOf="@id/page_range_text"
+        app:layout_constraintBottom_toBottomOf="@id/page_range_text"
+        app:layout_constraintEnd_toStartOf="@id/page_range_button" />
+
+    <ImageButton
+        android:padding="10dp"
+        android:id="@+id/page_range_button"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:spinnerMode="dropdown"
+        android:background="@color/white"
+        android:src="@drawable/ic_baseline_expand_more_24"
         app:layout_constraintBottom_toBottomOf="@id/page_range_text"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="@id/page_range_text"
-        tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
+        app:layout_constraintTop_toTopOf="@id/page_range_text"/>
 
 
     <CheckBox
@@ -295,6 +306,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:hint="@string/default_space"
+            android:text="@string/default_space"
             android:enabled="false"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toStartOf="@id/horizontal_space_mm"
@@ -317,6 +329,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:hint="@string/default_space"
+            android:text="@string/default_space"
             android:enabled="false"
             app:layout_constraintBottom_toBottomOf="@id/horizontal_space"
             app:layout_constraintEnd_toStartOf="@id/vertical_space_mm"

+ 40 - 0
app/src/main/res/layout/range_selector.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:padding="20dp"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <RadioGroup
+        android:id="@+id/select_group"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent">
+
+        <androidx.appcompat.widget.AppCompatRadioButton
+            android:id="@+id/all_pages"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="All pages"
+            android:checked="true"/>
+
+        <androidx.appcompat.widget.AppCompatRadioButton
+            android:id="@+id/custom_range"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Custom range" />
+
+    </RadioGroup>
+
+    <androidx.appcompat.widget.AppCompatEditText
+        android:id="@+id/range_edit"
+        android:layout_width="200dp"
+        android:layout_height="wrap_content"
+        android:hint="@string/range_hint"
+        app:layout_constraintTop_toBottomOf="@id/select_group"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        android:enabled="false"/>
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 18 - 0
app/src/main/res/layout/text_editor.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:padding="20dp"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <androidx.appcompat.widget.AppCompatEditText
+        android:id="@+id/text_editor"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:enabled="true"
+        android:hint="@string/watermark_context"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 1 - 0
app/src/main/res/layout/watermark_text_view.xml

@@ -25,6 +25,7 @@
             android:textSize="35sp"
             android:visibility="visible"
             android:alpha="0.5"
+            android:letterSpacing="0.012"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"

+ 1 - 0
app/src/main/res/menu/menu_done.xml

@@ -6,5 +6,6 @@
         android:id="@+id/done"
         android:icon="@drawable/ic_baseline_done_24"
         android:title="@string/done"
+        android:onClick="finishEditWatermark"
         app:showAsAction="always"/>
 </menu>

+ 3 - 0
app/src/main/res/values/strings.xml

@@ -17,4 +17,7 @@
     <string name="default_image">Default image</string>
     <string name="done">Done</string>
     <string name="page_image">Page Image</string>
+    <string name="range_hint">Such as: 1,3-5,10</string>
+    <string name="watermark_context">Watermark context</string>
+    <string name="all_pages">All pages</string>
 </resources>