From cbd62dbd0aca5e1358cbe373ffde334f67f5bf8a Mon Sep 17 00:00:00 2001 From: arakiken Date: Wed, 25 Mar 2020 22:38:49 +0900 Subject: [PATCH 1/3] Support OR mode which is enabled by -O, --ormode option. (http://www.pastel-flower.jp/~isaki/NetBSD/osc16hi/page40.html) --- converters/img2sixel.c | 6 +- include/sixel.h.in | 3 + src/encoder.c | 5 ++ src/encoder.h | 1 + src/output.c | 7 ++ src/output.h | 1 + src/tosixel.c | 141 ++++++++++++++++++++++++++++++++++++++--- 7 files changed, 152 insertions(+), 12 deletions(-) diff --git a/converters/img2sixel.c b/converters/img2sixel.c index eb0befcd2..f778bee3b 100644 --- a/converters/img2sixel.c +++ b/converters/img2sixel.c @@ -305,6 +305,7 @@ void show_help(void) " pass-through sequence\n" "-D, --pipe-mode [[deprecated]] read source images from\n" " stdin continuously\n" + "-O, --ormode output ormode sixel image\n" "-v, --verbose show debugging info\n" "-V, --version show version and license info\n" "-H, --help show this help\n" @@ -347,7 +348,7 @@ main(int argc, char *argv[]) int long_opt; int option_index; #endif /* HAVE_GETOPT_LONG */ - char const *optstring = "o:78Rp:m:eb:Id:f:s:c:w:h:r:q:kil:t:ugvSn:PE:B:C:DVH"; + char const *optstring = "o:78ORp:m:eb:Id:f:s:c:w:h:r:q:kil:t:ugvSn:PE:B:C:DVH"; #if HAVE_GETOPT_LONG struct option long_options[] = { {"outfile", no_argument, &long_opt, 'o'}, @@ -381,6 +382,7 @@ main(int argc, char *argv[]) {"bgcolor", required_argument, &long_opt, 'B'}, {"complexion-score", required_argument, &long_opt, 'C'}, {"pipe-mode", no_argument, &long_opt, 'D'}, /* deprecated */ + {"ormode", no_argument, &long_opt, 'O'}, {"version", no_argument, &long_opt, 'V'}, {"help", no_argument, &long_opt, 'H'}, {0, 0, 0, 0} @@ -467,7 +469,7 @@ main(int argc, char *argv[]) argerr: fprintf(stderr, - "usage: img2sixel [-78eIkiugvSPDVH] [-p colors] [-m file] [-d diffusiontype]\n" + "usage: img2sixel [-78eIkiugvSPDOVH] [-p colors] [-m file] [-d diffusiontype]\n" " [-f findtype] [-s selecttype] [-c geometory] [-w width]\n" " [-h height] [-r resamplingtype] [-q quality] [-l loopmode]\n" " [-t palettetype] [-n macronumber] [-C score] [-b palette]\n" diff --git a/include/sixel.h.in b/include/sixel.h.in index bcdb66c30..0d20f5a6d 100644 --- a/include/sixel.h.in +++ b/include/sixel.h.in @@ -354,6 +354,9 @@ typedef int SIXELSTATUS; size -> encode to as small sixel sequence as possible */ +#define SIXEL_OPTFLAG_ORMODE ('O') /* -O, --ormode: + output ormode sixel image + */ #define SIXEL_OPTFLAG_BGCOLOR ('B') /* -B BGCOLOR, --bgcolor=BGCOLOR: specify background color BGCOLOR is represented by the diff --git a/src/encoder.c b/src/encoder.c index e050045d1..23c65b454 100644 --- a/src/encoder.c +++ b/src/encoder.c @@ -1030,6 +1030,7 @@ sixel_encoder_encode_frame( sixel_output_set_penetrate_multiplexer( output, encoder->penetrate_multiplexer); sixel_output_set_encode_policy(output, encoder->encode_policy); + sixel_output_set_ormode(output, encoder->ormode); if (sixel_frame_get_multiframe(frame) && !encoder->fstatic) { if (sixel_frame_get_loop_no(frame) != 0 || sixel_frame_get_frame_no(frame) != 0) { @@ -1147,6 +1148,7 @@ sixel_encoder_new( (*ppencoder)->verbose = 0; (*ppencoder)->penetrate_multiplexer = 0; (*ppencoder)->encode_policy = SIXEL_ENCODEPOLICY_AUTO; + (*ppencoder)->ormode = 0; (*ppencoder)->pipe_mode = 0; (*ppencoder)->bgcolor = NULL; (*ppencoder)->outfd = STDOUT_FILENO; @@ -1605,6 +1607,9 @@ sixel_encoder_setopt( goto end; } break; + case SIXEL_OPTFLAG_ORMODE: /* O */ + encoder->ormode = 1; + break; case SIXEL_OPTFLAG_COMPLEXION_SCORE: /* C */ encoder->complexion = atoi(value); if (encoder->complexion < 1) { diff --git a/src/encoder.h b/src/encoder.h index 363fe8597..c1e2e4e7b 100644 --- a/src/encoder.h +++ b/src/encoder.h @@ -62,6 +62,7 @@ struct sixel_encoder { int macro_number; int penetrate_multiplexer; int encode_policy; + int ormode; int pipe_mode; int verbose; int has_gri_arg_limit; diff --git a/src/output.c b/src/output.c index 1b4c37abb..c8cdea92b 100644 --- a/src/output.c +++ b/src/output.c @@ -78,6 +78,7 @@ sixel_output_new( (*output)->pos = 0; (*output)->penetrate_multiplexer = 0; (*output)->encode_policy = SIXEL_ENCODEPOLICY_AUTO; + (*output)->ormode = 0; (*output)->allocator = allocator; status = SIXEL_OK; @@ -193,6 +194,12 @@ sixel_output_set_palette_type(sixel_output_t *output, int palettetype) } +SIXELAPI void +sixel_output_set_ormode(sixel_output_t *output, int ormode) +{ + output->ormode = ormode; +} + /* set encodeing policy: auto, fast or size */ SIXELAPI void sixel_output_set_encode_policy(sixel_output_t *output, int encode_policy) diff --git a/src/output.h b/src/output.h index 197d09781..eb2ad53e3 100644 --- a/src/output.h +++ b/src/output.h @@ -73,6 +73,7 @@ struct sixel_output { int penetrate_multiplexer; int encode_policy; + int ormode; void *priv; int pos; diff --git a/src/tosixel.c b/src/tosixel.c index 077dfa0c0..286cc167a 100644 --- a/src/tosixel.c +++ b/src/tosixel.c @@ -315,6 +315,11 @@ sixel_encode_header(int width, int height, sixel_output_t *output) int pcount = 3; int use_raster_attributes = 1; + if (output->ormode) { + p[0] = 7; + p[1] = 5; + } + output->pos = 0; if (!output->skip_dcs_envelope) { @@ -780,6 +785,111 @@ sixel_encode_footer(sixel_output_t *output) return status; } +static SIXELSTATUS +sixel_encode_body_ormode( + uint8_t /* in */ *pixels, + int /* in */ width, + int /* in */ height, + unsigned char /* in */ *palette, + int /* in */ ncolors, + int /* in */ keycolor, + sixel_output_t /* in */ *output) +{ + SIXELSTATUS status; + int n; + int nplanes; + uint8_t *buf = pixels; + uint8_t *buf_p; + int x; + int cur_h; + int nwrite; + int plane; + + for (n = 0; n < ncolors; n++) { + status = output_rgb_palette_definition(output, palette, n, keycolor); + if (SIXEL_FAILED(status)) { + return status; + } + } + + for (nplanes = 8; nplanes > 1; nplanes--) { + if (ncolors > (1 << (nplanes - 1))) { + break; + } + } + + for (cur_h = 6; cur_h <= height; cur_h += 6) { + for (plane = 0; plane < nplanes; plane++) { + sixel_putc(output->buffer + output->pos, '#'); + sixel_advance(output, 1); + nwrite = sixel_putnum(output->buffer + output->pos, 1 << plane); + sixel_advance(output, nwrite); + + buf_p = buf; + for (x = 0; x < width; x++, buf_p++) { + sixel_put_pixel(output, + ((buf_p[0] >> plane) & 0x1) | + (((buf_p[width] >> plane) << 1) & 0x2) | + (((buf_p[width * 2] >> plane) << 2) & 0x4) | + (((buf_p[width * 3] >> plane) << 3) & 0x8) | + (((buf_p[width * 4] >> plane) << 4) & 0x10) | + (((buf_p[width * 5] >> plane) << 5) & 0x20)); + } + status = sixel_put_flash(output); + if (SIXEL_FAILED(status)) { + return status; + } + sixel_putc(output->buffer + output->pos, '$'); + sixel_advance(output, 1); + } + sixel_putc(output->buffer + output->pos, '-'); + sixel_advance(output, 1); + buf += (width * 6); + } + + if (cur_h > height) { + for (plane = 0; plane < nplanes; plane++) { + int pix; + + sixel_putc(output->buffer + output->pos, '#'); + sixel_advance(output, 1); + nwrite = sixel_putnum(output->buffer + output->pos, 1 << plane); + sixel_advance(output, nwrite); + + buf_p = buf; + for (x = 0; x < width; x++) { + pix = ((buf_p[0] >> plane) & 0x1); + + switch(cur_h - height) { + case 1: + pix |= (((buf_p[width * 4] >> plane) << 4) & 0x10); + /* Fall through */ + case 2: + pix |= (((buf_p[width * 3] >> plane) << 3) & 0x8); + /* Fall through */ + case 3: + pix |= (((buf_p[width * 2] >> plane) << 2) & 0x4); + /* Fall through */ + case 4: + pix |= (((buf_p[width] >> plane) << 1) & 0x2); + /* Fall through */ + } + + sixel_put_pixel(output, pix); + } + status = sixel_put_flash(output); + if (SIXEL_FAILED(status)) { + return status; + } + + sixel_putc(output->buffer + output->pos, '$'); + sixel_advance(output, 1); + } + } + + return 0; +} + static SIXELSTATUS sixel_encode_dither( @@ -842,16 +952,27 @@ sixel_encode_dither( goto end; } - status = sixel_encode_body(input_pixels, - width, - height, - dither->palette, - dither->ncolors, - dither->keycolor, - dither->bodyonly, - output, - NULL, - dither->allocator); + if (output->ormode) { + status = sixel_encode_body_ormode(input_pixels, + width, + height, + dither->palette, + dither->ncolors, + dither->keycolor, + output); + } else { + status = sixel_encode_body(input_pixels, + width, + height, + dither->palette, + dither->ncolors, + dither->keycolor, + dither->bodyonly, + output, + NULL, + dither->allocator); + } + if (SIXEL_FAILED(status)) { goto end; } From 7249e61717e3b9c28effcc277273c324dd327927 Mon Sep 17 00:00:00 2001 From: arakiken Date: Sun, 12 Apr 2020 20:36:40 +0900 Subject: [PATCH 2/3] Fix compiling error of -Werror=pointer-sign. --- src/tosixel.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tosixel.c b/src/tosixel.c index 286cc167a..40e657c4c 100644 --- a/src/tosixel.c +++ b/src/tosixel.c @@ -513,7 +513,6 @@ sixel_encode_body( int sx; int mx; int len; - int pix; char *map = NULL; int check_integer_overflow; sixel_node_t *np, *tp, top; @@ -555,6 +554,8 @@ sixel_encode_body( } for (y = i = 0; y < height; y++) { + int pix; + if (output->encode_policy != SIXEL_ENCODEPOLICY_SIZE) { fillable = 0; } else if (palstate) { @@ -822,7 +823,7 @@ sixel_encode_body_ormode( for (plane = 0; plane < nplanes; plane++) { sixel_putc(output->buffer + output->pos, '#'); sixel_advance(output, 1); - nwrite = sixel_putnum(output->buffer + output->pos, 1 << plane); + nwrite = sixel_putnum((char *)output->buffer + output->pos, 1 << plane); sixel_advance(output, nwrite); buf_p = buf; @@ -853,7 +854,7 @@ sixel_encode_body_ormode( sixel_putc(output->buffer + output->pos, '#'); sixel_advance(output, 1); - nwrite = sixel_putnum(output->buffer + output->pos, 1 << plane); + nwrite = sixel_putnum((char *)output->buffer + output->pos, 1 << plane); sixel_advance(output, nwrite); buf_p = buf; From d404b804cfbaecd447bef2be5d6870bdfd6f437d Mon Sep 17 00:00:00 2001 From: arakiken Date: Sun, 12 Apr 2020 21:34:44 +0900 Subject: [PATCH 3/3] Add sixel_output_set_ormode() to sixel.h.in --- include/sixel.h.in | 5 +++++ src/output.c | 1 + src/tosixel.c | 4 +--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/sixel.h.in b/include/sixel.h.in index 0d20f5a6d..e19ddb367 100644 --- a/include/sixel.h.in +++ b/include/sixel.h.in @@ -648,6 +648,11 @@ sixel_output_set_palette_type( int /* in */ palettetype); /* PALETTETYPE_RGB: RGB palette PALETTETYPE_HLS: HLS palette */ +SIXELAPI void +sixel_output_set_ormode( + sixel_output_t /* in */ *output, /* output context */ + int /* in */ ormode); + /* set encodeing policy: auto, fast or size */ SIXELAPI void sixel_output_set_encode_policy( diff --git a/src/output.c b/src/output.c index c8cdea92b..9557276b5 100644 --- a/src/output.c +++ b/src/output.c @@ -200,6 +200,7 @@ sixel_output_set_ormode(sixel_output_t *output, int ormode) output->ormode = ormode; } + /* set encodeing policy: auto, fast or size */ SIXELAPI void sixel_output_set_encode_policy(sixel_output_t *output, int encode_policy) diff --git a/src/tosixel.c b/src/tosixel.c index 40e657c4c..21b84bd34 100644 --- a/src/tosixel.c +++ b/src/tosixel.c @@ -850,8 +850,6 @@ sixel_encode_body_ormode( if (cur_h > height) { for (plane = 0; plane < nplanes; plane++) { - int pix; - sixel_putc(output->buffer + output->pos, '#'); sixel_advance(output, 1); nwrite = sixel_putnum((char *)output->buffer + output->pos, 1 << plane); @@ -859,7 +857,7 @@ sixel_encode_body_ormode( buf_p = buf; for (x = 0; x < width; x++) { - pix = ((buf_p[0] >> plane) & 0x1); + int pix = ((buf_p[0] >> plane) & 0x1); switch(cur_h - height) { case 1: