1use sixel::*;
2use status;
3use optflags;
4use pixelformat::{Pixel, PixelFormatChan};
5
6use std::cell::Cell;
7use status::Status;
8use std::os::raw;
9use std::path::Path;
10
11pub struct Encoder {
12 encoder: *mut sixel::Encoder,
13}
14
15impl Encoder {
16 pub fn new() -> Status<Encoder> {
17 use std::ptr;
18
19 let mut encoder: *mut sixel::Encoder = ptr::null_mut() as *mut _;
20
21 unsafe {
22 let result = sixel_encoder_new(&mut encoder,
23 ptr::null_mut() as *mut Allocator);
24
25 status::from_libsixel(result)?;
26 }
27
28
29 Ok(Encoder { encoder })
30 }
31
32 #[deprecated]
33 pub fn create() -> Encoder {
34 let encoder;
35 unsafe {
36 encoder = sixel_encoder_create();
37 }
38
39 Encoder { encoder }
40
41 }
42
43 pub fn encode_file(&self, source: &Path) -> Status<()> {
44 use msc;
45
46 let cstr = msc::path_to_c_str(source)?;
47
48 let result = unsafe { sixel_encoder_encode(self.encoder, cstr.as_ptr()) };
49 status::from_libsixel(result)
50 }
51
52 pub fn encode_bytes(&self, frame: QuickFrame) -> Status<()> {
53 use std::os::raw::c_int;
54 use std::os::raw::c_uchar;
55
56 let palette: Vec<crate::pixelformat::Color3> = vec![];
58
59 let result = unsafe {
60 sixel_encoder_encode_bytes(self.encoder,
61 frame.pixels.as_ptr() as *mut c_uchar,
62 frame.width as c_int,
63 frame.height as c_int,
64 frame.format,
65 palette.as_ptr() as *mut c_uchar,
66 palette.len() as c_int)
67 };
68 status::from_libsixel(result)
69 }
70}
71
72impl Encoder {
74 pub fn set_cancel(&self, cancel: Canceller) -> Status<()> {
75 let result =
76 unsafe { sixel_encoder_set_cancel_flag(self.encoder, (&cancel.flag).as_ptr()) };
77 status::from_libsixel(result)
78 }
79
80 fn set_opt(&self, opt: Optflag, arg: *const raw::c_char) -> Status<()> {
81 let result = unsafe { sixel_encoder_setopt(self.encoder, opt, arg) };
82 status::from_libsixel(result)
83 }
84
85 pub fn set_output(&self, file: &Path) -> Status<()> {
86 use msc;
87
88 let cstr = msc::path_to_c_str(file)?;
89
90 self.set_opt(Optflag::OutFile, cstr.as_ptr())
91 }
92
93 pub fn set_bit_mode(&self, mode: optflags::BitMode) -> Status<()> {
94 use std::ptr;
95 use optflags::BitMode;
96
97 let mode_flag = match mode {
98 BitMode::SevenBit => Optflag::UseSevenBitMode,
99 BitMode::EightBit => Optflag::UseEightBitMode,
100 };
101
102 self.set_opt(mode_flag, ptr::null())
103 }
104
105 pub fn enable_gri_arg_limit(&self) -> Status<()> {
106 use std::ptr;
107
108 self.set_opt(Optflag::HasGRIArgLimit, ptr::null())
109 }
110
111 pub fn set_num_colors_str(&self, num_colors: &str) -> Status<()> {
112 use std::ffi::CString;
113
114 let cstr = match CString::new(num_colors.as_bytes()) {
115 Ok(s) => s,
116 Err(_) => return Err(status::Error::BadArgument),
117 };
118
119 self.set_opt(Optflag::NumColors, cstr.as_ptr())
120 }
121
122 pub fn set_num_colors(&self, num_colors: u8) -> Status<()> {
124 self.set_num_colors_str(&num_colors.to_string())
125 }
126
127 pub fn set_color_option<'a>(&self, option: optflags::ColorOption<'a>) -> Status<()> {
128 use optflags::ColorOption::*;
129 match option {
130 Monochrome => self.use_monochrome(),
131 Builtin(palette) => self.use_builtin_palette(palette),
132 Mapfile(file) => self.use_mapfile(file),
133 Highcolor => self.use_high_color(),
134
135 }
136 }
137
138 fn use_mapfile(&self, file: &Path) -> Status<()> {
139 use msc;
140
141 let cstr = msc::path_to_c_str(file)?;
142
143 self.set_opt(Optflag::Mapfile, cstr.as_ptr())
144 }
145
146 fn use_monochrome(&self) -> Status<()> {
147 use std::ptr;
148
149 self.set_opt(Optflag::Monochrome, ptr::null())
150 }
151
152 fn use_high_color(&self) -> Status<()> {
153 use std::ptr;
154
155 self.set_opt(Optflag::UseHighColor, ptr::null())
156 }
157
158 fn use_builtin_palette(&self, option: &str) -> Status<()> {
159 use std::ffi::CString;
160
161 let cstr = match CString::new(option.as_bytes()) {
162 Ok(s) => s,
163 Err(_) => return Err(status::Error::BadArgument),
164 };
165
166 self.set_opt(Optflag::BuiltinPalette, cstr.as_ptr())
167 }
168
169 pub fn set_diffusion_str(&self, method: &str) -> Status<()> {
170 use std::ffi::CString;
171
172 let cstr = match CString::new(method.as_bytes()) {
173 Ok(s) => s,
174 Err(_) => return Err(status::Error::BadArgument),
175 };
176
177 self.set_opt(Optflag::Diffusion, cstr.as_ptr())
178 }
179
180 pub fn set_diffusion(&self, method: optflags::DiffusionMethod) -> Status<()> {
181 self.set_diffusion_str(method.to_str())
182 }
183
184 pub fn set_find_largest_str(&self, option: &str) -> Status<()> {
185 use std::ffi::CString;
186
187 let cstr = match CString::new(option.as_bytes()) {
188 Ok(s) => s,
189 Err(_) => return Err(status::Error::BadArgument),
190 };
191
192 self.set_opt(Optflag::FindLargest, cstr.as_ptr())
193 }
194
195 pub fn set_find_largest(&self, opt: optflags::FindLargestOpt) -> Status<()> {
196 self.set_find_largest_str(opt.to_str())
197 }
198
199 pub fn set_color_select_str(&self, opt: &str) -> Status<()> {
200 use std::ffi::CString;
201
202 let cstr = match CString::new(opt.as_bytes()) {
203 Ok(s) => s,
204 Err(_) => return Err(status::Error::BadArgument),
205 };
206
207 self.set_opt(Optflag::SelectColor, cstr.as_ptr())
208 }
209
210 pub fn set_color_select(&self, meth: optflags::ColorSelectionMethod) -> Status<()> {
211 self.set_color_select_str(meth.to_str())
212 }
213
214 pub fn set_crop_str(&self, crop: &str) -> Status<()> {
215 use std::ffi::CString;
216
217 let cstr = match CString::new(crop.as_bytes()) {
218 Ok(s) => s,
219 Err(_) => return Err(status::Error::BadArgument),
220 };
221
222 self.set_opt(Optflag::CropRegion, cstr.as_ptr())
223 }
224
225 pub fn set_crop(&self, width: i64, height: i64, x: i64, y: i64) -> Status<()> {
226 let crop_str = format!("{}x{}+{}+{}", width, height, x, y);
227 self.set_crop_str(&crop_str)
228 }
229
230 pub fn set_width_str(&self, width: &str) -> Status<()> {
231 use std::ffi::CString;
232
233 let cstr = match CString::new(width.as_bytes()) {
234 Ok(s) => s,
235 Err(_) => return Err(status::Error::BadArgument),
236 };
237
238 self.set_opt(Optflag::Width, cstr.as_ptr())
239 }
240
241 pub fn set_width(&self, width: optflags::SizeSpecification) -> Status<()> {
242 self.set_width_str(&width.to_string())
243 }
244
245 pub fn set_height_str(&self, height: &str) -> Status<()> {
246 use std::ffi::CString;
247
248 let cstr = match CString::new(height.as_bytes()) {
249 Ok(s) => s,
250 Err(_) => return Err(status::Error::BadArgument),
251 };
252
253 self.set_opt(Optflag::Height, cstr.as_ptr())
254 }
255
256 pub fn set_height(&self, height: optflags::SizeSpecification) -> Status<()> {
257 self.set_height_str(&height.to_string())
258 }
259
260 pub fn set_resampling_str(&self, meth: &str) -> Status<()> {
261 use std::ffi::CString;
262
263 let cstr = match CString::new(meth.as_bytes()) {
264 Ok(s) => s,
265 Err(_) => return Err(status::Error::BadArgument),
266 };
267
268 self.set_opt(Optflag::Resampling, cstr.as_ptr())
269 }
270
271 pub fn set_resampling(&self, meth: optflags::ResampleMethod) -> Status<()> {
272 self.set_resampling_str(meth.to_str())
273 }
274
275 pub fn set_quality_str(&self, opt: &str) -> Status<()> {
276 use std::ffi::CString;
277
278 let cstr = match CString::new(opt.as_bytes()) {
279 Ok(s) => s,
280 Err(_) => return Err(status::Error::BadArgument),
281 };
282
283 self.set_opt(Optflag::QualityMode, cstr.as_ptr())
284 }
285
286 pub fn set_quality(&self, opt: optflags::Quality) -> Status<()> {
287 self.set_quality_str(opt.to_str())
288 }
289
290 pub fn set_loopmode_str(&self, mode: &str) -> Status<()> {
291 use std::ffi::CString;
292
293 let cstr = match CString::new(mode.as_bytes()) {
294 Ok(s) => s,
295 Err(_) => return Err(status::Error::BadArgument),
296 };
297
298 self.set_opt(Optflag::LoopMode, cstr.as_ptr())
299 }
300
301 pub fn set_loopmode(&self, mode: optflags::LoopMode) -> Status<()> {
302 self.set_loopmode_str(mode.to_str())
303 }
304
305 pub fn set_palette_type_str(&self, opt: &str) -> Status<()> {
306 use std::ffi::CString;
307
308 let cstr = match CString::new(opt.as_bytes()) {
309 Ok(s) => s,
310 Err(_) => return Err(status::Error::BadArgument),
311 };
312
313 self.set_opt(Optflag::PaletteType, cstr.as_ptr())
314 }
315
316 pub fn set_palette_type(&self, opt: optflags::PaletteType) -> Status<()> {
317 self.set_palette_type_str(opt.to_str())
318 }
319
320 pub fn set_background_color_str(&self, color: &str) -> Status<()> {
321 use std::ffi::CString;
322
323 let cstr = match CString::new(color.as_bytes()) {
324 Ok(s) => s,
325 Err(_) => return Err(status::Error::BadArgument),
326 };
327
328 self.set_opt(Optflag::BackgroundColor, cstr.as_ptr())
329 }
330
331 pub fn set_background_color(&self, red: u8, green: u8, blue: u8) -> Status<()> {
332 let color_str = format!("#{:0>3}{:0>3}{:0>3}", red, green, blue);
333
334 self.set_background_color_str(&color_str)
335 }
336
337 pub fn use_insecure(&self) -> Status<()> {
338 use std::ptr;
339
340 self.set_opt(Optflag::Insecure, ptr::null())
341 }
342
343 pub fn use_invert(&self) -> Status<()> {
344 use std::ptr;
345
346 self.set_opt(Optflag::InvertBackground, ptr::null())
347 }
348
349 pub fn use_macro(&self) -> Status<()> {
350 use std::ptr;
351
352 self.set_opt(Optflag::UseMacro, ptr::null())
353 }
354
355 pub fn set_macro_number_str(&self, num: &str) -> Status<()> {
356 use std::ffi::CString;
357
358 let cstr = match CString::new(num.as_bytes()) {
359 Ok(s) => s,
360 Err(_) => return Err(status::Error::BadArgument),
361 };
362
363 self.set_opt(Optflag::UseMacro, cstr.as_ptr())
364 }
365
366 pub fn set_macro_number(&self, num: i64) -> Status<()> {
367 let num_str = format!("{}", num);
368 self.set_macro_number_str(&num_str)
369 }
370
371 pub fn ignore_delay(&self) -> Status<()> {
372 use std::ptr;
373
374 self.set_opt(Optflag::IgnoreGIFDelay, ptr::null())
375 }
376
377 pub fn use_verbose(&self) -> Status<()> {
378 use std::ptr;
379
380 self.set_opt(Optflag::Verbose, ptr::null())
381 }
382
383 pub fn use_static(&self) -> Status<()> {
384 use std::ptr;
385
386 self.set_opt(Optflag::StaticGIF, ptr::null())
387 }
388
389 pub fn use_penetrate(&self) -> Status<()> {
390 use std::ptr;
391
392 self.set_opt(Optflag::PenetrateScreen, ptr::null())
393 }
394
395 pub fn set_encode_policy_str(&self, pol: &str) -> Status<()> {
396 use std::ffi::CString;
397
398 let cstr = match CString::new(pol.as_bytes()) {
399 Ok(s) => s,
400 Err(_) => return Err(status::Error::BadArgument),
401 };
402
403 self.set_opt(Optflag::EncodingPolicy, cstr.as_ptr())
404 }
405
406 pub fn set_encode_policy(&self, pol: optflags::EncodePolicy) -> Status<()> {
407 self.set_encode_policy_str(pol.to_str())
408 }
409
410 pub fn set_complexion_score_str(&self, score: &str) -> Status<()> {
411 use std::ffi::CString;
412
413 let cstr = match CString::new(score.as_bytes()) {
414 Ok(s) => s,
415 Err(_) => return Err(status::Error::BadArgument),
416 };
417
418 self.set_opt(Optflag::ComplexionScore, cstr.as_ptr())
419 }
420
421 pub fn set_complexion_score(&self, score: i64) -> Status<()> {
422 let score_str = format!("{}", score);
423 self.set_complexion_score_str(&score_str)
424 }
425
426 pub fn use_pipe_mode(&self) -> Status<()> {
427 use std::ptr;
428
429 self.set_opt(Optflag::PipeInput, ptr::null())
430 }
431}
432
433impl Clone for Encoder {
434 fn clone(&self) -> Encoder {
435 unsafe {
436 sixel_encoder_ref(self.encoder);
437 }
438
439 Encoder { encoder: self.encoder }
440 }
441}
442
443impl Drop for Encoder {
444 fn drop(&mut self) {
445 unsafe {
446 sixel_encoder_unref(self.encoder);
447 }
448 }
449}
450
451
452pub struct Canceller {
454 flag: Box<Cell<raw::c_int>>,
455}
456
457impl Canceller {
458 pub fn new() -> Canceller {
459 let flag: Box<Cell<raw::c_int>> = Box::new(Cell::new(0));
460 Canceller { flag }
467 }
468
469 pub fn cancel(&self) {
470 self.flag.set(1);
471 }
475
476 pub fn reset(&self) {
477 self.flag.set(0);
478 }
482}
483
484pub struct QuickFrameBuilder {
493 width: usize,
494 height: usize,
495 format: PixelFormat,
496}
497
498impl QuickFrameBuilder {
499 pub fn new() -> QuickFrameBuilder {
500 QuickFrameBuilder {
501 width: 0,
502 height: 0,
503 format: PixelFormat::RGB888,
504 }
505 }
506
507 pub fn width(mut self, width: usize) -> QuickFrameBuilder {
508 self.width = width;
509 self
510 }
511 pub fn height(mut self, height: usize) -> QuickFrameBuilder {
512 self.height = height;
513 self
514 }
515 pub fn format(mut self, format: PixelFormat) -> QuickFrameBuilder {
516 self.format = format;
517 self
518 }
519
520 pub fn finalize(self) -> QuickFrame {
521 let depth = self.format.channels_per_pixel() as usize;
522 let size = self.width * self.height * depth;
523 let pixels: Vec<u8> = Vec::with_capacity(size);
524
525 QuickFrame {
526 width: self.width,
527 height: self.height,
528 format: self.format,
529 pixels,
530 }
531 }
532 pub fn pixels(self, pixels: Vec<u8>) -> QuickFrame {
533 let depth = self.format.channels_per_pixel() as usize;
534 let size = self.width * self.height * depth;
535
536 assert_eq!(size, pixels.len());
537
538 QuickFrame {
539 width: self.width,
540 height: self.height,
541 format: self.format,
542 pixels,
543 }
544 }
545}
546
547pub struct QuickFrame {
548 pixels: Vec<u8>,
549 width: usize,
550 height: usize,
551 format: PixelFormat,
552}
553
554impl QuickFrame {
555 pub fn row(&self, row: usize) -> &[u8] {
556 let row_len = self.width * self.format.channels_per_pixel() as usize;
557
558 let row_start = (row - 1) * row_len;
559 let next_row_start = row * row_len;
560
561 &self.pixels[row_start..next_row_start]
562 }
563 pub fn row_mut(&mut self, row: usize) -> &mut [u8] {
564 let row_len = self.width * self.format.channels_per_pixel() as usize;
565
566 let row_start = (row - 1) * row_len;
567 let next_row_start = row * row_len;
568
569 &mut self.pixels[row_start..next_row_start]
570 }
571
572 pub fn pixel(&self, row: usize, column: usize) -> &[u8] {
573 let depth = self.format.channels_per_pixel() as usize;
574 let row_len = self.width * depth;
575
576 let row_start = (row - 1) * row_len;
577 let col_pos = column * depth;
578
579 let start = row_start + col_pos;
580 let end = start + depth;
581
582 &self.pixels[start..end]
583 }
584
585 pub fn pixel_mut(&mut self, row: usize, column: usize) -> &mut [u8] {
586 let depth = self.format.channels_per_pixel() as usize;
587 let row_len = self.width * depth;
588
589 let row_start = (row - 1) * row_len;
590 let col_pos = column * depth;
591
592 let start = row_start + col_pos;
593 let end = start + depth;
594
595 &mut self.pixels[start..end]
596 }
597
598 pub fn color(&self, row: usize, column: usize, depth: usize) -> u8 {
599 let pix_depth = self.format.channels_per_pixel() as usize;
600
601 assert!(depth < pix_depth,
602 "Gave a depth of {} when a pixel is only {} bytes deep",
603 depth,
604 pix_depth);
605
606 let row_len = self.width * pix_depth;
607
608 let row_start = (row - 1) * row_len;
609 let col_pos = column * pix_depth;
610
611 self.pixels[row_start + col_pos + depth]
612 }
613
614 pub fn set_color(&mut self, row: usize, column: usize, depth: usize, color: u8) {
615 let pix_depth = self.format.channels_per_pixel() as usize;
616
617 assert!(depth < pix_depth,
618 "Gave a depth of {} when a pixel is only {} bytes deep",
619 depth,
620 pix_depth);
621
622 let row_len = self.width * pix_depth;
623
624 let row_start = (row - 1) * row_len;
625 let col_pos = column * pix_depth;
626
627 self.pixels[row_start + col_pos + depth] = color;
628 }
629}