【问题标题】:Android, Attaching e-signature on pdf using drag and dropAndroid,使用拖放在pdf上附加电子签名
【发布时间】:2020-05-18 14:40:54
【问题描述】:

我正在开发一个 Android 应用程序,我需要实现将用户签名(图像)放置在用户拖动的 pdf 上。我正在使用 pdf 查看器(com.github.barteksc.pdfviewer.PDFView)来显示 pdf,并且我正在使用拖放侦听器从视图中获取坐标。但它没有放在pdf上的正确位置。我花了很多时间在其他解决方案上,但没有任何帮助。 (或者请推荐任何 Android 中可用的免费 SDK 来实现同样的目的。)

请帮我解决这个问题。这是我的代码示例。

public class MainActivity extends AppCompatActivity implements View.OnTouchListener, View.OnDragListener, OnPageChangeListener, OnPageScrollListener {
private PDFView pdfViewDemo;
private Button buttonGetPage;
private ImageView imageViewDemo;
private ImageView imageDrag;

private String pdfUrl = "/sdcard/sample.pdf";

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_pdf_view);
    findViewById(R.id.rootView).setOnDragListener(this);
    pdfViewDemo = findViewById(R.id.pdfView);
    final File file = new File(pdfUrl);
    pdfViewDemo.setMaxZoom(0);
    pdfViewDemo.fromFile(file)
            .onPageChange(this)
            .onPageScroll(this)
            .spacing(10)
            .swipeHorizontal(true)
            .enableDoubletap(false)
            .load();

    //Implementation of Drag and Drop---------------------------------------------
    imageDrag = findViewById(R.id.imageDrag);
    imageDrag.setOnTouchListener(this);
    //Implementation of Drag and Drop---------------------------------------------

    imageViewDemo = findViewById(R.id.imageDemo);

    buttonGetPage = findViewById(R.id.buttonGetPage);
    buttonGetPage.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ArrayList<Bitmap> bitmaps = pdfToBitmap(file);
            pdfViewDemo.setVisibility(View.GONE);
            imageViewDemo.setVisibility(View.VISIBLE);
            imageViewDemo.setImageBitmap(bitmaps.get(0));
            Log.e("test", "Bitmaps: " + bitmaps.size());
        }
    });


}

private ArrayList<Bitmap> pdfToBitmap(File pdfFile) {
    ArrayList<Bitmap> bitmaps = new ArrayList<>();

    try {
        PdfRenderer renderer = new PdfRenderer(ParcelFileDescriptor.open(pdfFile, ParcelFileDescriptor.MODE_READ_ONLY));

        Bitmap bitmap;
        final int pageCount = renderer.getPageCount();
        for (int i = 0; i < pageCount; i++) {
            PdfRenderer.Page page = renderer.openPage(i);

            int width = getResources().getDisplayMetrics().densityDpi / 72 * page.getWidth();
            int height = getResources().getDisplayMetrics().densityDpi / 72 * page.getHeight();
            bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

            page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);

            bitmaps.add(bitmap);

            // close the page
            page.close();

        }

        // close the renderer
        renderer.close();
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    return bitmaps;

}

@Override
public void onPageChanged(int page, int pageCount) {
    Log.e("test", "onPageChanged() called with: page = [" + page + "], pageCount = [" + pageCount + "]");
}

@Override
public void onPointerCaptureChanged(boolean hasCapture) {
    Log.e("test", "onPointerCaptureChanged() called with: hasCapture = [" + hasCapture + "]");
}

@Override
public void onPageScrolled(int page, float positionOffset) {
    Log.e("test", "onPageScrolled() called with: page = [" + page + "], positionOffset = [" + positionOffset + "]");
}

@Override
public boolean onTouch(View view, MotionEvent event) {
    Log.e("test", "onTouch() called with: v = [" + view + "], event = [" + event + "]");
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
        view.startDrag(null, shadowBuilder, view, 0);
        return true;
    } else {
        return false;
    }
}

@Override
public boolean onDrag(View v, DragEvent event) {
    int action = event.getAction();
    switch (action) {
        case DragEvent.ACTION_DRAG_STARTED:
            Log.e("test", "onDrag: ACTION_DRAG_STARTED");
            break;
        case DragEvent.ACTION_DRAG_ENTERED:
            Log.e("test", "onDrag: ACTION_DRAG_ENTERED");
            break;
        case DragEvent.ACTION_DRAG_EXITED:
            Log.e("test", "onDrag: ACTION_DRAG_EXITED");
            break;
        case DragEvent.ACTION_DROP:
            Log.e("test", "onDrag: ACTION_DROP");
            Log.e("test-", "X: " + (int) event.getX());
            Log.e("test-", "Y: " + (int) event.getY());
            getPdfCoordinates((int) event.getX(), (int) event.getY());
            /*View tvState = (View) event.getLocalState();
            val tvParent = tvState.parent as ViewGroup
            tvParent.removeView(tvState)
            val container = view as LinearLayout
            container.addView(tvState)
            tvParent.removeView(tvState)
            tvState.x = dragEvent.x
            tvState.y = dragEvent.y
            view.addView(tvState)
            view.setVisibility(View.VISIBLE)
            int x = (int) v.getX();
            int y = (int) v.getY();
            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(x, y);
            textTitle.setLayoutParams(layoutParams);*/
            break;
        case DragEvent.ACTION_DRAG_ENDED:
            Log.e("test", "onDrag: ACTION_DRAG_ENDED" + v.getX() + ":" + v.getY());
            imageDrag.setVisibility(View.VISIBLE);
            break;
        default:
            break;
    }
    return true;
}

private void getPdfCoordinates(int x, int y) {
    Log.e("test-", "PDF: getMeasuredWidth: " + pdfViewDemo.getMeasuredWidth());
    Log.e("test-", "PDF: getWidth: " + pdfViewDemo.getWidth());
    Log.e("test-", "PDF: getOptimalPageHeight: " + pdfViewDemo.getOptimalPageHeight());
    Log.e("test-", "PDF: getOptimalPageWidth: " + pdfViewDemo.getOptimalPageWidth());
    Log.e("test-", "PDF: getMeasuredWidthAndState: " + pdfViewDemo.getMeasuredWidthAndState());

    Log.e("test-", "PDF: getMinimumHeight: " + pdfViewDemo.getMinimumHeight());
    Log.e("test-", "PDF: getMinimumWidth: " + pdfViewDemo.getMinimumWidth());

    x= (int) pdfViewDemo.getOptimalPageHeight()/2-x;
    y=(int)pdfViewDemo.getOptimalPageWidth()/2-y;
    addImageToPdf(x, y);
}

private void addImageToPdf(int x, int y) {
    Log.e("test", "addImageToPdf() called with: x = [" + x + "], y = [" + y + "]" + pdfViewDemo.getCurrentPage());
    try {
        PdfReader reader = new PdfReader(pdfUrl);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("/sdcard/test_pdf.pdf"));
        PdfContentByte content = stamper.getOverContent(pdfViewDemo.getCurrentPage()+1);

        com.itextpdf.text.Image image = Image.getInstance("/sdcard/sign_1.jpg");


        image.scaleAbsoluteHeight(50);
        image.scaleAbsoluteWidth((image.getWidth() * 50) / image.getHeight());

        image.setAbsolutePosition(y, x);

        content.addImage(image);

        stamper.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

这里是输入输出的截图

【问题讨论】:

  • “但它没有放在 pdf 上的正确位置” - 它放在哪里?你有没有尝试在其中找到一种模式?只是在一个恒定的偏移量?还是镜像?还是x和y交换了? (作为第一印象:我看到您正在切换 x 和 y,这是设计使然吗?并且您从某个宽度/高度中减去两个坐标,通常只需减去一个。)
  • 感谢mkl的回复,我会添加截图,让你有更多的想法。
  • 我看到签名是您最可能不希望它出现的位置,但它打算去哪里?如果你改变了预期的位置,最终的位置会如何移动?平行、同向还是相反?在一个角度?
  • 根据我对此链接的观察pspdfkit.com/guides/android/current/faq/coordinate-spaces 视图坐标和 pdf 坐标不同,因为我手动做了一些数学运算,我发现了这个。如果我错了,请告诉我。
  • 我没有使用过 PDFView 组件的经验。但是,考虑到类似情况,它的坐标系原点似乎在左上角。另一方面,PDF 随处可见,通常在左下角。因此,我理解您为什么要通过减去宽度或高度来反转 一个 坐标,但为什么两者都?此外,您可以切换坐标 (setAbsolutePosition(y, x))。可能是因为页面旋转?但你不为此测试。那么,为什么?

标签: android pdf itext pdf-generation electronic-signature


【解决方案1】:

根据this answer,给定页面的坐标可以是任何东西,并且必须使用 PdfReader 进行检查。

可能还有一些其他因素会影响定位。

  • PDF 坐标系的缩放比例可能与机器人不同。
  • PdfStamper 可能会以一种意想不到的方式放置图章(我找不到足够的文档),因此需要进行一些测试来找出给定坐标下图章的确切放置位置。
  • 您在拖放时截获的触摸事件的坐标是绝对的,但应该是相对于 PdfView 的位置。这可以通过获取 PdfView 的绝对位置并从 TouchEvent 坐标中减去它来实现。

一些想法可以帮助您进行调试。

【讨论】:

    猜你喜欢
    • 2020-02-25
    • 1970-01-01
    • 2010-12-09
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    • 2019-12-14
    • 2016-06-16
    • 1970-01-01
    相关资源
    最近更新 更多