Mobile Development 22 min read

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.

51CTO HarmonyOS Developer Community
51CTO HarmonyOS Developer Community
51CTO HarmonyOS Developer Community
Building a Full-Featured Image Editor for HarmonyOS: 2025 Developer Competition Insights & Technical Guide

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*255

3.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 screenshot

Competition 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

mobile developmentperformance-optimizationImage ProcessingCanvasHarmonyOSArkUIDevEco StudioImageKitMediaLibraryKitShareKit
51CTO HarmonyOS Developer Community
Written by

51CTO HarmonyOS Developer Community

The HarmonyOS Developer Community is a learning-oriented community for developers to learn, communicate, ask questions, and share.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.