1
- import osproc, os, streams, pixie, json, options, strutils, strformat
1
+ import osproc, os, streams, pixie, json, options, strutils, strformat, locks
2
2
import frameos/ types
3
3
import frameos/ utils/ dither
4
+ import frameos/ utils/ image
4
5
5
6
type ScreenInfo * = object
6
7
width* : int
@@ -16,6 +17,25 @@ type Driver* = ref object of FrameOSDriver
16
17
lastImageData: seq [ColorRGBX ]
17
18
debug: bool
18
19
20
+ var
21
+ lastPixelsLock: Lock
22
+ lastPixels: seq [uint8 ] = @ []
23
+ lastWidth: int
24
+ lastHeight: int
25
+
26
+ proc setLastPixels * (image: seq [uint8 ], width: int , height: int ) =
27
+ withLock lastPixelsLock:
28
+ lastPixels = image
29
+ lastWidth = width
30
+ lastHeight = height
31
+
32
+ proc getLastPixels * (): seq [uint8 ] =
33
+ withLock lastPixelsLock:
34
+ result = lastPixels
35
+
36
+ proc notifyImageAvailable * (self: Driver ) =
37
+ self.logger.log (%* {" event" : " render:dither" , " info" : " Dithered image available" })
38
+
19
39
proc safeLog (logger: Logger , message: string ): JsonNode =
20
40
try :
21
41
result = parseJson (message)
@@ -41,21 +61,6 @@ proc safeStartProcess*(cmd: string; args: seq[string] = @[];
41
61
proc deviceArgs (dev: string ): seq [string ] =
42
62
if dev.len > 0 : @ [" --device" , dev] else : @ []
43
63
44
- proc paletteArgs (p: PaletteConfig , device: string ): seq [string ] =
45
- if p != nil and p.colors.len > 0 :
46
- let arr = newJArray ()
47
- for (r, g, b) in p.colors:
48
- arr.add ( %* [r, g, b])
49
- @ [" --palette" , $ arr]
50
- elif device == " pimoroni.inky_impression_7" or device == " pimoroni.inky_impression_13" :
51
- let arr = newJArray ()
52
- for (r, g, b) in spectra6ColorPalette:
53
- if r < 256 and b < 256 and g < 256 :
54
- arr.add ( %* [r, g, b])
55
- @ [" --palette" , $ arr]
56
- else :
57
- @ []
58
-
59
64
proc init * (frameOS: FrameOS ): Driver =
60
65
discard frameOS.logger.safeLog (" Initializing Inky driver" )
61
66
@@ -120,16 +125,39 @@ proc render*(self: Driver, image: Image) =
120
125
discard self.logger.safeLog (" Skipping render. Identical to last render." )
121
126
return
122
127
self.lastImageData = image.data
123
- let imageData = image.encodeImage (BmpFormat )
128
+
129
+ var imageData: seq [uint8 ]
130
+ var extraArgs: seq [string ] = @ []
131
+ if self.device == " pimoroni.inky_impression_7" or self.device == " pimoroni.inky_impression_13" :
132
+ var palette: seq [(int , int , int )]
133
+ if self.palette != nil and self.palette.colors.len > 0 :
134
+ let c = self.palette.colors
135
+ palette = @ [
136
+ (c[0 ][0 ], c[0 ][1 ], c[0 ][2 ]),
137
+ (c[1 ][0 ], c[1 ][1 ], c[1 ][2 ]),
138
+ (c[2 ][0 ], c[2 ][1 ], c[2 ][2 ]),
139
+ (c[3 ][0 ], c[3 ][1 ], c[3 ][2 ]),
140
+ (999 , 999 , 999 ),
141
+ (c[4 ][0 ], c[4 ][1 ], c[4 ][2 ]),
142
+ (c[5 ][0 ], c[5 ][1 ], c[5 ][2 ]),
143
+ ]
144
+ else :
145
+ palette = spectra6ColorPalette
146
+ imageData = ditherPaletteIndexed (image, palette)
147
+ setLastPixels (imageData, image.width, image.height)
148
+ self.notifyImageAvailable ()
149
+ extraArgs.add " --raw"
150
+ else :
151
+ imageData = cast [seq [uint8 ]](image.encodeImage (BmpFormat ))
124
152
125
153
let pOpt =
126
154
if self.mode == " nixos" :
127
155
safeStartProcess (" /nix/var/nix/profiles/system/sw/bin/inkyPython-run" ,
128
- deviceArgs (self.device) & paletteArgs (self.palette, self.device) ,
156
+ deviceArgs (self.device) & extraArgs ,
129
157
" /srv/frameos/vendor/inkyPython" , self.logger)
130
158
else :
131
159
safeStartProcess (" ./env/bin/python3" ,
132
- @ [" run.py" ] & deviceArgs (self.device) & paletteArgs (self.palette, self.device) ,
160
+ @ [" run.py" ] & deviceArgs (self.device) & extraArgs ,
133
161
" /srv/frameos/vendor/inkyPython" , self.logger)
134
162
135
163
if pOpt.isNone:
@@ -186,3 +214,28 @@ proc render*(self: Driver, image: Image) =
186
214
discard self.logger.safeLog (line)
187
215
188
216
process.close ()
217
+
218
+ # Convert the rendered pixels to a PNG image. For accurate colors on the web.
219
+ proc toPng * (rotate: int = 0 ): string =
220
+ let width = lastWidth
221
+ let height = lastHeight
222
+ var outputImage = newImage (width, height)
223
+
224
+ let pixels = getLastPixels ()
225
+ if pixels.len == 0 :
226
+ raise newException (Exception , " No render yet" )
227
+ for y in 0 ..< height:
228
+ for x in 0 ..< width:
229
+ let index = y * width + x
230
+ let pixelIndex = index div 2
231
+ let pixelShift = (1 - (index mod 2 )) * 4
232
+ let pixel = (pixels[pixelIndex] shr pixelShift) and 0x 07
233
+ outputImage.data[index].r = spectra6ColorPalette[pixel][0 ].uint8
234
+ outputImage.data[index].g = spectra6ColorPalette[pixel][1 ].uint8
235
+ outputImage.data[index].b = spectra6ColorPalette[pixel][2 ].uint8
236
+ outputImage.data[index].a = 255
237
+
238
+ if rotate != 0 :
239
+ return outputImage.rotateDegrees (rotate).encodeImage (PngFormat )
240
+
241
+ return outputImage.encodeImage (PngFormat )
0 commit comments