How a Custom Android Image Editor Boosts Warehouse Efficiency
This article details the design and implementation of a native Android image‑editing component built for warehouse quality‑inspection, covering business motivations, core features such as multi‑image batch editing, matrix‑based transformations, a command‑pattern undo/redo system, technical architecture, key challenges, and future extension plans.
Project Overview
The warehouse inspection workflow requires frequent photo capture, annotation, and data entry, which traditionally involves many UI switches and adds operational cost. A dedicated image‑editing module was created to streamline this process, improve image quality, and support multiple scenarios.
Business Value
Improved Efficiency : Optimised upload flow and UI layout match frontline operators' habits, speeding up image capture and data entry.
Higher Image Quality : Provides professional editing tools (annotation, rotation) to ensure consistent, standards‑compliant images.
Simplified Workflow : Reduces steps, accelerates shooting and uploading.
Multi‑Scenario Support : A unified solution that can be extended to various business contexts.
In the quality‑inspection scenario, operators handle large volumes of product images daily. Traditional processes suffer from long interaction paths, difficulty with batch operations, and low precision. The goal is a fast, accurate, and easy‑to‑use editor that supports annotation, multi‑image state management, and seamless switching.
Core Feature Points
Image annotation with rectangular boxes for marking defects or details.
Batch editing of multiple images.
Image rotation while preserving annotation positions.
Undo/redo history management.
Border‑color switching to differentiate annotation types.
Intuitive UI tailored to frontline staff.
Technical Architecture Overview
UI Layer : Activities and adapters that display the editor.
Editing Core Layer : Business logic centred on
ImageEditorView.
Data Processing Layer : Loading, saving, and managing image data and state.
Tool Service Layer : Permissions, file storage, and other foundational services.
Technology Selection
Existing open‑source libraries (Android‑Image‑Cropper, PhotoEditor) were evaluated but could not meet the specific needs (multiple boxes, rotation‑aware annotations, batch processing). A fully custom solution using Android native Canvas, Matrix, and Kotlin was chosen.
The comparison table shows the gaps of the open‑source options versus the custom implementation.
Feature
Android‑Image‑Cropper
PhotoEditor
Custom Solution
Box Annotation
❌ Only crop box, cannot keep multiple boxes
❌ Only doodle, no rectangular box
✅ Supports multiple simultaneous boxes
Rotation‑Preserved Boxes
❌ Rotation supported but boxes do not follow
❌ No rotation support
✅ Boxes stay aligned after rotation
Batch Processing
❌ Single‑image only
❌ Single‑image only
✅ Full multi‑image editing and state saving
Undo/Redo
❌ Not supported
✅ Supported
✅ Implemented via command pattern
Border Color Switch
❌ Fixed colour
✅ Supported
✅ Red/Yellow colour toggle
Because open‑source solutions cannot satisfy the specialised workflow, a native Android implementation using Canvas and Matrix was adopted despite higher development cost, delivering precise customisation and better performance.
Overall Design
Core Architecture
The editor is built on a pure Android stack. A custom
Viewhandles flexible editing interactions, Matrix performs image transformations, and the command pattern manages edit history.
Implementation Flow Diagram
Core Technical Components
Image Rendering & Transformation System
Matrix Transformation Principle : 3×3 matrix for translation, scaling, rotation.
Coordinate Mapping : Provides bidirectional mapping between screen and image coordinates.
Animation : ObjectAnimator creates smooth rotation animations.
Fit Algorithm : Calculates optimal scale to fully display the image.
Rotation is handled by first rotating the bitmap, then mapping annotation coordinates using the inverse matrix to keep boxes aligned.
Touch Event Handling System
Event Dispatch : onTouchEvent processes all touch types.
Multi‑Stage Decision : Distinguishes click, long‑press, and drag.
Coordinate Conversion : Maps touch points from screen space to image space.
Target Detection : Determines whether a touch hits an existing box or starts a new one.
Boundary Constraints : Prevents operations from exceeding image bounds.
Multi‑Touch Filtering : Ignores extra fingers to avoid accidental actions.
A state machine records the initial touch point, current state, and movement threshold to differentiate clicks from drags. After a drag, the system updates the box position using the inverse matrix.
Command Pattern for Edit History
Each edit operation (create, move, delete) implements an
Operationinterface with
undo()and
redo(). A linear history list with a current index enables unlimited undo/redo and branch discarding when new actions are added.
interface Operation {
fun undo()
fun redo()
}
class CreateOperation(private val box: SelectionBox, private val boxes: MutableList<SelectionBox>) : Operation {
override fun redo() { if (!boxes.contains(box)) boxes.add(box) }
override fun undo() { boxes.remove(box) }
}
class MoveOperation(private val box: SelectionBox, private val oldRect: RectF, private val newRect: RectF) : Operation {
override fun redo() { box.rect.set(newRect) }
override fun undo() { box.rect.set(oldRect) }
}
class DeleteOperation(private val box: SelectionBox, private val boxes: MutableList<SelectionBox>) : Operation {
override fun redo() { boxes.remove(box) }
override fun undo() { if (!boxes.contains(box)) boxes.add(box) }
}State Management System
Each image’s edit state is stored in an
ImageStatedata class containing the list of boxes, rotation angle, matrix, and border colour. When the user switches images, the current state is saved and the target state is restored, enabling seamless multi‑image editing.
fun setImageWithPath(bitmap: Bitmap, imagePath: String) {
// Save current state
currentImagePath?.let { path ->
imageSelectionStates[path] = ImageState(
selectionBoxes = selectionBoxes.toList(),
rotation = currentRotation,
matrix = Matrix(imageMatrix),
borderColor = currentBorderColor
)
}
// Load new image and restore its state
imageBitmap = bitmap
currentImagePath = imagePath
val state = imageSelectionStates[imagePath]
if (state != null) {
selectionBoxes.clear()
selectionBoxes.addAll(state.selectionBoxes)
currentRotation = state.rotation
imageMatrix = Matrix(state.matrix)
currentBorderColor = state.borderColor
} else {
// initialise fresh state
}
}Multi‑Image Editing & Management
ViewPager2 hosts the editor pages, but user swiping is disabled to avoid gesture conflicts. A horizontal RecyclerView of thumbnails provides navigation, with each thumbnail indicating whether the image has been edited.
private fun initViews() {
viewPager = findViewById(R.id.media_picker_image_pager)
viewPager.adapter = imagePagerAdapter
viewPager.isUserInputEnabled = false
viewPager.offscreenPageLimit = selectedImages?.size ?: 10
recyclerView = findViewById<RecyclerView>(R.id.media_picker_image_list)
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
recyclerView.adapter = imageListAdapter
imageListAdapter.setOnImageSelectedListener { position ->
viewPager.currentItem = position
}
}Key Technical Challenges
Gesture Conflict Resolution
Disabled ViewPager2 swipe and replaced it with thumbnail navigation.
Implemented multi‑touch filtering to ignore extra fingers.
Adjusted event interception based on interaction mode (edit vs. select).
Used a clear
isEditModeflag to separate box‑selection and editing states.
Coordinate System Conversion
Managed both view‑space and image‑space coordinates.
Applied Matrix and its inverse for precise mapping.
Handled rotation‑induced width/height swaps and ensured coordinates stay within bounds.
Rotation Synchronisation
Applied the same transformation matrix to both the bitmap and annotation boxes.
Rotated around the image centre using
postRotate(currentRotation, viewWidth/2, viewHeight/2).
Coordinated animation updates so boxes move smoothly with the image.
Future Feature Planning
Additional Editing Tools : Text labels, arrow annotations, free‑hand drawing, measurement utilities.
Enhanced Image Processing : More filters, brightness/contrast adjustment, cropping.
Intelligent Assistance : AI‑based defect detection, auto‑suggested annotation regions, batch‑processing recommendations.
Collaboration & Sharing : Cloud‑sync of edit history, multi‑user editing, comments on specific regions.
Project Summary
The custom Android image editor addresses the unique needs of warehouse quality‑inspection by providing fast, precise annotation, multi‑image batch handling, and a robust undo/redo system built on matrix transformations and the command pattern. The solution has markedly improved operational efficiency and offers a solid foundation for future AI‑assisted features.
References & Open‑Source Libraries
Core Technical References
Android Canvas and drawing fundamentals.
Affine transformation mathematics (3×3 matrix).
Touch event dispatching and multi‑touch handling.
GestureDetector custom implementations.
Key Literature
Official Android documentation (Canvas, Matrix, Touch Events).
"Android Custom View Development" – practical guide for custom UI components.
"Android High‑Performance Programming" – performance tuning and memory management.
Development Tools & Libraries
Android Profiler for CPU and memory analysis.
AndroidX Core‑KTX for Kotlin extensions.
AndroidX ConstraintLayout for flexible UI layouts.
These resources helped ensure the editor meets high‑quality standards and performs smoothly across devices.
Want to learn more about ZhiZhuan’s business practices? Follow the public account below!
大转转FE
Regularly sharing the team's thoughts and insights on frontend development
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.