1 /*
2  * Copyright (c) 2014-2019 Hayaki Saito
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy of
5  * this software and associated documentation files (the "Software"), to deal in
6  * the Software without restriction, including without limitation the rights to
7  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8  * the Software, and to permit persons to whom the Software is furnished to do so,
9  * subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20  */
21 
22 #include "config.h"
23 
24 #if STDC_HEADERS
25 # include <stdio.h>
26 # include <stdlib.h>
27 #endif  /* STDC_HEADERS */
28 #if HAVE_ASSERT_H
29 # include <assert.h>
30 #endif  /* HAVE_ASSERT_H */
31 
32 #include <sixel.h>
33 #include "output.h"
34 
35 
36 /* create new output context object */
37 SIXELAPI SIXELSTATUS
sixel_output_new(sixel_output_t ** output,sixel_write_function fn_write,void * priv,sixel_allocator_t * allocator)38 sixel_output_new(
39     sixel_output_t          /* out */ **output,
40     sixel_write_function    /* in */  fn_write,
41     void                    /* in */  *priv,
42     sixel_allocator_t       /* in */  *allocator)
43 {
44     SIXELSTATUS status = SIXEL_FALSE;
45     size_t size;
46 
47     if (allocator == NULL) {
48         status = sixel_allocator_new(&allocator, NULL, NULL, NULL, NULL);
49         if (SIXEL_FAILED(status)) {
50             goto end;
51         }
52     } else {
53         sixel_allocator_ref(allocator);
54     }
55     size = sizeof(sixel_output_t) + SIXEL_OUTPUT_PACKET_SIZE * 2;
56 
57     *output = (sixel_output_t *)sixel_allocator_malloc(allocator, size);
58     if (*output == NULL) {
59         sixel_helper_set_additional_message(
60             "sixel_output_new: sixel_allocator_malloc() failed.");
61         status = SIXEL_BAD_ALLOCATION;
62         goto end;
63     }
64 
65     (*output)->ref = 1;
66     (*output)->has_8bit_control = 0;
67     (*output)->has_sdm_glitch = 0;
68     (*output)->has_gri_arg_limit = 1;
69     (*output)->skip_dcs_envelope = 0;
70     (*output)->palette_type = SIXEL_PALETTETYPE_AUTO;
71     (*output)->fn_write = fn_write;
72     (*output)->save_pixel = 0;
73     (*output)->save_count = 0;
74     (*output)->active_palette = (-1);
75     (*output)->node_top = NULL;
76     (*output)->node_free = NULL;
77     (*output)->priv = priv;
78     (*output)->pos = 0;
79     (*output)->penetrate_multiplexer = 0;
80     (*output)->encode_policy = SIXEL_ENCODEPOLICY_AUTO;
81     (*output)->allocator = allocator;
82 
83     status = SIXEL_OK;
84 
85 end:
86     return status;
87 }
88 
89 
90 /* deprecated: create an output object */
91 SIXELAPI sixel_output_t *
sixel_output_create(sixel_write_function fn_write,void * priv)92 sixel_output_create(sixel_write_function fn_write, void *priv)
93 {
94     SIXELSTATUS status = SIXEL_FALSE;
95     sixel_output_t *output = NULL;
96 
97     status = sixel_output_new(&output, fn_write, priv, NULL);
98     if (SIXEL_FAILED(status)) {
99         goto end;
100     }
101 
102 end:
103     return output;
104 }
105 
106 
107 /* destroy output context object */
108 SIXELAPI void
sixel_output_destroy(sixel_output_t * output)109 sixel_output_destroy(sixel_output_t *output)
110 {
111     sixel_allocator_t *allocator;
112 
113     if (output) {
114         allocator = output->allocator;
115         sixel_allocator_free(allocator, output);
116         sixel_allocator_unref(allocator);
117     }
118 }
119 
120 
121 /* increase reference count of output context object (thread-unsafe) */
122 SIXELAPI void
sixel_output_ref(sixel_output_t * output)123 sixel_output_ref(sixel_output_t *output)
124 {
125     /* TODO: be thread-safe */
126     ++output->ref;
127 }
128 
129 
130 /* decrease reference count of output context object (thread-unsafe) */
131 SIXELAPI void
sixel_output_unref(sixel_output_t * output)132 sixel_output_unref(sixel_output_t *output)
133 {
134     /* TODO: be thread-safe */
135     if (output) {
136         assert(output->ref > 0);
137         output->ref--;
138         if (output->ref == 0) {
139             sixel_output_destroy(output);
140         }
141     }
142 }
143 
144 
145 /* get 8bit output mode which indicates whether it uses C1 control characters */
146 SIXELAPI int
sixel_output_get_8bit_availability(sixel_output_t * output)147 sixel_output_get_8bit_availability(sixel_output_t *output)
148 {
149     return output->has_8bit_control;
150 }
151 
152 
153 /* set 8bit output mode state */
154 SIXELAPI void
sixel_output_set_8bit_availability(sixel_output_t * output,int availability)155 sixel_output_set_8bit_availability(sixel_output_t *output, int availability)
156 {
157     output->has_8bit_control = availability;
158 }
159 
160 
161 /* set whether limit arguments of DECGRI('!') to 255 */
162 SIXELAPI void
sixel_output_set_gri_arg_limit(sixel_output_t * output,int value)163 sixel_output_set_gri_arg_limit(
164     sixel_output_t /* in */ *output, /* output context */
165     int            /* in */ value)   /* 0: don't limit arguments of DECGRI
166                                         1: limit arguments of DECGRI to 255 */
167 {
168     output->has_gri_arg_limit = value;
169 }
170 
171 
172 /* set GNU Screen penetration feature enable or disable */
173 SIXELAPI void
sixel_output_set_penetrate_multiplexer(sixel_output_t * output,int penetrate)174 sixel_output_set_penetrate_multiplexer(sixel_output_t *output, int penetrate)
175 {
176     output->penetrate_multiplexer = penetrate;
177 }
178 
179 
180 /* set whether we skip DCS envelope */
181 SIXELAPI void
sixel_output_set_skip_dcs_envelope(sixel_output_t * output,int skip)182 sixel_output_set_skip_dcs_envelope(sixel_output_t *output, int skip)
183 {
184     output->skip_dcs_envelope = skip;
185 }
186 
187 
188 /* set palette type: RGB or HLS */
189 SIXELAPI void
sixel_output_set_palette_type(sixel_output_t * output,int palettetype)190 sixel_output_set_palette_type(sixel_output_t *output, int palettetype)
191 {
192     output->palette_type = palettetype;
193 }
194 
195 
196 /* set encodeing policy: auto, fast or size */
197 SIXELAPI void
sixel_output_set_encode_policy(sixel_output_t * output,int encode_policy)198 sixel_output_set_encode_policy(sixel_output_t *output, int encode_policy)
199 {
200     output->encode_policy = encode_policy;
201 }
202 
203 /* emacs Local Variables:      */
204 /* emacs mode: c               */
205 /* emacs tab-width: 4          */
206 /* emacs indent-tabs-mode: nil */
207 /* emacs c-basic-offset: 4     */
208 /* emacs End:                  */
209 /* vim: set expandtab ts=4 sts=4 sw=4 : */
210 /* EOF */
211