Technical Solution for Static Text Template Rendering in Video Editing
The article presents a JSON‑driven solution for rendering static text templates in video editing, detailing asset integration, cross‑platform layout using CoreText and FreeType, asynchronous drawing, memory and performance optimizations, and guidelines for consistent rich‑text rendering across iOS, Android, and web.
This article shares a technical solution for rendering static text templates in video editing scenarios, based on the development practice of the DuKa video editing app. The solution, as a superset of rich‑text rendering, can be extended to other complex rich‑text use cases.
Background : Video creation tools rely heavily on a rich asset library, including text templates that enable styled text overlays. Early versions of DuKa lacked text templates; the new feature improves product competitiveness and material penetration.
Overall Design : A new asset type "text template" was added to the existing material platform, providing editing, preview, configuration, and online publishing functions. The workflow integrates material production, preview, distribution, and client rendering.
Implementation :
Material Production : Uses a JSON structure to describe typography attributes and rendering parameters. Two production approaches were considered: resource/configuration files and Photoshop PSD files. The JSON‑based approach was chosen for flexibility and lower cost.
Client Rendering : Text layout is performed with CoreText on iOS and FontMetrics/FreeType on Android. Rendering uses QuartzCore on iOS and Canvas on Android. During export, text templates are converted to stickers and composited into the video.
Description File Design : The JSON file includes (1) typography attributes (baseline, ascent, descent, leading, advance width, side bearings, bounding box, x‑height, cap‑height) and (2) text object composition.
Layout & Rendering Process : Layout and drawing are interleaved. Asynchronous drawing is employed to off‑load heavy rendering to background threads, preventing UI blocking.
Performance Optimizations : Asynchronous rendering queues user operations, processes them sequentially on a background thread, and caches partially rendered results to avoid full re‑draws.
Memory Optimizations : Each text template is kept under 20 MB. Font size, line count, and scaling are calculated to balance clarity and memory usage, preventing OOM on devices.
The article also discusses challenges such as multi‑platform rendering consistency and pre‑layout calculations, and emphasizes the need for standardized JSON definitions to achieve uniform results across web, iOS, and Android.
Conclusion : Rich‑text rendering in video editing is complex and requires careful design of typography, layout, and rendering pipelines. The presented solution provides a practical approach for static text templates, covering typography fundamentals, JSON description, asynchronous drawing, and memory management.
CGFloat ascent, descent;
UIFont *font = [self.calFont fontWithSize:size];
CTFontRef fontRefMeasure = (__bridge CTFontRef)font;
[attrString addAttribute:(id)kCTFontAttributeName value:(__bridge id)fontRefMeasure range:NSMakeRange(0, attrString.length)];
CTLineRef line = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)attrString);
CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
// calculate max font size
CGFloat calFontHeight = MIN(height, width);
self.maxFontHeight = calFontHeight;
// calculate min font size
CGFloat maxLine = self.document.maxLine * BDTZBigFontDataOriginScale;
if (maxLine <= 0) { maxLine = 1; }
calFontHeight = [self itemWidth] / (maxLine + (maxLine - 1) * (self.leadingRatio * BDTZBigFontDataOriginScale - 1));
self.minFontHeight = MIN(self.maxFontHeight, calFontHeight);
// longest column
int64_t n = 0;
NSArray *strArray = [self.document.content componentsSeparatedByString:@"\n"];
NSString *measureStr = self.document.content;
for (NSString *str in strArray) {
if (str.length > n) {
n = str.length;
measureStr = str;
}
}
CGFloat fontWidthRatioOrigin = (self.document.fontWidthRatio * BDTZBigFontDataOriginScale);
CGFloat trackingRatio = (self.document.trackingRatio * BDTZBigFontDataOriginScale) * (ascent + descent) / ascent;
CGRect rect = [@"我" boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.calFont} context:nil];
CGFloat fontWidthRatio = fontWidthRatioOrigin > 0 ? fontWidthRatioOrigin * (ascent + descent) / ascent : rect.size.width / rect.size.height;
CGFloat fontHeight = width / (n * fontWidthRatio + n * trackingRatio);
if (strArray.count > 1) {
calFontHeight = [self itemWidth] / (strArray.count + (strArray.count - 1) * (self.leadingRatio * BDTZBigFontDataOriginScale - 1));
fontHeight = MIN(fontHeight, calFontHeight);
}
if (fontHeight > self.maxFontHeight) { fontHeight = self.maxFontHeight; }
else if (fontHeight < self.minFontHeight) { fontHeight = self.minFontHeight; }
CGFloat calSize = fontHeight;
calFontHeight = [self calculateFontHeightSize:calSize];
calSize = floorf(calSize / (calFontHeight * (ascent + descent) / ascent) * calSize);
if (calSize <= 0) { return calSize; }
self.fontHeight = calFontHeight * (ascent + descent) / ascent;
self.font = [self.calFont fontWithSize:calSize];Baidu Geek Talk
Follow us to discover more Baidu tech insights.
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.