code wiki / (root) / nx_media_convert.nx

nx_media_convert.nx source

↩ module page · 141 lines · 5930 B

1// nx_media_convert.nx -- the user-facing media CONVERT: a real image FILE in, 2// decode -> selectable-model resample -> encode -> real image FILE out, one call. 3// 4// Composes the existing sovereign decoder + the selectable resampler + the 5// sovereign PNG encoder -- ZERO 3rd-party. This is the literal "upscaling / 6// downscaling when media is converted, with easily selectable models" ask. 7// 8// RUNG: RGB PNG in/out (nx_png_write_rgb is RGB). JPEG input (nx_jpeg_decode) 9// + RGBA/gray channel adaptation = flagged next rung. 10// license_tier: ORIGINAL 11 12import "nx_syscalls.nx" 13import "nx_img_resample.nx" 14import "nx_png_decoder.nx" 15import "nx_png_write.nx" 16import "nx_seg_store.nx" 17import "nx_jpeg_ascii.nx" 18 19// Convert a PNG file to dw x dh using `model`, writing a PNG. Returns 0 ok, 20// negative on error (-1 read, -2 decode, -3 non-RGB, -4 resize, else encode rc). 21func nx_media_convert_png(in_path: *u8, model: i64, dw: i64, dh: i64, out_path: *u8) -> i64 { 22 let szbox: *i64 = sys_mmap(16) as *i64 23 let png: *u8 = ss_readall(in_path, szbox) 24 if szbox[0] <= 0 { return 0 - 1 } 25 let r: *NxPngResult = nx_png_decode(png, szbox[0]) 26 if r.error_code != NX_PNG_OK { return 0 - 2 } 27 if r.n_channels != 3 { return 0 - 3 } 28 let hd: *NxPngHeader = r.header 29 let dst: *u8 = sys_mmap(dw * dh * 3 + 16) 30 if nx_img_resample(model, r.pixels, hd.width, hd.height, 3, dst, dw, dh) != 0 { return 0 - 4 } 31 return nx_png_write_rgb(out_path, dst, dw, dh) 32} 33 34// Adapt decoded pixels (nc: 1=gray, 2=gray+alpha, 3=RGB, 4=RGBA) into 35// interleaved RGB (3ch). Gray replicates to R=G=B; alpha is dropped. 36func nx_img_to_rgb(src: *u8, w: i64, h: i64, nc: i64, dst: *u8) -> i64 { 37 if nc <= 0 { return 0 - 1 } 38 let n: i64 = w * h 39 var i: i64 = 0 40 while i < n { 41 let s: i64 = i * nc 42 let d: i64 = i * 3 43 if nc < 3 { 44 let g: i64 = src[s] as i64 45 dst[d + 0] = g as u8 46 dst[d + 1] = g as u8 47 dst[d + 2] = g as u8 48 } else { 49 dst[d + 0] = src[s + 0] 50 dst[d + 1] = src[s + 1] 51 dst[d + 2] = src[s + 2] 52 } 53 i = i + 1 54 } 55 return 0 56} 57 58// resize decoded interleaved-RGB (w x h) to dw x dh with `model`, write PNG. 59func _mc_finish(rgb: *u8, w: i64, h: i64, model: i64, dw: i64, dh: i64, out_path: *u8) -> i64 { 60 let dst: *u8 = sys_mmap(dw * dh * 3 + 16) 61 if nx_img_resample(model, rgb, w, h, 3, dst, dw, dh) != 0 { return 0 - 4 } 62 return nx_png_write_rgb(out_path, dst, dw, dh) 63} 64 65// Convert a JPEG file to dw x dh using `model`, writing a PNG. 66func nx_media_convert_jpeg(in_path: *u8, model: i64, dw: i64, dh: i64, out_path: *u8) -> i64 { 67 let szbox: *i64 = sys_mmap(16) as *i64 68 let jpg: *u8 = ss_readall(in_path, szbox) 69 if szbox[0] <= 8 { return 0 - 1 } 70 let pp_rgb: *i64 = sys_mmap(8) as *i64 71 let pp_w: *i64 = sys_mmap(8) as *i64 72 let pp_h: *i64 = sys_mmap(8) as *i64 73 if nx_jpeg_decode_rgb(jpg, szbox[0], pp_rgb, pp_w, pp_h) != NX_JPEG_ASCII_OK { return 0 - 5 } 74 return _mc_finish(pp_rgb[0] as *u8, pp_w[0], pp_h[0], model, dw, dh, out_path) 75} 76 77// Unified: sniff PNG vs JPEG by magic bytes, decode, resample (selectable 78// model), encode PNG. Any supported image FILE -> resized PNG. Returns 0 ok, 79// negative on error, -6 = unknown/unsupported format. 80func nx_media_convert_file(in_path: *u8, model: i64, dw: i64, dh: i64, out_path: *u8) -> i64 { 81 let szbox: *i64 = sys_mmap(16) as *i64 82 let buf: *u8 = ss_readall(in_path, szbox) 83 let n: i64 = szbox[0] 84 if n <= 8 { return 0 - 1 } 85 if buf[0] == (137 as u8) { // PNG: 0x89 'P' ... 86 if buf[1] == (80 as u8) { 87 let r: *NxPngResult = nx_png_decode(buf, n) 88 if r.error_code != NX_PNG_OK { return 0 - 2 } 89 if r.n_channels < 1 { return 0 - 3 } 90 let hd: *NxPngHeader = r.header 91 let rgb: *u8 = sys_mmap(hd.width * hd.height * 3 + 16) 92 nx_img_to_rgb(r.pixels, hd.width, hd.height, r.n_channels, rgb) 93 return _mc_finish(rgb, hd.width, hd.height, model, dw, dh, out_path) 94 } 95 } 96 if buf[0] == (255 as u8) { // JPEG: 0xFF 0xD8 97 if buf[1] == (216 as u8) { 98 let pp_rgb: *i64 = sys_mmap(8) as *i64 99 let pp_w: *i64 = sys_mmap(8) as *i64 100 let pp_h: *i64 = sys_mmap(8) as *i64 101 if nx_jpeg_decode_rgb(buf, n, pp_rgb, pp_w, pp_h) != NX_JPEG_ASCII_OK { return 0 - 5 } 102 return _mc_finish(pp_rgb[0] as *u8, pp_w[0], pp_h[0], model, dw, dh, out_path) 103 } 104 } 105 return 0 - 6 106} 107 108// Demo: build a sharp 4-quadrant RGB image, encode to a real PNG, then convert 109// that FILE two ways (NEAREST vs BICUBIC) so model selection is visible. 110func main() -> i64 { 111 let sw: i64 = 24 112 let sh: i64 = 24 113 let src: *u8 = sys_mmap(sw * sh * 3 + 16) 114 var y: i64 = 0 115 while y < sh { 116 var x: i64 = 0 117 while x < sw { 118 let o: i64 = (y * sw + x) * 3 119 var rr: i64 = 0 120 var gg: i64 = 0 121 var bb: i64 = 0 122 if y < 12 { 123 if x < 12 { rr = 255 } else { gg = 255 } // TL red, TR green 124 } else { 125 if x < 12 { bb = 255 } else { rr = 255; gg = 255 } // BL blue, BR yellow 126 } 127 src[o + 0] = rr as u8 128 src[o + 1] = gg as u8 129 src[o + 2] = bb as u8 130 x = x + 1 131 } 132 y = y + 1 133 } 134 let srcpath: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/_sv_mc_src.png" as *u8 135 if nx_png_write_rgb(srcpath, src, sw, sh) != 0 { return 1 } 136 137 // convert the FILE 5x two ways 138 if nx_media_convert_png(srcpath, NX_RS_NEAREST, 120, 120, "/mnt/c/Users/elder/nishi-core/nxc2/_sv_mc_near.png" as *u8) != 0 { return 2 } 139 if nx_media_convert_png(srcpath, NX_RS_BICUBIC, 120, 120, "/mnt/c/Users/elder/nishi-core/nxc2/_sv_mc_cubic.png" as *u8) != 0 { return 3 } 140 return 0 141}