# MaLiang: Metal-Based Drawing and Handwriting for iOS

> MaLiang is a Swift 5 drawing framework for iOS applications that need textured brushes, pressure-sensitive strokes, chartlets, zoom, undo, redo, image export, and saved vector content. Its documented setup is CocoaPods or Carthage, while the latest listed release dates from 2020 and the repository was last pushed on 2026-06-22.

**Harley-xk/MaLiang** — iOS painting and drawing library based on Metal. 神笔马良有一支神笔（基于 Metal 的涂鸦绘图库）

- Repository: https://github.com/Harley-xk/MaLiang
- Stars: 1,497 · Forks: 218
- Language: Swift
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/harley-xk-maliang

## What MaLiang solves for iOS drawing applications

MaLiang addresses a specific part of an iOS product: presenting an interactive drawing surface to the user. It is for developers who need handwriting, sketching, or doodling without implementing the rendering layer, brush registration, gesture handling, and drawing history from scratch. The library is written in Swift 5 and its core painting module uses Metal through MetalKit.

The documented feature set includes Bézier curves, texture rotation, glowing lines, force-based stroke adjustment, Pencil and 3D Touch support, undo and redo, zooming and scaling, image export, and saving vector contents to disk. It also supports chartlets, which are image or other UIView snapshots rendered as canvas elements. These are application-facing capabilities rather than a general document editor. MaLiang does not provide text layout or text styling. The README says that an application should style and lay out text first, take a snapshot, and then render that image through the chartlet APIs.

That boundary matters. MaLiang is closer to a rendering and interaction framework than to a complete annotation product. It can place prepared visual content on a canvas, but the developer still owns the surrounding application model, text composition, and application-specific saving behavior.

## Canvas, MetalView, and the drawing data path

The central type is `Canvas`, declared in the README as an open subclass of `MetalView`. `MetalView` in turn extends `MTKView`. According to the repository documentation, `MetalView` handles the MetalKit logic and hides that implementation from the application developer. This gives the app a familiar `UIView`-style surface while the library manages Metal-backed rendering underneath.

A canvas can be created in Interface Builder by changing a `UIView` object's class to `Canvas` and its module to `MaLiang`, or it can be created in code with `init(frame:)`. Once a canvas exists, the README describes registering a `Brush` from image data or a file. A brush supplies a texture and color, which are then used while the user paints.

The brush configuration includes opacity, point size, point spacing, force sensitivity, color, and whether stroke size scales with the canvas. `pointStep` controls the minimum distance between nearby textures. A value of 1 means every calculated texture is rendered and distance calculation is skipped. Force changes stroke size through `forceSensitive`, which is documented as a value from 0 to 1. A value of 0 disables force-based size adjustment. The README also states that 3D Touch is supported by default and that simulated force is configured on devices without it.

## Textured brushes, chartlets, and pressure-sensitive strokes

MaLiang distinguishes ordinary brush strokes from chartlet elements. A brush is registered directly with the canvas from a file or image data. The documented example uses a PNG named `pencil`, registers it, and calls `use()` to activate it. Brush opacity affects stroke darkness, while `pointSize` controls line width in points. The library also supports texture rotation and glowing lines, although the README excerpt does not show the complete API calls for those features.

Chartlets are pre-rendered image elements rather than procedural strokes. An application can obtain PNG data from a `UIImage`, convert that data into a texture with `makeTexture(with:)`, and render it at a location with a size, texture identifier, and rotation. The documented call is:

```swift
let data = UIImage(named: "chartlet").pngData()
let texture = try canvas.makeTexture(with: data)
```

The resulting texture can be passed to `renderChartlet(at:size:textureID:rotation:)`. Rotation is expressed as a counterclockwise angle in radians. This model works for images and snapshots of arbitrary `UIView` content, but it means the quality and layout of non-paint content depend on the snapshot produced by the host application. MaLiang does not turn the chartlet back into editable vector text.

## Installing MaLiang and adding the first canvas

The README documents two installation routes. CocoaPods is the shorter route. Add the dependency to the `Podfile`:

```ruby
pod 'MaLiang'
```

For the older OpenGL ES version, the README gives a separate dependency declaration:

```ruby
pod 'MaLiang', '~> 1.1'
```

The project is also documented as Carthage compatible. Add the repository to a `Cartfile`:

```ruby
github "Harley-xk/MaLiang"
```

Then run the documented build command:

```bash
carthage update
```

The README instructs the developer to drag the built `MaLiang.framework` into the Xcode project and add it to the target's `Embedded Binaries`. It does not give a Swift Package Manager installation procedure.

A first real use starts by importing the module and creating a canvas in the host view controller. The README's usage sequence is simply to import `MaLiang`, create the `Canvas`, and paint. For a programmatic surface, the README says it can be created with `init(frame:)` as with a `UIView`.

The application still needs to add the canvas to its view hierarchy and position it. In Interface Builder, the documented alternative is to use a `UIView`, set its class to `Canvas`, and set its module to `MaLiang`.

## Saving, exporting, and recovery boundaries

MaLiang separates rendered output from the data that represents the canvas. The `CanvasData` type is configured by default, holds the canvas data, and makes undo and redo possible. The README says applications can implement their own saving logic using the data held by `CanvasData`.

Image output is available through the canvas `snapshot` function, which returns an optional `UIImage`. This is convenient for thumbnails, sharing, or saving a bitmap representation, but the documentation does not state the image scale, color profile, or whether snapshot output preserves all vector metadata. Those details would need verification against the implementation before they become part of an application's export contract.

For disk persistence, the documented starting point is `DataExporter`:

```swift
let exporter = DataExporter(canvas: canvas)
exporter.save(to: localPath, progress: progressHandler, result: resultHandler)
```

The README excerpt says that vector contents can be saved to disk and shows this method signature. It does not define the file format, serialization version, migration policy, error object, or behavior when `localPath` already contains data. It also does not document rollback or recovery after a failed save. MaLiang therefore supplies persistence entry points, but it does not promise a complete document lifecycle.

## Platform limits, alternatives, and maintenance cost

The documented requirements are iOS 9.0 and Swift 5, with Metal at the core. The README also states support for macOS Catalyst. It does not provide evidence for native macOS use, iPad-specific behavior, or deployment beyond the stated requirements. The claim that lower iOS and Swift versions can be supported by changing several lines of code is not accompanied by a compatibility matrix, so it should not be treated as a supported configuration.

A real alternative is to build a drawing layer directly on `MTKView` or use another canvas-oriented iOS drawing framework. The direct MetalKit approach gives the developer control over render pipelines, shaders, touch handling, and storage, but it also requires implementing brush spacing, curve handling, history, and export. MaLiang packages those concerns around Metal and adds chartlets and pressure configuration. Its tradeoff is a smaller documented surface and an older visible release history.

The repository is not archived, and the last push was on 2026-06-22. However, the latest listed releases are `2.9.2` on 2020-12-16, `2.9.1` on 2020-12-16, and `2.9.0` on 2020-10-26. The current source history should not be confused with a recent release stream. Upgrade planning should account for the long gap between listed releases, the Swift 5 requirement, and the absence of release notes for any post-2.9.2 changes. The MIT license permits use and modification under its terms, but applications still need to review the license text and attribution obligations themselves.

## Conclusion

Adopt MaLiang when an iOS app needs a Metal-backed canvas with textured brushes, handwriting input, chartlets, undo and redo, and image or vector persistence. Do not choose it if the application requires macOS support outside the documented Catalyst case, a current release train, or a complete text layout system. Verify first that your target and toolchain match the documented Swift 5 and iOS 9.0 requirements, then inspect the Example project and the persistence APIs because the README does not document deployment targets, Xcode version support, schema versioning, or rollback behavior.

## FAQ

### What is MaLiang used for?

MaLiang is a Swift 5 iOS painting framework based on Metal. It supports drawing, handwriting, textured brushes, pressure-sensitive strokes, chartlets, undo and redo, zoom, image export, and saving vector contents.

### How do I install MaLiang in an iOS project?

The README documents CocoaPods with `pod 'MaLiang'` and Carthage with `github "Harley-xk/MaLiang"` in a `Cartfile`. It does not document Swift Package Manager installation.

### Can MaLiang render text and UIView content?

MaLiang can render chartlets made from image data or snapshots of a `UIView`. Text layout and styling are left to the application, so MaLiang does not provide editable text layout through the documented API.

## Sources

- [Harley-xk/MaLiang on GitHub](https://github.com/Harley-xk/MaLiang)
- [Issues](https://github.com/Harley-xk/MaLiang/issues)
- [License: MIT](https://github.com/Harley-xk/MaLiang/blob/master/LICENSE)
- [README](https://github.com/Harley-xk/MaLiang/blob/master/README.md)
- [Releases](https://github.com/Harley-xk/MaLiang/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/harley-xk-maliang
