4
4
// libsixel (C/C++) - https://github.com/saitoha/libsixel
5
5
// Copyright (c) 2014-2016 Hayaki Saito @license MIT
6
6
7
- using Terminal . Gui ;
8
-
9
7
namespace Terminal . Gui ;
10
8
11
9
/// <summary>
12
- /// Encodes a images into the sixel console image output format.
10
+ /// Encodes a images into the sixel console image output format.
13
11
/// </summary>
14
12
public class SixelEncoder
15
13
{
@@ -35,32 +33,29 @@ e.g. to draw more color layers.
35
33
36
34
*/
37
35
38
-
39
36
/// <summary>
40
- /// Gets or sets the quantizer responsible for building a representative
41
- /// limited color palette for images and for mapping novel colors in
42
- /// images to their closest palette color
37
+ /// Gets or sets the quantizer responsible for building a representative
38
+ /// limited color palette for images and for mapping novel colors in
39
+ /// images to their closest palette color
43
40
/// </summary>
44
41
public ColorQuantizer Quantizer { get ; set ; } = new ( ) ;
45
42
46
43
/// <summary>
47
- /// Encode the given bitmap into sixel encoding
44
+ /// Encode the given bitmap into sixel encoding
48
45
/// </summary>
49
46
/// <param name="pixels"></param>
50
47
/// <returns></returns>
51
48
public string EncodeSixel ( Color [ , ] pixels )
52
49
{
53
-
54
50
const string start = "\u001b P" ; // Start sixel sequence
55
51
56
-
57
- string defaultRatios = this . AnyHasAlphaOfZero ( pixels ) ? "0;1;0" : "0;0;0" ; // Defaults for aspect ratio and grid size
52
+ string defaultRatios = AnyHasAlphaOfZero ( pixels ) ? "0;1;0" : "0;0;0" ; // Defaults for aspect ratio and grid size
58
53
const string completeStartSequence = "q" ; // Signals beginning of sixel image data
59
54
const string noScaling = "\" 1;1;" ; // no scaling factors (1x1);
60
55
61
56
string fillArea = GetFillArea ( pixels ) ;
62
57
63
- string pallette = GetColorPalette ( pixels ) ;
58
+ string pallette = GetColorPalette ( pixels ) ;
64
59
65
60
string pixelData = WriteSixel ( pixels ) ;
66
61
@@ -71,15 +66,14 @@ public string EncodeSixel (Color [,] pixels)
71
66
72
67
private string WriteSixel ( Color [ , ] pixels )
73
68
{
74
-
75
- StringBuilder sb = new StringBuilder ( ) ;
69
+ var sb = new StringBuilder ( ) ;
76
70
int height = pixels . GetLength ( 1 ) ;
77
71
int width = pixels . GetLength ( 0 ) ;
78
72
79
73
// Iterate over each 'row' of the image. Because each sixel write operation
80
74
// outputs a screen area 6 pixels high (and 1+ across) we must process the image
81
75
// 6 'y' units at once (1 band)
82
- for ( int y = 0 ; y < height ; y += 6 )
76
+ for ( var y = 0 ; y < height ; y += 6 )
83
77
{
84
78
sb . Append ( ProcessBand ( pixels , y , Math . Min ( 6 , height - y ) , width ) ) ;
85
79
@@ -107,69 +101,45 @@ private string ProcessBand (Color [,] pixels, int startY, int bandHeight, int wi
107
101
Array . Fill ( accu , ( ushort ) 1 ) ;
108
102
Array . Fill ( slots , ( short ) - 1 ) ;
109
103
110
- var usedColorIdx = new List < int > ( ) ;
111
- var targets = new List < List < string > > ( ) ;
104
+ List < int > usedColorIdx = new List < int > ( ) ;
105
+ List < List < string > > targets = new List < List < string > > ( ) ;
112
106
113
107
// Process columns within the band
114
- for ( int x = 0 ; x < width ; ++ x )
108
+ for ( var x = 0 ; x < width ; ++ x )
115
109
{
116
110
Array . Clear ( code , 0 , usedColorIdx . Count ) ;
117
- bool anyNonTransparentPixel = false ; // Track if any non-transparent pixels are found in this column
118
111
119
112
// Process each row in the 6-pixel high band
120
- for ( int row = 0 ; row < bandHeight ; ++ row )
113
+ for ( var row = 0 ; row < bandHeight ; ++ row )
121
114
{
122
- var color = pixels [ x , startY + row ] ;
115
+ Color color = pixels [ x , startY + row ] ;
123
116
124
117
int colorIndex = Quantizer . GetNearestColor ( color ) ;
125
118
126
119
if ( color . A == 0 ) // Skip fully transparent pixels
127
120
{
128
121
continue ;
129
122
}
130
- else
131
- {
132
- anyNonTransparentPixel = true ;
133
- }
134
123
135
124
if ( slots [ colorIndex ] == - 1 )
136
125
{
137
- targets . Add ( new List < string > ( ) ) ;
126
+ targets . Add ( new ( ) ) ;
127
+
138
128
if ( x > 0 )
139
129
{
140
130
last [ usedColorIdx . Count ] = 0 ;
141
131
accu [ usedColorIdx . Count ] = ( ushort ) x ;
142
132
}
133
+
143
134
slots [ colorIndex ] = ( short ) usedColorIdx . Count ;
144
135
usedColorIdx . Add ( colorIndex ) ;
145
136
}
146
137
147
138
code [ slots [ colorIndex ] ] |= ( byte ) ( 1 << row ) ; // Accumulate SIXEL data
148
139
}
149
140
150
- /*
151
- // If no non-transparent pixels are found in the entire column, it's fully transparent
152
- if (!anyNonTransparentPixel)
153
- {
154
- // Emit fully transparent pixel data: #0!<width>?$
155
- result.Append ($"#0!{width}?");
156
-
157
- // Add the line terminator: use "$-" if it's not the last line, "$" if it's the last line
158
- if (x < width - 1)
159
- {
160
- result.Append ("$-");
161
- }
162
- else
163
- {
164
- result.Append ("$");
165
- }
166
-
167
- // Skip to the next column as we have already handled transparency
168
- continue;
169
- }*/
170
-
171
141
// Handle transitions between columns
172
- for ( int j = 0 ; j < usedColorIdx . Count ; ++ j )
142
+ for ( var j = 0 ; j < usedColorIdx . Count ; ++ j )
173
143
{
174
144
if ( code [ j ] == last [ j ] )
175
145
{
@@ -181,14 +151,15 @@ private string ProcessBand (Color [,] pixels, int startY, int bandHeight, int wi
181
151
{
182
152
targets [ j ] . Add ( CodeToSixel ( last [ j ] , accu [ j ] ) ) ;
183
153
}
154
+
184
155
last [ j ] = ( sbyte ) code [ j ] ;
185
156
accu [ j ] = 1 ;
186
157
}
187
158
}
188
159
}
189
160
190
161
// Process remaining data for this band
191
- for ( int j = 0 ; j < usedColorIdx . Count ; ++ j )
162
+ for ( var j = 0 ; j < usedColorIdx . Count ; ++ j )
192
163
{
193
164
if ( last [ j ] != 0 )
194
165
{
@@ -198,7 +169,8 @@ private string ProcessBand (Color [,] pixels, int startY, int bandHeight, int wi
198
169
199
170
// Build the final output for this band
200
171
var result = new StringBuilder ( ) ;
201
- for ( int j = 0 ; j < usedColorIdx . Count ; ++ j )
172
+
173
+ for ( var j = 0 ; j < usedColorIdx . Count ; ++ j )
202
174
{
203
175
result . Append ( $ "#{ usedColorIdx [ j ] } { string . Join ( "" , targets [ j ] ) } $") ;
204
176
}
@@ -208,27 +180,42 @@ private string ProcessBand (Color [,] pixels, int startY, int bandHeight, int wi
208
180
209
181
private static string CodeToSixel ( int code , int repeat )
210
182
{
211
- char c = ( char ) ( code + 63 ) ;
212
- if ( repeat > 3 ) return "!" + repeat + c ;
213
- if ( repeat == 3 ) return c . ToString ( ) + c + c ;
214
- if ( repeat == 2 ) return c . ToString ( ) + c ;
183
+ var c = ( char ) ( code + 63 ) ;
184
+
185
+ if ( repeat > 3 )
186
+ {
187
+ return "!" + repeat + c ;
188
+ }
189
+
190
+ if ( repeat == 3 )
191
+ {
192
+ return c . ToString ( ) + c + c ;
193
+ }
194
+
195
+ if ( repeat == 2 )
196
+ {
197
+ return c . ToString ( ) + c ;
198
+ }
199
+
215
200
return c . ToString ( ) ;
216
201
}
217
202
218
203
private string GetColorPalette ( Color [ , ] pixels )
219
204
{
220
205
Quantizer . BuildPalette ( pixels ) ;
221
206
222
- StringBuilder paletteSb = new StringBuilder ( ) ;
207
+ var paletteSb = new StringBuilder ( ) ;
223
208
224
- for ( int i = 0 ; i < Quantizer . Palette . Count ; i ++ )
209
+ for ( var i = 0 ; i < Quantizer . Palette . Count ; i ++ )
225
210
{
226
- var color = Quantizer . Palette . ElementAt ( i ) ;
227
- paletteSb . AppendFormat ( "#{0};2;{1};{2};{3}" ,
228
- i ,
229
- color . R * 100 / 255 ,
230
- color . G * 100 / 255 ,
231
- color . B * 100 / 255 ) ;
211
+ Color color = Quantizer . Palette . ElementAt ( i ) ;
212
+
213
+ paletteSb . AppendFormat (
214
+ "#{0};2;{1};{2};{3}" ,
215
+ i ,
216
+ color . R * 100 / 255 ,
217
+ color . G * 100 / 255 ,
218
+ color . B * 100 / 255 ) ;
232
219
}
233
220
234
221
return paletteSb . ToString ( ) ;
@@ -241,15 +228,16 @@ private string GetFillArea (Color [,] pixels)
241
228
242
229
return $ "{ widthInChars } ;{ heightInChars } ";
243
230
}
231
+
244
232
private bool AnyHasAlphaOfZero ( Color [ , ] pixels )
245
233
{
246
234
int width = pixels . GetLength ( 0 ) ;
247
235
int height = pixels . GetLength ( 1 ) ;
248
236
249
237
// Loop through each pixel in the 2D array
250
- for ( int x = 0 ; x < width ; x ++ )
238
+ for ( var x = 0 ; x < width ; x ++ )
251
239
{
252
- for ( int y = 0 ; y < height ; y ++ )
240
+ for ( var y = 0 ; y < height ; y ++ )
253
241
{
254
242
// Check if the alpha component (A) is 0
255
243
if ( pixels [ x , y ] . A == 0 )
@@ -258,6 +246,7 @@ private bool AnyHasAlphaOfZero (Color [,] pixels)
258
246
}
259
247
}
260
248
}
249
+
261
250
return false ; // No pixel with A of 0 was found
262
251
}
263
- }
252
+ }
0 commit comments