@angadie/chittie-react-native 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/ChittieReactNative.podspec +32 -0
  2. package/LICENSE +24 -0
  3. package/README.md +80 -0
  4. package/android/CMakeLists.txt +25 -0
  5. package/android/build.gradle +100 -0
  6. package/android/fix-prefab.gradle +37 -0
  7. package/android/gradle.properties +5 -0
  8. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  9. package/android/src/main/java/com/margelo/nitro/chittie/HybridChittieRasterizer.kt +53 -0
  10. package/app.plugin.js +5 -0
  11. package/ios/HybridChittieRasterizer.swift +48 -0
  12. package/lib/commonjs/adapter.js +33 -0
  13. package/lib/commonjs/adapter.js.map +1 -0
  14. package/lib/commonjs/index.js +34 -0
  15. package/lib/commonjs/index.js.map +1 -0
  16. package/lib/commonjs/package.json +1 -0
  17. package/lib/commonjs/specs/ChittieRasterizer.nitro.js +6 -0
  18. package/lib/commonjs/specs/ChittieRasterizer.nitro.js.map +1 -0
  19. package/lib/module/adapter.js +29 -0
  20. package/lib/module/adapter.js.map +1 -0
  21. package/lib/module/index.js +25 -0
  22. package/lib/module/index.js.map +1 -0
  23. package/lib/module/specs/ChittieRasterizer.nitro.js +4 -0
  24. package/lib/module/specs/ChittieRasterizer.nitro.js.map +1 -0
  25. package/lib/typescript/src/adapter.d.ts +11 -0
  26. package/lib/typescript/src/adapter.d.ts.map +1 -0
  27. package/lib/typescript/src/index.d.ts +15 -0
  28. package/lib/typescript/src/index.d.ts.map +1 -0
  29. package/lib/typescript/src/specs/ChittieRasterizer.nitro.d.ts +23 -0
  30. package/lib/typescript/src/specs/ChittieRasterizer.nitro.d.ts.map +1 -0
  31. package/nitro.json +23 -0
  32. package/nitrogen/generated/.gitattributes +1 -0
  33. package/nitrogen/generated/android/ChittieReactNative+autolinking.cmake +81 -0
  34. package/nitrogen/generated/android/ChittieReactNative+autolinking.gradle +27 -0
  35. package/nitrogen/generated/android/ChittieReactNativeOnLoad.cpp +54 -0
  36. package/nitrogen/generated/android/ChittieReactNativeOnLoad.hpp +34 -0
  37. package/nitrogen/generated/android/c++/JHybridChittieRasterizerSpec.cpp +58 -0
  38. package/nitrogen/generated/android/c++/JHybridChittieRasterizerSpec.hpp +63 -0
  39. package/nitrogen/generated/android/c++/JRasterBitmap.hpp +66 -0
  40. package/nitrogen/generated/android/kotlin/com/margelo/nitro/chittie/ChittieReactNativeOnLoad.kt +35 -0
  41. package/nitrogen/generated/android/kotlin/com/margelo/nitro/chittie/HybridChittieRasterizerSpec.kt +54 -0
  42. package/nitrogen/generated/android/kotlin/com/margelo/nitro/chittie/RasterBitmap.kt +44 -0
  43. package/nitrogen/generated/ios/ChittieReactNative+autolinking.rb +60 -0
  44. package/nitrogen/generated/ios/ChittieReactNative-Swift-Cxx-Bridge.cpp +33 -0
  45. package/nitrogen/generated/ios/ChittieReactNative-Swift-Cxx-Bridge.hpp +54 -0
  46. package/nitrogen/generated/ios/ChittieReactNative-Swift-Cxx-Umbrella.hpp +48 -0
  47. package/nitrogen/generated/ios/ChittieReactNativeAutolinking.mm +33 -0
  48. package/nitrogen/generated/ios/ChittieReactNativeAutolinking.swift +26 -0
  49. package/nitrogen/generated/ios/c++/HybridChittieRasterizerSpecSwift.cpp +11 -0
  50. package/nitrogen/generated/ios/c++/HybridChittieRasterizerSpecSwift.hpp +88 -0
  51. package/nitrogen/generated/ios/swift/HybridChittieRasterizerSpec.swift +55 -0
  52. package/nitrogen/generated/ios/swift/HybridChittieRasterizerSpec_cxx.swift +138 -0
  53. package/nitrogen/generated/ios/swift/RasterBitmap.swift +39 -0
  54. package/nitrogen/generated/shared/c++/HybridChittieRasterizerSpec.cpp +21 -0
  55. package/nitrogen/generated/shared/c++/HybridChittieRasterizerSpec.hpp +64 -0
  56. package/nitrogen/generated/shared/c++/RasterBitmap.hpp +91 -0
  57. package/package.json +77 -0
  58. package/src/adapter.ts +25 -0
  59. package/src/index.ts +27 -0
  60. package/src/specs/ChittieRasterizer.nitro.ts +21 -0
@@ -0,0 +1,32 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "ChittieReactNative"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported }
14
+ s.source = { :git => "https://github.com/octalpixel/chittie.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = [
17
+ # Implementation (Swift)
18
+ "ios/**/*.{swift}",
19
+ # Autolinking / registration (Objective-C++)
20
+ "ios/**/*.{m,mm}",
21
+ # C++ objects (if any)
22
+ "cpp/**/*.{hpp,cpp}",
23
+ ]
24
+
25
+ # nitrogen-generated autolinking (produced by `nitro-codegen`).
26
+ load 'nitrogen/generated/ios/ChittieReactNative+autolinking.rb'
27
+ add_nitrogen_files(s)
28
+
29
+ s.dependency 'React-jsi'
30
+ s.dependency 'React-callinvoker'
31
+ install_modules_dependencies(s)
32
+ end
package/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Asyncdot Engineering
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ Portions of this software are vendored from MIT-licensed projects and retain
16
+ their original copyright notices; see VENDOR.md.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # @angadie/chittie-react-native
2
+
3
+ The **React Native backend for chittie** — a [Nitro](https://nitro.margelo.com) module that
4
+ rasterizes **non-Latin text** (Sinhala/Tamil/Arabic) natively (**CoreText** on iOS,
5
+ **android.graphics** on Android) and exposes it as chittie's `TextRasterizer`. No Skia.
6
+
7
+ > **Dev client / bare RN only** — it's a native module, so it can't run in Expo Go. (Your printer
8
+ > transport — BLE/USB — needs a dev client anyway, so this costs you nothing extra.) See the RFC:
9
+ > `docs/rfc/rn-native.md`.
10
+
11
+ ## Install
12
+
13
+ ```sh
14
+ npm i @angadie/chittie-react-native @angadie/chittie react-native-nitro-modules
15
+ cd ios && pod install # iOS
16
+ # Android autolinks; rebuild the dev client.
17
+ ```
18
+
19
+ The Nitro bindings (`nitrogen/`) are **generated and shipped** — you only re-run `npm run codegen`
20
+ if you change the `.nitro.ts` spec. Built with **react-native-builder-bob** (`lib/commonjs|module|
21
+ typescript`). Requires React Native's **new architecture**.
22
+
23
+ ## Use
24
+
25
+ Pass the native rasterizer to `render()` — everything else is the same chittie API:
26
+
27
+ ```tsx
28
+ import { render, Printer, Text, Row } from '@angadie/chittie';
29
+ import { createNativeRasterizer } from '@angadie/chittie-react-native';
30
+
31
+ const rasterizer = createNativeRasterizer();
32
+
33
+ const bytes = render(
34
+ <Printer width={32}>
35
+ <Text align="center" bold>ආයුබෝවන්</Text>
36
+ <Row left="තේ" right="Rs. 250" />
37
+ </Printer>,
38
+ { dotWidth: 384, rasterizer } // 58mm
39
+ );
40
+ // send `bytes` over your transport (BLE/USB/TCP)
41
+ ```
42
+
43
+ The native side returns an RGBA bitmap sized to the text (dims padded to /8), which chittie packs
44
+ to ESC/POS raster unchanged.
45
+
46
+ ## Architecture
47
+
48
+ ```
49
+ TS: createNativeRasterizer() → makeRasterizer(native) → chittie TextRasterizer
50
+ (src/index.ts) (src/adapter.ts, pure) (ImageData → render())
51
+ Nitro spec: src/specs/ChittieRasterizer.nitro.ts (rasterize → RasterBitmap{data,width,height})
52
+ Native: ios/HybridChittieRasterizer.swift (UIKit/CoreText)
53
+ android/.../HybridChittieRasterizer.kt (StaticLayout/Canvas)
54
+ ```
55
+
56
+ `makeRasterizer` is pure and dependency-free (no Nitro import) so it's unit-testable off-device;
57
+ `createNativeRasterizer` wires the real Nitro HybridObject.
58
+
59
+ ## What's verified vs gated
60
+
61
+ - **Verified (off-device):** `nitro-codegen` runs and the bindings are committed under `nitrogen/`;
62
+ the TS adapter spike (native bitmap → `ImageData` → chittie's `padTo8`, `spikes/adapter.spike.mts`);
63
+ `bob build` (commonjs/module/typescript) + typecheck in the monorepo gate.
64
+ - **Gated (needs Xcode/Android Studio + a device):** the native **Swift/Kotlin compile** and an
65
+ on-device snapshot of the rendered glyphs. The iOS/Android build files mirror the proven
66
+ `react-native-nitro-haptics` template; the device build validates them.
67
+
68
+ ## Roadmap (per the RFC)
69
+
70
+ - Phase 1 — **rasterizer** (this).
71
+ - Phase 2 — **read-capable BLE transport** (status via `DLE EOT` notify; see `chittie-transport`'s
72
+ `queryStatus`).
73
+ - Phase 3 — **USB (Android host) + TCP** transports.
74
+
75
+ ## Notes
76
+
77
+ - Complex shaping + bidi come from the platform engines for free (UIKit/StaticLayout), so Arabic
78
+ joins and reorders correctly. For RTL *rows*, also pass `rtl` to `<Row>` (see `docs/i18n.md`).
79
+ - For font selection, the native side uses the system font (which has Sinhala/Tamil/Arabic
80
+ fallbacks); custom-font support is a future option.
@@ -0,0 +1,25 @@
1
+ project(ChittieReactNative)
2
+ cmake_minimum_required(VERSION 3.9.0)
3
+
4
+ set (PACKAGE_NAME ChittieReactNative)
5
+ set (CMAKE_VERBOSE_MAKEFILE ON)
6
+ set (CMAKE_CXX_STANDARD 20)
7
+
8
+ # Define C++ library and add all sources
9
+ add_library(${PACKAGE_NAME} SHARED
10
+ src/main/cpp/cpp-adapter.cpp
11
+ )
12
+
13
+ # Add Nitrogen specs :)
14
+ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/ChittieReactNative+autolinking.cmake)
15
+
16
+ # Set up local includes
17
+ include_directories("src/main/cpp")
18
+
19
+ find_library(LOG_LIB log)
20
+
21
+ target_link_libraries(
22
+ ${PACKAGE_NAME}
23
+ ${LOG_LIB}
24
+ android
25
+ )
@@ -0,0 +1,100 @@
1
+ buildscript {
2
+ repositories {
3
+ google()
4
+ mavenCentral()
5
+ }
6
+ dependencies {
7
+ classpath "com.android.tools.build:gradle:8.8.0"
8
+ }
9
+ }
10
+
11
+ def reactNativeArchitectures() {
12
+ def value = rootProject.getProperties().get("reactNativeArchitectures")
13
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
14
+ }
15
+
16
+ def isNewArchitectureEnabled() {
17
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
18
+ }
19
+
20
+ apply plugin: "com.android.library"
21
+ apply plugin: "org.jetbrains.kotlin.android"
22
+ apply from: '../nitrogen/generated/android/ChittieReactNative+autolinking.gradle'
23
+ apply from: "./fix-prefab.gradle"
24
+
25
+ if (isNewArchitectureEnabled()) {
26
+ apply plugin: "com.facebook.react"
27
+ }
28
+
29
+ def getExtOrDefault(name) {
30
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["ChittieReactNative_" + name]
31
+ }
32
+
33
+ def getExtOrIntegerDefault(name) {
34
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["ChittieReactNative_" + name]).toInteger()
35
+ }
36
+
37
+ android {
38
+ namespace "com.chittie"
39
+
40
+ ndkVersion getExtOrDefault("ndkVersion")
41
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
42
+
43
+ defaultConfig {
44
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
45
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
46
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
47
+
48
+ externalNativeBuild {
49
+ cmake {
50
+ cppFlags "-frtti -fexceptions -Wall -Wextra -fstack-protector-all"
51
+ arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
52
+ abiFilters (*reactNativeArchitectures())
53
+
54
+ buildTypes {
55
+ debug { cppFlags "-O1 -g" }
56
+ release { cppFlags "-O2" }
57
+ }
58
+ }
59
+ }
60
+ }
61
+
62
+ externalNativeBuild {
63
+ cmake { path "CMakeLists.txt" }
64
+ }
65
+
66
+ buildFeatures {
67
+ buildConfig true
68
+ prefab true
69
+ }
70
+
71
+ buildTypes {
72
+ release { minifyEnabled false }
73
+ }
74
+
75
+ lintOptions { disable "GradleCompatible" }
76
+
77
+ compileOptions {
78
+ sourceCompatibility JavaVersion.VERSION_1_8
79
+ targetCompatibility JavaVersion.VERSION_1_8
80
+ }
81
+ }
82
+
83
+ repositories {
84
+ mavenCentral()
85
+ google()
86
+ }
87
+
88
+ dependencies {
89
+ //noinspection GradleDynamicVersion
90
+ implementation "com.facebook.react:react-native:+"
91
+ implementation project(":react-native-nitro-modules")
92
+ }
93
+
94
+ if (isNewArchitectureEnabled()) {
95
+ react {
96
+ jsRootDir = file("../src/")
97
+ libraryName = "ChittieReactNative"
98
+ codegenJavaPackageName = "com.chittie"
99
+ }
100
+ }
@@ -0,0 +1,37 @@
1
+ tasks.configureEach { task ->
2
+ // Generate our prefab publication file only after building the native library so a full
3
+ // configuration publication (including the .so) is generated, not just a header publication.
4
+ def prefabConfigurePattern = ~/^prefab(.+)ConfigurePackage$/
5
+ def matcher = task.name =~ prefabConfigurePattern
6
+ if (matcher.matches()) {
7
+ def variantName = matcher[0][1]
8
+ task.outputs.upToDateWhen { false }
9
+ task.dependsOn("externalNativeBuild${variantName}")
10
+ }
11
+ }
12
+
13
+ afterEvaluate {
14
+ def abis = rootProject.getProperties().get("reactNativeArchitectures")?.split(",") ?: ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
15
+ rootProject.allprojects.each { proj ->
16
+ if (proj === rootProject) return
17
+
18
+ def dependsOnThisLib = proj.configurations.findAll { it.canBeResolved }.any { config ->
19
+ config.dependencies.any { dep -> dep.group == project.group && dep.name == project.name }
20
+ }
21
+ if (!dependsOnThisLib && proj != project) return
22
+ if (!proj.plugins.hasPlugin('com.android.application') && !proj.plugins.hasPlugin('com.android.library')) return
23
+
24
+ def variants = proj.android.hasProperty('applicationVariants') ? proj.android.applicationVariants : proj.android.libraryVariants
25
+ variants.all { variant ->
26
+ def variantName = variant.name
27
+ abis.each { abi ->
28
+ def searchDir = new File(proj.projectDir, ".cxx/${variantName}")
29
+ if (!searchDir.exists()) return
30
+ searchDir.eachDir { randomDir ->
31
+ def prefabFile = new File(randomDir, "${abi}/prefab_config.json")
32
+ if (prefabFile.exists()) prefabFile.setLastModified(System.currentTimeMillis())
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,5 @@
1
+ ChittieReactNative_kotlinVersion=2.1.20
2
+ ChittieReactNative_minSdkVersion=24
3
+ ChittieReactNative_targetSdkVersion=35
4
+ ChittieReactNative_compileSdkVersion=34
5
+ ChittieReactNative_ndkVersion=27.1.12297006
@@ -0,0 +1,6 @@
1
+ #include <jni.h>
2
+ #include "ChittieReactNativeOnLoad.hpp"
3
+
4
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
5
+ return margelo::nitro::chittie::initialize(vm);
6
+ }
@@ -0,0 +1,53 @@
1
+ package com.margelo.nitro.chittie
2
+
3
+ import android.graphics.Bitmap
4
+ import android.graphics.Canvas
5
+ import android.graphics.Color
6
+ import android.graphics.Typeface
7
+ import android.text.Layout
8
+ import android.text.StaticLayout
9
+ import android.text.TextPaint
10
+ import com.margelo.nitro.core.ArrayBuffer
11
+ import java.nio.ByteBuffer
12
+ import kotlin.math.ceil
13
+
14
+ // Implements the nitrogen-generated HybridChittieRasterizerSpec.
15
+ // StaticLayout shapes complex scripts (Sinhala/Tamil joining), bidi (Arabic) and
16
+ // wrapping. We size the bitmap to the TEXT width (so chittie's ESC alignment can
17
+ // center the image) and pad width/height to multiples of 8.
18
+ class HybridChittieRasterizer : HybridChittieRasterizerSpec() {
19
+ override fun rasterize(text: String, fontSize: Double, maxWidth: Double, bold: Boolean): RasterBitmap {
20
+ val paint = TextPaint().apply {
21
+ isAntiAlias = true
22
+ color = Color.BLACK
23
+ textSize = fontSize.toFloat()
24
+ typeface = if (bold) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
25
+ }
26
+ val maxW = maxWidth.toInt().coerceAtLeast(8)
27
+
28
+ val layout = StaticLayout.Builder
29
+ .obtain(text, 0, text.length, paint, maxW)
30
+ .setAlignment(Layout.Alignment.ALIGN_NORMAL)
31
+ .setIncludePad(false)
32
+ .build()
33
+
34
+ fun pad8(v: Int) = (v + 7) and 7.inv()
35
+ var used = 0f
36
+ for (i in 0 until layout.lineCount) used = maxOf(used, layout.getLineWidth(i))
37
+ val w = pad8(ceil(used.toDouble()).toInt().coerceIn(8, maxW))
38
+ val h = pad8(layout.height.coerceAtLeast(8))
39
+
40
+ val bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
41
+ Canvas(bmp).apply {
42
+ drawColor(Color.WHITE)
43
+ layout.draw(this)
44
+ }
45
+
46
+ val bb = ByteBuffer.allocateDirect(w * h * 4)
47
+ bmp.copyPixelsToBuffer(bb)
48
+ bb.rewind()
49
+ bmp.recycle()
50
+
51
+ return RasterBitmap(data = ArrayBuffer.copy(bb), width = w.toDouble(), height = h.toDouble())
52
+ }
53
+ }
package/app.plugin.js ADDED
@@ -0,0 +1,5 @@
1
+ // Expo config plugin (pass-through). chittie-react-native is a Nitro native module
2
+ // picked up by autolinking on `expo prebuild` / in a dev client — no extra native
3
+ // config is required. This exists so it can be listed in app.json `plugins` without
4
+ // error if a project prefers to be explicit.
5
+ module.exports = (config) => config;
@@ -0,0 +1,48 @@
1
+ import Foundation
2
+ import NitroModules
3
+ import UIKit
4
+
5
+ // Implements the nitrogen-generated HybridChittieRasterizerSpec.
6
+ // Shapes one line of text with UIKit/CoreText (complex-script shaping + bidi for
7
+ // free) into an RGBA bitmap sized to the TEXT (so chittie's ESC alignment can
8
+ // center the image), with width/height padded to multiples of 8.
9
+ class HybridChittieRasterizer: HybridChittieRasterizerSpec {
10
+ func rasterize(text: String, fontSize: Double, maxWidth: Double, bold: Bool) throws -> RasterBitmap {
11
+ let font = bold
12
+ ? UIFont.boldSystemFont(ofSize: CGFloat(fontSize))
13
+ : UIFont.systemFont(ofSize: CGFloat(fontSize))
14
+ let attrs: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: UIColor.black]
15
+ let attr = NSAttributedString(string: text, attributes: attrs)
16
+
17
+ let maxW = CGFloat(max(8, maxWidth))
18
+ let opts: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading]
19
+ let bounds = attr.boundingRect(
20
+ with: CGSize(width: maxW, height: .greatestFiniteMagnitude), options: opts, context: nil)
21
+
22
+ func pad8(_ v: Int) -> Int { (v + 7) & ~7 }
23
+ let w = max(8, pad8(Int(ceil(bounds.width)) + 2))
24
+ let h = max(8, pad8(Int(ceil(bounds.height)) + 2))
25
+
26
+ let bytesPerRow = w * 4
27
+ var pixels = [UInt8](repeating: 255, count: w * h * 4) // white, opaque
28
+ guard
29
+ let ctx = CGContext(
30
+ data: &pixels, width: w, height: h, bitsPerComponent: 8, bytesPerRow: bytesPerRow,
31
+ space: CGColorSpaceCreateDeviceRGB(),
32
+ bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
33
+ else {
34
+ throw NSError(domain: "chittie", code: 1, userInfo: [NSLocalizedDescriptionKey: "CGContext failed"])
35
+ }
36
+
37
+ // UIKit draws top-left origin; flip the CG context to match.
38
+ UIGraphicsPushContext(ctx)
39
+ ctx.translateBy(x: 0, y: CGFloat(h))
40
+ ctx.scaleBy(x: 1, y: -1)
41
+ attr.draw(with: CGRect(x: 1, y: 1, width: CGFloat(w) - 2, height: CGFloat(h) - 2),
42
+ options: opts, context: nil)
43
+ UIGraphicsPopContext()
44
+
45
+ let buffer = ArrayBuffer.copy(data: Data(pixels))
46
+ return RasterBitmap(data: buffer, width: Double(w), height: Double(h))
47
+ }
48
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.makeRasterizer = makeRasterizer;
7
+ /**
8
+ * Adapt a native `ChittieRasterizer` HybridObject to chittie's `TextRasterizer`.
9
+ * The native side returns an RGBA bitmap (dims already padded to /8); we wrap it
10
+ * as the structural `ImageData` chittie's raster pipeline consumes. Pure and
11
+ * dependency-free at runtime (no Nitro import) — inject `native` so it's testable
12
+ * off-device.
13
+ */
14
+ function makeRasterizer(native) {
15
+ return {
16
+ rasterize(text, options = {}) {
17
+ const {
18
+ fontSize = 24,
19
+ maxWidth = 576,
20
+ bold = false
21
+ } = options;
22
+ const b = native.rasterize(text, fontSize, maxWidth, !!bold);
23
+ // RGBA, structural ImageData — chittie reads { data, width, height }.
24
+ return {
25
+ data: new Uint8ClampedArray(b.data),
26
+ width: b.width,
27
+ height: b.height,
28
+ colorSpace: 'srgb'
29
+ };
30
+ }
31
+ };
32
+ }
33
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["makeRasterizer","native","rasterize","text","options","fontSize","maxWidth","bold","b","data","Uint8ClampedArray","width","height","colorSpace"],"sourceRoot":"../../src","sources":["adapter.ts"],"mappings":";;;;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,cAAcA,CAACC,MAAyB,EAAkB;EACxE,OAAO;IACLC,SAASA,CAACC,IAAY,EAAEC,OAAsB,GAAG,CAAC,CAAC,EAAa;MAC9D,MAAM;QAAEC,QAAQ,GAAG,EAAE;QAAEC,QAAQ,GAAG,GAAG;QAAEC,IAAI,GAAG;MAAM,CAAC,GAAGH,OAAO;MAC/D,MAAMI,CAAC,GAAGP,MAAM,CAACC,SAAS,CAACC,IAAI,EAAEE,QAAQ,EAAEC,QAAQ,EAAE,CAAC,CAACC,IAAI,CAAC;MAC5D;MACA,OAAO;QACLE,IAAI,EAAE,IAAIC,iBAAiB,CAACF,CAAC,CAACC,IAAI,CAAC;QACnCE,KAAK,EAAEH,CAAC,CAACG,KAAK;QACdC,MAAM,EAAEJ,CAAC,CAACI,MAAM;QAChBC,UAAU,EAAE;MACd,CAAC;IACH;EACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createNativeRasterizer = createNativeRasterizer;
7
+ Object.defineProperty(exports, "makeRasterizer", {
8
+ enumerable: true,
9
+ get: function () {
10
+ return _adapter.makeRasterizer;
11
+ }
12
+ });
13
+ var _reactNativeNitroModules = require("react-native-nitro-modules");
14
+ var _adapter = require("./adapter.js");
15
+ let cached;
16
+
17
+ /**
18
+ * The native chittie rasterizer (CoreText / android.graphics) as a chittie
19
+ * `TextRasterizer` — pass it to `render()` so Sinhala/Tamil/Arabic print on a
20
+ * device without Skia. Requires a dev client / bare RN (native module).
21
+ *
22
+ * ```ts
23
+ * import { createNativeRasterizer } from '@angadie/chittie-react-native';
24
+ * const bytes = render(<Receipt/>, { dotWidth: 384, rasterizer: createNativeRasterizer() });
25
+ * ```
26
+ */
27
+ function createNativeRasterizer() {
28
+ if (!cached) {
29
+ const native = _reactNativeNitroModules.NitroModules.createHybridObject('ChittieRasterizer');
30
+ cached = (0, _adapter.makeRasterizer)(native);
31
+ }
32
+ return cached;
33
+ }
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNativeNitroModules","require","_adapter","cached","createNativeRasterizer","native","NitroModules","createHybridObject","makeRasterizer"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;AAAA,IAAAA,wBAAA,GAAAC,OAAA;AAGA,IAAAC,QAAA,GAAAD,OAAA;AAKA,IAAIE,MAAkC;;AAEtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,sBAAsBA,CAAA,EAAmB;EACvD,IAAI,CAACD,MAAM,EAAE;IACX,MAAME,MAAM,GAAGC,qCAAY,CAACC,kBAAkB,CAAoB,mBAAmB,CAAC;IACtFJ,MAAM,GAAG,IAAAK,uBAAc,EAACH,MAAM,CAAC;EACjC;EACA,OAAOF,MAAM;AACf","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ //# sourceMappingURL=ChittieRasterizer.nitro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["specs/ChittieRasterizer.nitro.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Adapt a native `ChittieRasterizer` HybridObject to chittie's `TextRasterizer`.
5
+ * The native side returns an RGBA bitmap (dims already padded to /8); we wrap it
6
+ * as the structural `ImageData` chittie's raster pipeline consumes. Pure and
7
+ * dependency-free at runtime (no Nitro import) — inject `native` so it's testable
8
+ * off-device.
9
+ */
10
+ export function makeRasterizer(native) {
11
+ return {
12
+ rasterize(text, options = {}) {
13
+ const {
14
+ fontSize = 24,
15
+ maxWidth = 576,
16
+ bold = false
17
+ } = options;
18
+ const b = native.rasterize(text, fontSize, maxWidth, !!bold);
19
+ // RGBA, structural ImageData — chittie reads { data, width, height }.
20
+ return {
21
+ data: new Uint8ClampedArray(b.data),
22
+ width: b.width,
23
+ height: b.height,
24
+ colorSpace: 'srgb'
25
+ };
26
+ }
27
+ };
28
+ }
29
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["makeRasterizer","native","rasterize","text","options","fontSize","maxWidth","bold","b","data","Uint8ClampedArray","width","height","colorSpace"],"sourceRoot":"../../src","sources":["adapter.ts"],"mappings":";;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,cAAcA,CAACC,MAAyB,EAAkB;EACxE,OAAO;IACLC,SAASA,CAACC,IAAY,EAAEC,OAAsB,GAAG,CAAC,CAAC,EAAa;MAC9D,MAAM;QAAEC,QAAQ,GAAG,EAAE;QAAEC,QAAQ,GAAG,GAAG;QAAEC,IAAI,GAAG;MAAM,CAAC,GAAGH,OAAO;MAC/D,MAAMI,CAAC,GAAGP,MAAM,CAACC,SAAS,CAACC,IAAI,EAAEE,QAAQ,EAAEC,QAAQ,EAAE,CAAC,CAACC,IAAI,CAAC;MAC5D;MACA,OAAO;QACLE,IAAI,EAAE,IAAIC,iBAAiB,CAACF,CAAC,CAACC,IAAI,CAAC;QACnCE,KAAK,EAAEH,CAAC,CAACG,KAAK;QACdC,MAAM,EAAEJ,CAAC,CAACI,MAAM;QAChBC,UAAU,EAAE;MACd,CAAC;IACH;EACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ import { NitroModules } from 'react-native-nitro-modules';
4
+ import { makeRasterizer } from './adapter.js';
5
+ export { makeRasterizer } from './adapter.js';
6
+ let cached;
7
+
8
+ /**
9
+ * The native chittie rasterizer (CoreText / android.graphics) as a chittie
10
+ * `TextRasterizer` — pass it to `render()` so Sinhala/Tamil/Arabic print on a
11
+ * device without Skia. Requires a dev client / bare RN (native module).
12
+ *
13
+ * ```ts
14
+ * import { createNativeRasterizer } from '@angadie/chittie-react-native';
15
+ * const bytes = render(<Receipt/>, { dotWidth: 384, rasterizer: createNativeRasterizer() });
16
+ * ```
17
+ */
18
+ export function createNativeRasterizer() {
19
+ if (!cached) {
20
+ const native = NitroModules.createHybridObject('ChittieRasterizer');
21
+ cached = makeRasterizer(native);
22
+ }
23
+ return cached;
24
+ }
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["NitroModules","makeRasterizer","cached","createNativeRasterizer","native","createHybridObject"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,4BAA4B;AAGzD,SAASC,cAAc,QAAQ,cAAc;AAE7C,SAASA,cAAc,QAAQ,cAAc;AAG7C,IAAIC,MAAkC;;AAEtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,sBAAsBA,CAAA,EAAmB;EACvD,IAAI,CAACD,MAAM,EAAE;IACX,MAAME,MAAM,GAAGJ,YAAY,CAACK,kBAAkB,CAAoB,mBAAmB,CAAC;IACtFH,MAAM,GAAGD,cAAc,CAACG,MAAM,CAAC;EACjC;EACA,OAAOF,MAAM;AACf","ignoreList":[]}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export {};
4
+ //# sourceMappingURL=ChittieRasterizer.nitro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["specs/ChittieRasterizer.nitro.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,11 @@
1
+ import type { TextRasterizer } from '@angadie/chittie-text';
2
+ import type { ChittieRasterizer } from './specs/ChittieRasterizer.nitro.js';
3
+ /**
4
+ * Adapt a native `ChittieRasterizer` HybridObject to chittie's `TextRasterizer`.
5
+ * The native side returns an RGBA bitmap (dims already padded to /8); we wrap it
6
+ * as the structural `ImageData` chittie's raster pipeline consumes. Pure and
7
+ * dependency-free at runtime (no Nitro import) — inject `native` so it's testable
8
+ * off-device.
9
+ */
10
+ export declare function makeRasterizer(native: ChittieRasterizer): TextRasterizer;
11
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAE5E;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,cAAc,CAcxE"}
@@ -0,0 +1,15 @@
1
+ import type { TextRasterizer } from '@angadie/chittie-text';
2
+ export { makeRasterizer } from './adapter.js';
3
+ export type { ChittieRasterizer, RasterBitmap } from './specs/ChittieRasterizer.nitro.js';
4
+ /**
5
+ * The native chittie rasterizer (CoreText / android.graphics) as a chittie
6
+ * `TextRasterizer` — pass it to `render()` so Sinhala/Tamil/Arabic print on a
7
+ * device without Skia. Requires a dev client / bare RN (native module).
8
+ *
9
+ * ```ts
10
+ * import { createNativeRasterizer } from '@angadie/chittie-react-native';
11
+ * const bytes = render(<Receipt/>, { dotWidth: 384, rasterizer: createNativeRasterizer() });
12
+ * ```
13
+ */
14
+ export declare function createNativeRasterizer(): TextRasterizer;
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAI1F;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,IAAI,cAAc,CAMvD"}
@@ -0,0 +1,23 @@
1
+ import type { HybridObject } from 'react-native-nitro-modules';
2
+ /**
3
+ * An RGBA bitmap. `width`/`height` are padded to multiples of 8 on the native
4
+ * side so chittie's ESC/POS raster packer (`padTo8`) is a no-op.
5
+ */
6
+ export interface RasterBitmap {
7
+ data: ArrayBuffer;
8
+ width: number;
9
+ height: number;
10
+ }
11
+ /**
12
+ * Native text rasterizer — shapes a line with the platform text engine
13
+ * (CoreText on iOS, android.graphics on Android), which handles complex-script
14
+ * shaping (Sinhala/Tamil joining) and bidi (Arabic/Hebrew) for free.
15
+ */
16
+ export interface ChittieRasterizer extends HybridObject<{
17
+ ios: 'swift';
18
+ android: 'kotlin';
19
+ }> {
20
+ /** Render `text` to an RGBA bitmap (black on white), wrapped at `maxWidth` dots. */
21
+ rasterize(text: string, fontSize: number, maxWidth: number, bold: boolean): RasterBitmap;
22
+ }
23
+ //# sourceMappingURL=ChittieRasterizer.nitro.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChittieRasterizer.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/ChittieRasterizer.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IAC1F,oFAAoF;IACpF,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,YAAY,CAAC;CAC1F"}