Search code examples
matriximageviewpositionreset

How to reset imageview to original/clean state after PAN and Zoom before setting new bitmap


I have tried many of the similar questions offered by the Stackoverflow system but they are for other escenarios. I do not use canvas, and I use Matrix to Zoom and PAN but in combination with scrollBy and imageview.scaleX, imageview.scaleY.

The problem is that I want to replace the Bitmap in the ImageView but when replaced it takes the same position and zoom states of the previous Bitmap.

I tried doing ScrollTo(0,0) to reset the position. Tried translateX(0), translateY(0). Tried setX(0), setY(0)

Tried to do setImageMatrix(originalM) where originalM is the imageview.imageMatrix at Create. Tried imageview.imageMatrix = Matrix()

Tried to imageview.setScaleType(ImageView.ScaleType.CENTER_CROP) then imageview.setScaleType(ImageView.ScaleType.MATRIX)

To benefit the readers this is part of my code. You will notice I translate and scale the Matrix behind the scene but do not invalidate() the imageview. I want the user to see the changes in the view but not the Matrix. I am trying to make the zoom and pan of the matrix in PX (this part does not work correctly but is outside the scope of this Question. The use use of this Matrix is probably part of the problem but I can't remove it as is use for another function in the code and for other Topic/Question)

Layout:

<FrameLayout
    android:id="@+id/frame"
    android:layout_width="350dp"
    android:layout_height="500dp"
    android:layout_marginStart="30dp"
    android:layout_marginTop="2dp"
    android:layout_marginEnd="30dp"
    android:background="@drawable/image_border"
    android:visibility="visible"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/button_layout">

    
    <ImageView
        android:id="@+id/pdfview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="@string/pdf"
        android:cropToPadding="true"
        android:scaleType="matrix"
        app:layout_constraintDimensionRatio="1:1"
        app:srcCompat="@color/material_dynamic_neutral80" />

    <!--android:scaleType="centerCrop"-->


</FrameLayout>

Zoom:

slider.addOnChangeListener { slider, value, fromUser ->
        // Responds to when slider's value is changed
        tv = "Zoom Value:\n${value.format(2)}%"
        zoom.text = tv
        m = pdfview.imageMatrix
        scaleX = 1 + value / 100
        scaleY = 1 + value / 100

        // Responds to when slider's value is changed
        pdfview.scaleX = scaleX
        pdfview.scaleY = scaleY
        scrollX = pdfview.scrollX
        scrollY = pdfview.scrollY
        m.setScale(scaleX, scaleY, centerX, centerY)
        m.postTranslate(
            -(scrollX).toInt().toFloat().px,
            -(scrollY).toInt().toFloat().px
        )
    }

Extension function

private val Float.px: Float get() = (this * getSystem().displayMetrics.density)

PAN:

     pdfview.setOnTouchListener { v, event ->

        val currentX: Float
        val currentY: Float
        
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                preX = event.x
                preY = event.y
            }

            MotionEvent.ACTION_MOVE -> {
                currentX = event.x
                currentY = event.y
                
                    pdfview.scrollBy((preX - currentX).toInt(), (preY - currentY).toInt())
                    m.postTranslate( 
                        -(preX - currentX).toInt().toFloat().px,
                        -(preY - currentY).toInt().toFloat().px
                    )
                    preX = currentX
                    preY = currentY
                
            }

            MotionEvent.ACTION_UP -> {
                currentX = event.x
                currentY = event.y
                    pdfview.scrollBy((preX - currentX).toInt(), (preY - currentY).toInt())
                    m.postTranslate(
                        -(preX - currentX).toInt().toFloat().px,
                        -(preY - currentY).toInt().toFloat().px
                    )
                
            }
        }
        true
    }

Imageview Bitmap:

 @Throws(IOException::class)
private fun openPdfFromStorage(uri: Uri) {
    var FILE_NAME = getFileName(uri)//"temp${Date()}.pdf"
    if (FILE_NAME == null) FILE_NAME = "temp${Date()}.pdf"
    val fileCopy = File(cacheDir, FILE_NAME) //anything as the name
    copyToCache(fileCopy, uri) /////////// Function not shown. Reads full file from Uri and place it in memory
    // Get a page from the PDF doc by calling 'open'
    val fileDescriptor = ParcelFileDescriptor.open(
        fileCopy,
        ParcelFileDescriptor.MODE_READ_ONLY
    )
    mPdfRenderer = PdfRenderer(fileDescriptor)
    pdfpages = mPdfRenderer.pageCount
    pdfnum = 0

    val mPdfPage = mPdfRenderer.openPage(pdfnum)

    val bitmap = Bitmap.createBitmap(
        pdfview.width, //bmWidth,
        pdfview.height, //bmHeight,
        Bitmap.Config.ARGB_8888
    ) //Not RGB, but ARGB
    mPdfPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)

    pdfview.setImageBitmap(bitmap)
    ///////////
    // WHEN THIS IS EXECUTED OVER A PREVIOUSLY USED IMAGEVIEW THE BITMAP IS SHOWN WITH THE SAME POSITION AND SCALE OF THE PREVIOUS BITMAP
    ///////////
    pdfview.setScaleType(ImageView.ScaleType.CENTER_CROP)
    pdfview.setScaleType(ImageView.ScaleType.MATRIX)
    m = pdfview.imageMatrix
    mPdfPage.close()
    pbounds = getImageBounds(pdfview) //imageView.imageMatrix.mapRect(bounds, RectF(drawable.bounds))
    centerX = pbounds.centerX()
    centerY = pbounds.centerY()
    
}

Solution

  • Once I found how to use the Matrix movement mechanism correctly it was simple:

    Before replacing the Image move the current Image to the origin. Following code will PAN the Image back to the origin.

            val sX = scrollX //current X coord.
            val sY = scrollY //current Y coord. 
            val pX = pscrollX //previous X coord.
            val pY = pscrollY //previous Y coord.
    
            m.postTranslate(-(pX - sX), -(pY - sY)) 
            pdfview.imageMatrix = m
            val f = FloatArray(9)
            m.getValues(f)
            pscrollX = f[Matrix.MTRANS_X]
            pscrollY = f[Matrix.MTRANS_Y]
    

    Then to replace the Image just:

    pdfview.imageMatrix = Matrix()
    pdfview.scaleType = ImageView.ScaleType.MATRIX
    pdfview.setImageBitmap(bitmap)