Building a Full-Featured Image Editor for HarmonyOS: 2025 Developer Competition Insights & Technical Guide
A HarmonyOS developer shares complete technical implementation details and competition strategies from building 'Koko Picture Editor' for the 2025 HarmonyOS Developer Incentive Program, covering ArkUI architecture, ImageKit compression, Canvas cropping, color matrix filters, componentSnapshot watermarks, and performance optimization patterns.
Project Background and Overview
The author participated in the HarmonyOS Application Developer Incentive Program 2025 and built a full-featured image editing app called "Koko Picture Editor" on HarmonyOS 5.0.2(14). The project was chosen because image editing is a high-frequency user scenario, presents moderate technical challenges spanning multimedia, graphics rendering, and file operations, showcases HarmonyOS imaging and UI capabilities, and has clear commercialization potential.
Core Features Implemented
Image compression with efficient algorithms to save storage
Precise cropping with custom region selection
Professional filter effects for one-click quality enhancement
Text and image watermarking for content protection
Collage creation for multi-image composition
Freehand drawing and annotation
Technical Architecture and Stack
Technology Choices
Development environment: DevEco Studio 4.0+
SDK version: HarmonyOS 5.0.2(14)
Routing: ZRouter third-party library ( ohpm install @hzw/zrouter)
State management: V2 architecture (@ComponentV2)
UI framework: ArkUI declarative paradigm
Project Initialization
Created a standard Stage model project in DevEco Studio and integrated ZRouter for navigation management.
Tab Structure
Used the system Tab component for multi-page layout:
Tabs({ barPosition: BarPosition.End }) {
TabContent() {
HomePage()
}
.tabBar('Home')
TabContent() {
EditPage()
}
.tabBar('Edit')
// Other tab pages...
}Development Insights and Best Practices
Permission Management Optimization
Insight: Prefer secure controls like SaveButton to reduce complex permission request flows. The SaveButton automatically grants temporary media library access within one minute.
// Using SaveButton secure control, no complex permission requests needed
SaveButton({ text: SaveDescription.SAVE_IMAGE })
.onClick(async () => {
// Automatically gains media library access within one minute
await this.saveToGallery();
})Performance Optimization Strategy
Insight: Check image dimensions and downscale before processing large images to avoid OOM.
async compressImage() {
// Check image dimensions
const info = await src.getImageInfo();
const { width, height } = info.size;
// Downscale large images before compression
if (width > 2048 || height > 2048) {
const scaledPixelMap = await this.scaleImage(src, 2048, 2048);
// Use scaled image for compression...
}
}User Experience Enhancement
Insight: Add loading indicators for async operations to prevent UI freezing.
@State isLoading: boolean = false;
async processImage() {
this.isLoading = true;
try {
// Execute time-consuming operation...
await this.compressionTask();
} finally {
this.isLoading = false;
}
}
// In UI
if (this.isLoading) {
LoadingProgress()
.width(50)
.height(50)
}Core Technical Implementation Details
Image Compression Feature
Compression involves four key steps: selection, core algorithm, save, and share.
3.1.1 Image Selection
Used PhotoViewPicker from MediaLibraryKit:
import { photoAccessHelper } from '@kit.MediaLibraryKit';
async selectPhoto() {
const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
photoSelectOptions.maxSelectNumber = 1;
const photoPicker = new photoAccessHelper.PhotoViewPicker();
const photoSelectResult = await photoPicker.select(photoSelectOptions);
this.selectedPhotoUri = photoSelectResult?.photoUris?.[0] ?? '';
}3.1.2 Core Compression Algorithm
Used ImagePacker from ImageKit for efficient compression:
import { image } from '@kit.ImageKit';
async compressImage() {
const file = fileIo.openSync(this.selectedPhotoUri, fileIo.OpenMode.READ_ONLY);
const src = image.createImageSource(file.fd);
const packer = image.createImagePacker();
// Construct target path
const targetPath = context.cacheDir + '/' + Date.now() + '.jpg';
const newFile = fileIo.openSync(targetPath,
fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE);
// Compress to JPEG format
await packer.packToFile(src, newFile.fd, {
format: 'image/jpeg',
quality: 10 // Quality parameter: 0-100
});
}3.1.3 Save and Share
Integrated ShareKit for cross-app sharing:
import { systemShare } from '@kit.ShareKit';
import { uniformTypeDescriptor } from '@kit.ArkData';
async shareImage() {
// Determine UTD type from file extension
let utdTypeId = uniformTypeDescriptor.getUniformDataTypeByFilenameExtension(
'.jpg', uniformTypeDescriptor.UniformDataType.IMAGE);
const shareData = new systemShare.SharedData({
utd: utdTypeId,
title: 'Image Share',
description: 'From Koko Picture Editor',
uri: fileUri.getUriFromPath(this.selectedPhotoUri),
});
const controller = new systemShare.ShareController(shareData);
await controller.show(context, {
selectionMode: systemShare.SelectionMode.SINGLE,
previewMode: systemShare.SharePreviewMode.DETAIL
});
}Canvas Image Cropping Technology
Cropping is implemented using Canvas 2D drawing capabilities.
3.2.1 Canvas Basic Usage
@Component
struct CanvasDemo {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D =
new CanvasRenderingContext2D(this.settings);
build() {
Canvas(this.context)
.width('100%')
.height('100%')
.onReady(() => {
// Draw rectangle
this.context.strokeRect(50, 50, 200, 150);
})
}
}3.2.2 Coordinate System and Drawing APIs
Canvas coordinate system originates at top-left (0,0). Key APIs demonstrated:
// Draw line
this.context.moveTo(10, 10);
this.context.lineTo(100, 100);
this.context.stroke();
// Draw rectangle
this.context.strokeRect(50, 50, 200, 150);
// Draw arc (radians: 360° = 2π)
this.context.beginPath();
this.context.arc(100, 75, 50, 0, Math.PI / 2);
this.context.stroke();3.2.3 Image Cropping Implementation
Combined createPixelMap and drawImage for precise cropping:
async cropImage() {
const file = fileIo.openSync(this.selectedPhotoUri, fileIo.OpenMode.READ_ONLY);
const src = image.createImageSource(file.fd);
const pm = await src.createPixelMap();
// Define crop region
const sx = 200, sy = 200; // Start coordinates
const sw = 100, sh = 100; // Crop dimensions
// Clear canvas and draw crop region
this.context.clearRect(0, 0, 200, 200);
this.context.drawImage(pm, sx, sy, sw, sh, 0, 0, sw, sh);
}Filter Effects Implementation
Filters use colorFilter property and color matrix transformations.
3.3.1 Color Matrix Principle
colorFilter uses a 4×5 matrix to mathematically transform each pixel's RGBA values:
R' = r1*R + r2*G + r3*B + r4*A + r5*255
G' = g1*R + g2*G + g3*B + g4*A + g5*255
B' = b1*R + b2*G + b3*B + b4*A + b5*255
A' = a1*R + a2*G + a3*B + a4*A + a5*2553.3.2 Common Filter Matrices
Grayscale Filter:
const grayMatrix = [
0.299, 0.587, 0.114, 0, 0,
0.299, 0.587, 0.114, 0, 0,
0.299, 0.587, 0.114, 0, 0,
0, 0, 0, 1, 0
];Sepia Nostalgic Effect:
const sepiaMatrix = [
0.393, 0.769, 0.189, 0, 0,
0.349, 0.686, 0.168, 0, 0,
0.272, 0.534, 0.131, 0, 0,
0, 0, 0, 1, 0
];3.3.3 DrawingColorFilter Advanced Usage
Used @kit.ArkGraphics2D convenience APIs:
import { drawing } from '@kit.ArkGraphics2D';
// Blend mode tinting
let redFilter = drawing.ColorFilter.createBlendModeColorFilter(
{ alpha: 255, red: 255, green: 0, blue: 0 },
drawing.BlendMode.SRC_IN
);Watermark Feature Implementation
Watermarking cleverly combines UI layering and component screenshot technology.
3.4.1 componentSnapshot Technology
componentSnapshot converts UI components to PixelMap image data:
async takeScreenshot() {
const uiContext = this.getUIContext();
const pixelMap = await uiContext.getComponentSnapshot()
.get('watermarkContainer', {
scale: 1.0,
waitUntilRenderFinished: true
});
this.screenshotImage = pixelMap;
}3.4.2 Watermark Implementation Approach
Stack layout with original image and watermark text, then capture via componentSnapshot:
Stack({ alignContent: Alignment.BottomEnd }) {
// Original image
Image(this.selectedImage)
.width(200)
.height(200)
// Watermark text
Text("© Koko Picture Editor")
.fontColor(Color.White)
.backgroundColor(Color.Black)
.opacity(0.6)
.padding(8)
}
.width(200)
.height(200)
.id("watermarkContainer") // Set ID for screenshotCompetition Strategy and Experience Sharing
Preparation Phase
Technical Preparation
Familiarize with HarmonyOS development environment: install DevEco Studio, learn ArkUI syntax, understand Stage model lifecycle
Master core APIs: MediaLibrary (selection/save), ImageKit (compression/crop/filter), File I/O (read/write/share)
Reference official docs: HarmonyOS developer website, API reference, samples and Codelabs
Project Planning
Feature design: define core features, plan UI/UX flows, design technical architecture
Development plan: set milestones, reserve testing/optimization time, prepare app assets (icons, screenshots)
Implementation Phase
Development Process
Basic framework setup: create project, install dependencies (hvigor create, ohpm install @hzw/zrouter)
Core feature development: image selection/display, compression algorithm, cropping, filters, watermark integration
UI/UX refinement: interface polish, interaction optimization, responsive adaptation
Common Issues and Solutions
Issue 1: Large image processing causes OOM
// Check dimensions and scale appropriately
const info = await src.getImageInfo();
if (info.size.width > 2048) {
// Scale first, then process
const scaledPixelMap = await this.scaleImage(src, 2048, -1);
}Issue 2: Complex permission requests
// Use secure controls to simplify permission flow
SaveButton({ text: SaveDescription.SAVE_IMAGE })
.onClick(() => {
// Automatically gains temporary permission
})Issue 3: Device compatibility
// Responsive layout
.width('100%')
.height('100%')
.constraintSize({
minWidth: 320,
maxWidth: 768
})Testing and Optimization
Testing Strategy
Functional testing: core flows, boundary conditions, exception handling
Performance testing: large image processing, memory usage, response time
Compatibility testing: different device models, system versions, orientation changes
Performance Optimization Techniques
1. Image processing optimization: Use Worker threads for large images
// Use Worker thread for large image processing
const worker = new worker.ThreadWorker('workers/image-processor.js');
worker.postMessage({ imageUri: this.selectedUri });2. Memory management: Release PixelMap resources promptly
// Release PixelMap resources promptly
pixelMap.release();3. UI rendering optimization: Use LazyForEach for lazy loading
// Use LazyForEach for lazy loading
LazyForEach(this.dataSource, item => {
return ImageItem({ item: item });
})App Release Preparation
AGC App Creation
Access AppGallery Connect console
Create HarmonyOS app
Configure basic app information
Signing Certificate Configuration
Generate keystore file (.p12)
Apply for debug/release certificate (.cer)
Apply for Profile file (.p7b)
Configure build-profile.json5
App Information Preparation
Assets: 512x512 icon, at least 3 screenshots, optional demo video
Description: name, summary, feature highlights, changelog
Category and tags: appropriate category selection, relevant tags
Competition Gains and Outlook
Technical Gains
HarmonyOS development proficiency: mastered ArkUI declarative development, familiar with system capability invocation, accumulated performance optimization experience
Image processing depth: deep understanding of compression algorithms, Canvas drawing, color matrix transformation principles
Full-stack capability: complete flow from UI design to implementation, app publishing and operations experience, user feedback handling
Commercial Value
App store revenue: Huawei AppGallery exposure, user downloads, potential monetization
Technical influence: community recognition, speaking/sharing opportunities, personal brand building
Ecosystem participation: contribute to HarmonyOS ecosystem, gain official resource support, future collaboration opportunities
Future Directions
Feature expansion: AI smart editing, batch processing, cloud sync
Technical upgrades: adapt to HarmonyOS 6.0 new features, integrate more system capabilities, optimize performance and UX
Ecosystem collaboration: integrate with other apps, contribute to open source, share development experience
Advice for New Participants
Technical Advice
Start with simple features: don't chase complexity initially, implement core features first then iterate, focus on code quality and architecture
Leverage official resources: read docs carefully, reference samples and Codelabs, engage in developer community discussions
Prioritize performance: consider performance early, use profiling tools, optimize memory and response speed
Competition Strategy
Plan time wisely: detailed development plan, reserve ample testing time, don't wait until deadline to submit
Focus on UX: design intuitive UI, provide smooth interactions, handle edge cases gracefully
Prepare thoroughly: ready app assets early, write detailed descriptions, prepare demo videos and screenshots
Mindset Adjustment
Maintain learning mindset: actively seek solutions, learn from failures, continuously improve skills
Enjoy the process: treat competition as learning opportunity, enjoy technical innovation, exchange with other developers
Focus on long-term growth: don't fixate on competition results, emphasize technical accumulation, build foundation for career
Conclusion
Participating in the HarmonyOS Developer Incentive Program 2025 was a valuable technical growth experience. Through building Koko Picture Editor, the author not only mastered HarmonyOS development but gained practical battle-tested experience. The HarmonyOS ecosystem is in rapid growth, offering developers a broad stage. The article concludes with links to the app on AppGallery and reference resources including the HarmonyOS developer website, AppGallery Connect, and Huawei Developer Alliance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
51CTO HarmonyOS Developer Community
The HarmonyOS Developer Community is a learning-oriented community for developers to learn, communicate, ask questions, and share.
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.
