├── .gitignore
├── COPYING
├── DEPENDENCIES
├── LICENSE
├── META-INF
└── MANIFEST.MF
├── Makefile
├── README
├── cowsay2img
├── dist
└── archlinux
│ ├── bleeding
│ └── PKGBUILD
│ └── stable
│ └── PKGBUILD
├── fdl.texinfo
├── img2cowsay
├── img2ponysay
├── img2unisay
├── lowcaps.linux.conf
├── lowcaps.rxvt.conf
├── lowcaps.tango.conf
├── lowcaps.xterm.conf
├── ponysay2img
├── ponysay2ttyponysay
├── ponytool
├── src
└── se
│ └── kth
│ └── maandree
│ └── utilsay
│ ├── Cat.java
│ ├── Colour.java
│ ├── Common.java
│ ├── Cowsay.java
│ ├── Image.java
│ ├── Pony.java
│ ├── Ponysay.java
│ ├── PonysayHaiku.java
│ ├── PonysayLinux.java
│ ├── PonysaySubmodule.java
│ ├── PonysayXterm.java
│ ├── Program.java
│ ├── Raw.java
│ ├── Test.java
│ ├── Unisay.java
│ └── imgsrcrecover.java
├── unisay2img
└── util-say.texinfo
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Non-staging area ##
2 | ########################
3 |
4 | _/
5 |
6 |
7 | ## compiled files ##
8 | ######################
9 |
10 | /bin/
11 | /doc/javadoc/
12 | *.class
13 | /*.jar
14 | /*.info
15 | /*.info.*
16 | /*.dvi
17 | /*.dvi.*
18 | /*.ps
19 | /*.ps.*
20 | /*.pdf
21 | /*.pdf.*
22 |
23 |
24 | ## backup files ##
25 | ####################
26 |
27 | *~
28 | \#*\#
29 | .\#*
30 | *.swp
31 | *.bak
32 |
33 |
34 | ## distribution files ##
35 | ##########################
36 |
37 | /dist/*/*/*
38 | !/dist/*/*/PKGBUILD
39 |
40 |
41 | ## auxiliary files ##
42 | #######################
43 |
44 | /*.aux
45 | /*.cp
46 | /*.cps
47 | /*.fn
48 | /*.ky
49 | /*.log
50 | /*.op
51 | /*.ops
52 | /*.pg
53 | /*.toc
54 | /*.tp
55 | /*.vr
56 |
57 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | util-say — Collection of tools for creating ponies for cowsay and cowsay-like programs
2 |
3 | Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
4 |
5 | util-say is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | util-say is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with util-say. If not, see .
17 |
--------------------------------------------------------------------------------
/DEPENDENCIES:
--------------------------------------------------------------------------------
1 | # REQUIRED
2 |
3 | java-runtime>=6
4 |
5 | coreutils
6 |
7 | texinfo
8 | #for using the Makefile to generate "util-say.info.gz" || or if people type "make all"
9 |
10 | # OPTIONAL
11 |
12 | imagemagick
13 | # for bursting gif images
14 |
15 | perl
16 | # required for cowsay2unisay
17 |
--------------------------------------------------------------------------------
/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Created-By: Mattias Andrée
3 | Main-Class: se.kth.maandree.utilsay.Program
4 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | PREFIX=/usr
2 | BIN=/bin
3 | DATA=/share
4 |
5 | JAR=jar
6 | JAVAC=javac
7 |
8 | SRC=$(shell find src | grep '\.java$$')
9 | OBJ=$(shell find src | grep '\.java$$' | sed -e 's_/[a-zA-Z]*\.java$$_/\*\.class_g' -e 's_^src/__g' | sort | uniq)
10 |
11 | all: util-say.jar info
12 |
13 | .PHONY: util-say.jar
14 | util-say.jar:
15 | "$(JAVAC)" -O -cp src -s src -d . $(SRC) -encoding UTF-8
16 | "$(JAR)" -cfm "$@" "META-INF/MANIFEST.MF" $(OBJ)
17 |
18 |
19 | info: util-say.info.gz
20 | %.info: %.texinfo
21 | $(MAKEINFO) "$<"
22 | %.info.gz: %.info
23 | gzip -9c < "$<" > "$@"
24 |
25 |
26 | pdf: util-say.pdf
27 | %.pdf: %.texinfo
28 | texi2pdf "$<"
29 |
30 | pdf.gz: util-say.pdf.gz
31 | %.pdf.gz: %.pdf
32 | gzip -9c < "$<" > "$@"
33 |
34 | pdf.xz: util-say.pdf.xz
35 | %.pdf.xz: %.pdf
36 | xz -e9 < "$<" > "$@"
37 |
38 |
39 | dvi: util-say.dvi
40 | %.dvi: %.texinfo
41 | $(TEXI2DVI) "$<"
42 |
43 | dvi.gz: util-say.dvi.gz
44 | %.dvi.gz: %.dvi
45 | gzip -9c < "$<" > "$@"
46 |
47 | dvi.xz: util-say.dvi.xz
48 | %.dvi.xz: %.dvi
49 | xz -e9 < "$<" > "$@"
50 |
51 |
52 | install: util-say.jar util-say.info.gz
53 | install -d -m 755 "$(DESTDIR)$(PREFIX)$(BIN)"
54 | install -m 755 util-say.jar "$(DESTDIR)$(PREFIX)$(BIN)"
55 | install -m 755 img2{pony,uni,cow}say "$(DESTDIR)$(PREFIX)$(BIN)"
56 | install -m 755 {pony,uni,cow}say2img "$(DESTDIR)$(PREFIX)$(BIN)"
57 | install -m 755 ponysay2ttyponysay "$(DESTDIR)$(PREFIX)$(BIN)"
58 | ln -sf ponysay2ttyponysay "$(DESTDIR)$(PREFIX)$(BIN)"/tty2colourfultty
59 | ln -sf /usr/bin/cat "$(DESTDIR)$(PREFIX)$(BIN)"/unzebra
60 | install -m 755 ponytool "$(DESTDIR)$(PREFIX)$(BIN)"
61 | install -d -m 755 "$(DESTDIR)$(PREFIX)$(DATA)/licenses/util-say"
62 | install -m 644 LICENSE COPYING "$(DESTDIR)$(PREFIX)$(DATA)/licenses/util-say"
63 | install -d -m 755 "$(DESTDIR)$(PREFIX)$(DATA)/info"
64 | install -m 644 util-say.info.gz "$(DESTDIR)$(PREFIX)$(DATA)/info"
65 |
66 |
67 | uninstall:
68 | unlink "$(DESTDIR)$(PREFIX)$(BIN)/util-say.jar"
69 | unlink "$(DESTDIR)$(PREFIX)$(BIN)/ponytool"
70 | unlink "$(DESTDIR)$(PREFIX)$(DATA)/info/util-say.info.gz"
71 | rm -- "$(DESTDIR)$(PREFIX)$(BIN)/"img2{pony,uni,cow}say
72 | rm -- "$(DESTDIR)$(PREFIX)$(BIN)/"{pony,uni,cow}say2img
73 | rm -- "$(DESTDIR)$(PREFIX)$(BIN)/"ponysay2ttyponysay
74 | rm -- "$(DESTDIR)$(PREFIX)$(BIN)/"tty2colourfultty
75 | rm -- "$(DESTDIR)$(PREFIX)$(BIN)/"unzebra
76 | yes | rm -r "$(DESTDIR)$(PREFIX)$(DATA)/licenses/util-say"
77 |
78 |
79 | .PHONY: clean
80 | clean:
81 | yes | rm -r se || true
82 | rm util-say.jar || true
83 | rm *.{info,pdf,ps,dvi}{,.*} || true
84 | rm *.{aux,cp,cps,fn,ky,log,op,ops,pg,toc,tp,vr} || true
85 |
86 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Tools for creating ponies for cowsay and cowsay-like programs.
2 |
--------------------------------------------------------------------------------
/cowsay2img:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | magnified='1'
4 | file='-'
5 | dash=0
6 |
7 | for arg in "$@"; do
8 | if [ $dash = 1 ]; then
9 | file="$arg"
10 | elif [ "$arg" = "--" ]; then
11 | dash=1
12 | elif [ "$arg" = "-2" ]; then
13 | magnified=2
14 | else
15 | file="$arg"
16 | fi
17 | done
18 |
19 | java -jar "$(dirname "$0")/util-say.jar" \
20 | --import cowsay --file - --export image --magnified $magnified --file "$file" --left - --right - --bottom - --top -
21 |
22 |
--------------------------------------------------------------------------------
/dist/archlinux/bleeding/PKGBUILD:
--------------------------------------------------------------------------------
1 | # Maintainer: Mattias Andrée <`base64 -d`(bWFhbmRyZWUK)@member.fsf.org>
2 | pkgname=util-say-git
3 | pkgver=20130405.2
4 | pkgrel=1
5 | pkgdesc="Tools for creating ponies for cowsay and cowsay-like programs"
6 | arch=('any')
7 | url="https://github.com/maandree/util-say"
8 | license=('GPL3')
9 | depends=('java-runtime>=6')
10 | makedepends=('git' 'java-environment>=6' 'bash')
11 | optdepends=('imagemagick: allows imgsrcrecovery to read frames in GIF files' 'perl: required for cowsay import support')
12 | provides=('util-say')
13 | conflicts=('util-say')
14 |
15 | _gitroot=https://github.com/maandree/util-say.git
16 | _gitname=util-say
17 |
18 | build() {
19 | cd "$srcdir"
20 | msg "Connecting to GIT server...."
21 |
22 | if [[ -d "$_gitname" ]]; then
23 | cd "$_gitname" && git pull origin
24 | msg "The local files are updated."
25 | else
26 | git clone "$_gitroot" "$_gitname"
27 | fi
28 |
29 | msg "GIT checkout done or server timeout"
30 | msg "Starting build..."
31 |
32 | rm -rf "$srcdir/$_gitname-build"
33 | git clone "$srcdir/$_gitname" "$srcdir/$_gitname-build"
34 | cd "$srcdir/$_gitname-build"
35 |
36 | make -B DESTDIR="$pkgdir/"
37 | }
38 |
39 | package() {
40 | cd "$srcdir/$_gitname-build"
41 | make DESTDIR="$pkgdir/" install
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/dist/archlinux/stable/PKGBUILD:
--------------------------------------------------------------------------------
1 | # Maintainer: Mattias Andrée <`base64 -d`(bWFhbmRyZWUK)@member.fsf.org>
2 | pkgname=util-say
3 | pkgver=3.2.1
4 | pkgrel=1
5 | pkgdesc="Tools for creating ponies for cowsay and cowsay-like programs"
6 | arch=('any')
7 | url="https://github.com/maandree/util-say"
8 | license=('GPL3')
9 | depends=('java-runtime>=6')
10 | makedepends=('java-environment>=6' 'bash')
11 | optdepends=('imagemagick: allows imgsrcrecovery to read frames in GIF files' 'perl: required for cowsay import support')
12 | provides=('util-say')
13 | conflicts=('util-say')
14 | source=(https://github.com/maandree/util-say/archive/$pkgver.tar.gz)
15 | sha256sums=(38539e74d97afb719ad71f694ff08fc024ae71a33f60dd5d94e163d5bc66e98f)
16 |
17 | build() {
18 | cd "$srcdir/util-say-$pkgver"
19 | make -B DESTDIR="$pkgdir/"
20 | }
21 |
22 | package() {
23 | cd "$srcdir/util-say-$pkgver"
24 | make DESTDIR="$pkgdir/" install
25 | }
26 |
--------------------------------------------------------------------------------
/fdl.texinfo:
--------------------------------------------------------------------------------
1 | @c The GNU Free Documentation License.
2 | @center Version 1.3, 3 November 2008
3 |
4 | @c This file is intended to be included within another document,
5 | @c hence no sectioning command or @node.
6 |
7 | @display
8 | Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
9 | @uref{http://fsf.org/}
10 |
11 | Everyone is permitted to copy and distribute verbatim copies
12 | of this license document, but changing it is not allowed.
13 | @end display
14 |
15 | @enumerate 0
16 | @item
17 | PREAMBLE
18 |
19 | The purpose of this License is to make a manual, textbook, or other
20 | functional and useful document @dfn{free} in the sense of freedom: to
21 | assure everyone the effective freedom to copy and redistribute it,
22 | with or without modifying it, either commercially or noncommercially.
23 | Secondarily, this License preserves for the author and publisher a way
24 | to get credit for their work, while not being considered responsible
25 | for modifications made by others.
26 |
27 | This License is a kind of ``copyleft'', which means that derivative
28 | works of the document must themselves be free in the same sense. It
29 | complements the GNU General Public License, which is a copyleft
30 | license designed for free software.
31 |
32 | We have designed this License in order to use it for manuals for free
33 | software, because free software needs free documentation: a free
34 | program should come with manuals providing the same freedoms that the
35 | software does. But this License is not limited to software manuals;
36 | it can be used for any textual work, regardless of subject matter or
37 | whether it is published as a printed book. We recommend this License
38 | principally for works whose purpose is instruction or reference.
39 |
40 | @item
41 | APPLICABILITY AND DEFINITIONS
42 |
43 | This License applies to any manual or other work, in any medium, that
44 | contains a notice placed by the copyright holder saying it can be
45 | distributed under the terms of this License. Such a notice grants a
46 | world-wide, royalty-free license, unlimited in duration, to use that
47 | work under the conditions stated herein. The ``Document'', below,
48 | refers to any such manual or work. Any member of the public is a
49 | licensee, and is addressed as ``you''. You accept the license if you
50 | copy, modify or distribute the work in a way requiring permission
51 | under copyright law.
52 |
53 | A ``Modified Version'' of the Document means any work containing the
54 | Document or a portion of it, either copied verbatim, or with
55 | modifications and/or translated into another language.
56 |
57 | A ``Secondary Section'' is a named appendix or a front-matter section
58 | of the Document that deals exclusively with the relationship of the
59 | publishers or authors of the Document to the Document's overall
60 | subject (or to related matters) and contains nothing that could fall
61 | directly within that overall subject. (Thus, if the Document is in
62 | part a textbook of mathematics, a Secondary Section may not explain
63 | any mathematics.) The relationship could be a matter of historical
64 | connection with the subject or with related matters, or of legal,
65 | commercial, philosophical, ethical or political position regarding
66 | them.
67 |
68 | The ``Invariant Sections'' are certain Secondary Sections whose titles
69 | are designated, as being those of Invariant Sections, in the notice
70 | that says that the Document is released under this License. If a
71 | section does not fit the above definition of Secondary then it is not
72 | allowed to be designated as Invariant. The Document may contain zero
73 | Invariant Sections. If the Document does not identify any Invariant
74 | Sections then there are none.
75 |
76 | The ``Cover Texts'' are certain short passages of text that are listed,
77 | as Front-Cover Texts or Back-Cover Texts, in the notice that says that
78 | the Document is released under this License. A Front-Cover Text may
79 | be at most 5 words, and a Back-Cover Text may be at most 25 words.
80 |
81 | A ``Transparent'' copy of the Document means a machine-readable copy,
82 | represented in a format whose specification is available to the
83 | general public, that is suitable for revising the document
84 | straightforwardly with generic text editors or (for images composed of
85 | pixels) generic paint programs or (for drawings) some widely available
86 | drawing editor, and that is suitable for input to text formatters or
87 | for automatic translation to a variety of formats suitable for input
88 | to text formatters. A copy made in an otherwise Transparent file
89 | format whose markup, or absence of markup, has been arranged to thwart
90 | or discourage subsequent modification by readers is not Transparent.
91 | An image format is not Transparent if used for any substantial amount
92 | of text. A copy that is not ``Transparent'' is called ``Opaque''.
93 |
94 | Examples of suitable formats for Transparent copies include plain
95 | ASCII without markup, Texinfo input format, La@TeX{} input
96 | format, SGML or XML using a publicly available
97 | DTD, and standard-conforming simple HTML,
98 | PostScript or PDF designed for human modification. Examples
99 | of transparent image formats include PNG, XCF and
100 | JPG. Opaque formats include proprietary formats that can be
101 | read and edited only by proprietary word processors, SGML or
102 | XML for which the DTD and/or processing tools are
103 | not generally available, and the machine-generated HTML,
104 | PostScript or PDF produced by some word processors for
105 | output purposes only.
106 |
107 | The ``Title Page'' means, for a printed book, the title page itself,
108 | plus such following pages as are needed to hold, legibly, the material
109 | this License requires to appear in the title page. For works in
110 | formats which do not have any title page as such, ``Title Page'' means
111 | the text near the most prominent appearance of the work's title,
112 | preceding the beginning of the body of the text.
113 |
114 | The ``publisher'' means any person or entity that distributes copies
115 | of the Document to the public.
116 |
117 | A section ``Entitled XYZ'' means a named subunit of the Document whose
118 | title either is precisely XYZ or contains XYZ in parentheses following
119 | text that translates XYZ in another language. (Here XYZ stands for a
120 | specific section name mentioned below, such as ``Acknowledgements'',
121 | ``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title''
122 | of such a section when you modify the Document means that it remains a
123 | section ``Entitled XYZ'' according to this definition.
124 |
125 | The Document may include Warranty Disclaimers next to the notice which
126 | states that this License applies to the Document. These Warranty
127 | Disclaimers are considered to be included by reference in this
128 | License, but only as regards disclaiming warranties: any other
129 | implication that these Warranty Disclaimers may have is void and has
130 | no effect on the meaning of this License.
131 |
132 | @item
133 | VERBATIM COPYING
134 |
135 | You may copy and distribute the Document in any medium, either
136 | commercially or noncommercially, provided that this License, the
137 | copyright notices, and the license notice saying this License applies
138 | to the Document are reproduced in all copies, and that you add no other
139 | conditions whatsoever to those of this License. You may not use
140 | technical measures to obstruct or control the reading or further
141 | copying of the copies you make or distribute. However, you may accept
142 | compensation in exchange for copies. If you distribute a large enough
143 | number of copies you must also follow the conditions in section 3.
144 |
145 | You may also lend copies, under the same conditions stated above, and
146 | you may publicly display copies.
147 |
148 | @item
149 | COPYING IN QUANTITY
150 |
151 | If you publish printed copies (or copies in media that commonly have
152 | printed covers) of the Document, numbering more than 100, and the
153 | Document's license notice requires Cover Texts, you must enclose the
154 | copies in covers that carry, clearly and legibly, all these Cover
155 | Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
156 | the back cover. Both covers must also clearly and legibly identify
157 | you as the publisher of these copies. The front cover must present
158 | the full title with all words of the title equally prominent and
159 | visible. You may add other material on the covers in addition.
160 | Copying with changes limited to the covers, as long as they preserve
161 | the title of the Document and satisfy these conditions, can be treated
162 | as verbatim copying in other respects.
163 |
164 | If the required texts for either cover are too voluminous to fit
165 | legibly, you should put the first ones listed (as many as fit
166 | reasonably) on the actual cover, and continue the rest onto adjacent
167 | pages.
168 |
169 | If you publish or distribute Opaque copies of the Document numbering
170 | more than 100, you must either include a machine-readable Transparent
171 | copy along with each Opaque copy, or state in or with each Opaque copy
172 | a computer-network location from which the general network-using
173 | public has access to download using public-standard network protocols
174 | a complete Transparent copy of the Document, free of added material.
175 | If you use the latter option, you must take reasonably prudent steps,
176 | when you begin distribution of Opaque copies in quantity, to ensure
177 | that this Transparent copy will remain thus accessible at the stated
178 | location until at least one year after the last time you distribute an
179 | Opaque copy (directly or through your agents or retailers) of that
180 | edition to the public.
181 |
182 | It is requested, but not required, that you contact the authors of the
183 | Document well before redistributing any large number of copies, to give
184 | them a chance to provide you with an updated version of the Document.
185 |
186 | @item
187 | MODIFICATIONS
188 |
189 | You may copy and distribute a Modified Version of the Document under
190 | the conditions of sections 2 and 3 above, provided that you release
191 | the Modified Version under precisely this License, with the Modified
192 | Version filling the role of the Document, thus licensing distribution
193 | and modification of the Modified Version to whoever possesses a copy
194 | of it. In addition, you must do these things in the Modified Version:
195 |
196 | @enumerate A
197 | @item
198 | Use in the Title Page (and on the covers, if any) a title distinct
199 | from that of the Document, and from those of previous versions
200 | (which should, if there were any, be listed in the History section
201 | of the Document). You may use the same title as a previous version
202 | if the original publisher of that version gives permission.
203 |
204 | @item
205 | List on the Title Page, as authors, one or more persons or entities
206 | responsible for authorship of the modifications in the Modified
207 | Version, together with at least five of the principal authors of the
208 | Document (all of its principal authors, if it has fewer than five),
209 | unless they release you from this requirement.
210 |
211 | @item
212 | State on the Title page the name of the publisher of the
213 | Modified Version, as the publisher.
214 |
215 | @item
216 | Preserve all the copyright notices of the Document.
217 |
218 | @item
219 | Add an appropriate copyright notice for your modifications
220 | adjacent to the other copyright notices.
221 |
222 | @item
223 | Include, immediately after the copyright notices, a license notice
224 | giving the public permission to use the Modified Version under the
225 | terms of this License, in the form shown in the Addendum below.
226 |
227 | @item
228 | Preserve in that license notice the full lists of Invariant Sections
229 | and required Cover Texts given in the Document's license notice.
230 |
231 | @item
232 | Include an unaltered copy of this License.
233 |
234 | @item
235 | Preserve the section Entitled ``History'', Preserve its Title, and add
236 | to it an item stating at least the title, year, new authors, and
237 | publisher of the Modified Version as given on the Title Page. If
238 | there is no section Entitled ``History'' in the Document, create one
239 | stating the title, year, authors, and publisher of the Document as
240 | given on its Title Page, then add an item describing the Modified
241 | Version as stated in the previous sentence.
242 |
243 | @item
244 | Preserve the network location, if any, given in the Document for
245 | public access to a Transparent copy of the Document, and likewise
246 | the network locations given in the Document for previous versions
247 | it was based on. These may be placed in the ``History'' section.
248 | You may omit a network location for a work that was published at
249 | least four years before the Document itself, or if the original
250 | publisher of the version it refers to gives permission.
251 |
252 | @item
253 | For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
254 | the Title of the section, and preserve in the section all the
255 | substance and tone of each of the contributor acknowledgements and/or
256 | dedications given therein.
257 |
258 | @item
259 | Preserve all the Invariant Sections of the Document,
260 | unaltered in their text and in their titles. Section numbers
261 | or the equivalent are not considered part of the section titles.
262 |
263 | @item
264 | Delete any section Entitled ``Endorsements''. Such a section
265 | may not be included in the Modified Version.
266 |
267 | @item
268 | Do not retitle any existing section to be Entitled ``Endorsements'' or
269 | to conflict in title with any Invariant Section.
270 |
271 | @item
272 | Preserve any Warranty Disclaimers.
273 | @end enumerate
274 |
275 | If the Modified Version includes new front-matter sections or
276 | appendices that qualify as Secondary Sections and contain no material
277 | copied from the Document, you may at your option designate some or all
278 | of these sections as invariant. To do this, add their titles to the
279 | list of Invariant Sections in the Modified Version's license notice.
280 | These titles must be distinct from any other section titles.
281 |
282 | You may add a section Entitled ``Endorsements'', provided it contains
283 | nothing but endorsements of your Modified Version by various
284 | parties---for example, statements of peer review or that the text has
285 | been approved by an organization as the authoritative definition of a
286 | standard.
287 |
288 | You may add a passage of up to five words as a Front-Cover Text, and a
289 | passage of up to 25 words as a Back-Cover Text, to the end of the list
290 | of Cover Texts in the Modified Version. Only one passage of
291 | Front-Cover Text and one of Back-Cover Text may be added by (or
292 | through arrangements made by) any one entity. If the Document already
293 | includes a cover text for the same cover, previously added by you or
294 | by arrangement made by the same entity you are acting on behalf of,
295 | you may not add another; but you may replace the old one, on explicit
296 | permission from the previous publisher that added the old one.
297 |
298 | The author(s) and publisher(s) of the Document do not by this License
299 | give permission to use their names for publicity for or to assert or
300 | imply endorsement of any Modified Version.
301 |
302 | @item
303 | COMBINING DOCUMENTS
304 |
305 | You may combine the Document with other documents released under this
306 | License, under the terms defined in section 4 above for modified
307 | versions, provided that you include in the combination all of the
308 | Invariant Sections of all of the original documents, unmodified, and
309 | list them all as Invariant Sections of your combined work in its
310 | license notice, and that you preserve all their Warranty Disclaimers.
311 |
312 | The combined work need only contain one copy of this License, and
313 | multiple identical Invariant Sections may be replaced with a single
314 | copy. If there are multiple Invariant Sections with the same name but
315 | different contents, make the title of each such section unique by
316 | adding at the end of it, in parentheses, the name of the original
317 | author or publisher of that section if known, or else a unique number.
318 | Make the same adjustment to the section titles in the list of
319 | Invariant Sections in the license notice of the combined work.
320 |
321 | In the combination, you must combine any sections Entitled ``History''
322 | in the various original documents, forming one section Entitled
323 | ``History''; likewise combine any sections Entitled ``Acknowledgements'',
324 | and any sections Entitled ``Dedications''. You must delete all
325 | sections Entitled ``Endorsements.''
326 |
327 | @item
328 | COLLECTIONS OF DOCUMENTS
329 |
330 | You may make a collection consisting of the Document and other documents
331 | released under this License, and replace the individual copies of this
332 | License in the various documents with a single copy that is included in
333 | the collection, provided that you follow the rules of this License for
334 | verbatim copying of each of the documents in all other respects.
335 |
336 | You may extract a single document from such a collection, and distribute
337 | it individually under this License, provided you insert a copy of this
338 | License into the extracted document, and follow this License in all
339 | other respects regarding verbatim copying of that document.
340 |
341 | @item
342 | AGGREGATION WITH INDEPENDENT WORKS
343 |
344 | A compilation of the Document or its derivatives with other separate
345 | and independent documents or works, in or on a volume of a storage or
346 | distribution medium, is called an ``aggregate'' if the copyright
347 | resulting from the compilation is not used to limit the legal rights
348 | of the compilation's users beyond what the individual works permit.
349 | When the Document is included in an aggregate, this License does not
350 | apply to the other works in the aggregate which are not themselves
351 | derivative works of the Document.
352 |
353 | If the Cover Text requirement of section 3 is applicable to these
354 | copies of the Document, then if the Document is less than one half of
355 | the entire aggregate, the Document's Cover Texts may be placed on
356 | covers that bracket the Document within the aggregate, or the
357 | electronic equivalent of covers if the Document is in electronic form.
358 | Otherwise they must appear on printed covers that bracket the whole
359 | aggregate.
360 |
361 | @item
362 | TRANSLATION
363 |
364 | Translation is considered a kind of modification, so you may
365 | distribute translations of the Document under the terms of section 4.
366 | Replacing Invariant Sections with translations requires special
367 | permission from their copyright holders, but you may include
368 | translations of some or all Invariant Sections in addition to the
369 | original versions of these Invariant Sections. You may include a
370 | translation of this License, and all the license notices in the
371 | Document, and any Warranty Disclaimers, provided that you also include
372 | the original English version of this License and the original versions
373 | of those notices and disclaimers. In case of a disagreement between
374 | the translation and the original version of this License or a notice
375 | or disclaimer, the original version will prevail.
376 |
377 | If a section in the Document is Entitled ``Acknowledgements'',
378 | ``Dedications'', or ``History'', the requirement (section 4) to Preserve
379 | its Title (section 1) will typically require changing the actual
380 | title.
381 |
382 | @item
383 | TERMINATION
384 |
385 | You may not copy, modify, sublicense, or distribute the Document
386 | except as expressly provided under this License. Any attempt
387 | otherwise to copy, modify, sublicense, or distribute it is void, and
388 | will automatically terminate your rights under this License.
389 |
390 | However, if you cease all violation of this License, then your license
391 | from a particular copyright holder is reinstated (a) provisionally,
392 | unless and until the copyright holder explicitly and finally
393 | terminates your license, and (b) permanently, if the copyright holder
394 | fails to notify you of the violation by some reasonable means prior to
395 | 60 days after the cessation.
396 |
397 | Moreover, your license from a particular copyright holder is
398 | reinstated permanently if the copyright holder notifies you of the
399 | violation by some reasonable means, this is the first time you have
400 | received notice of violation of this License (for any work) from that
401 | copyright holder, and you cure the violation prior to 30 days after
402 | your receipt of the notice.
403 |
404 | Termination of your rights under this section does not terminate the
405 | licenses of parties who have received copies or rights from you under
406 | this License. If your rights have been terminated and not permanently
407 | reinstated, receipt of a copy of some or all of the same material does
408 | not give you any rights to use it.
409 |
410 | @item
411 | FUTURE REVISIONS OF THIS LICENSE
412 |
413 | The Free Software Foundation may publish new, revised versions
414 | of the GNU Free Documentation License from time to time. Such new
415 | versions will be similar in spirit to the present version, but may
416 | differ in detail to address new problems or concerns. See
417 | @uref{http://www.gnu.org/copyleft/}.
418 |
419 | Each version of the License is given a distinguishing version number.
420 | If the Document specifies that a particular numbered version of this
421 | License ``or any later version'' applies to it, you have the option of
422 | following the terms and conditions either of that specified version or
423 | of any later version that has been published (not as a draft) by the
424 | Free Software Foundation. If the Document does not specify a version
425 | number of this License, you may choose any version ever published (not
426 | as a draft) by the Free Software Foundation. If the Document
427 | specifies that a proxy can decide which future versions of this
428 | License can be used, that proxy's public statement of acceptance of a
429 | version permanently authorizes you to choose that version for the
430 | Document.
431 |
432 | @item
433 | RELICENSING
434 |
435 | ``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any
436 | World Wide Web server that publishes copyrightable works and also
437 | provides prominent facilities for anybody to edit those works. A
438 | public wiki that anybody can edit is an example of such a server. A
439 | ``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the
440 | site means any set of copyrightable works thus published on the MMC
441 | site.
442 |
443 | ``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0
444 | license published by Creative Commons Corporation, a not-for-profit
445 | corporation with a principal place of business in San Francisco,
446 | California, as well as future copyleft versions of that license
447 | published by that same organization.
448 |
449 | ``Incorporate'' means to publish or republish a Document, in whole or
450 | in part, as part of another Document.
451 |
452 | An MMC is ``eligible for relicensing'' if it is licensed under this
453 | License, and if all works that were first published under this License
454 | somewhere other than this MMC, and subsequently incorporated in whole
455 | or in part into the MMC, (1) had no cover texts or invariant sections,
456 | and (2) were thus incorporated prior to November 1, 2008.
457 |
458 | The operator of an MMC Site may republish an MMC contained in the site
459 | under CC-BY-SA on the same site at any time before August 1, 2009,
460 | provided the MMC is eligible for relicensing.
461 |
462 | @end enumerate
463 |
464 | @page
465 | @heading ADDENDUM: How to use this License for your documents
466 |
467 | To use this License in a document you have written, include a copy of
468 | the License in the document and put the following copyright and
469 | license notices just after the title page:
470 |
471 | @smallexample
472 | @group
473 | Copyright (C) @var{year} @var{your name}.
474 | Permission is granted to copy, distribute and/or modify this document
475 | under the terms of the GNU Free Documentation License, Version 1.3
476 | or any later version published by the Free Software Foundation;
477 | with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
478 | Texts. A copy of the license is included in the section entitled ``GNU
479 | Free Documentation License''.
480 | @end group
481 | @end smallexample
482 |
483 | If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
484 | replace the ``with@dots{}Texts.''@: line with this:
485 |
486 | @smallexample
487 | @group
488 | with the Invariant Sections being @var{list their titles}, with
489 | the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
490 | being @var{list}.
491 | @end group
492 | @end smallexample
493 |
494 | If you have Invariant Sections without Cover Texts, or some other
495 | combination of the three, merge those two alternatives to suit the
496 | situation.
497 |
498 | If your document contains nontrivial examples of program code, we
499 | recommend releasing these examples in parallel under your choice of
500 | free software license, such as the GNU General Public License,
501 | to permit their use in free software.
502 |
503 | @c Local Variables:
504 | @c ispell-local-pdict: "ispell-dict"
505 | @c End:
506 |
--------------------------------------------------------------------------------
/img2cowsay:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | magnified='1'
4 | file='-'
5 | dash=0
6 | chroma=1
7 | c=0
8 | platform=xterm
9 |
10 | for arg in "$@"; do
11 | if [ $c = 1 ]; then
12 | c=0
13 | chroma="$arg"
14 | elif [ $dash = 1 ]; then
15 | file="$arg"
16 | elif [ "$arg" = "--" ]; then
17 | dash=1
18 | elif [ "$arg" = "-2" ]; then
19 | magnified=2
20 | elif [ "$arg" = "-c" ]; then
21 | c=1
22 | elif [ "$arg" = "-p" ]; then
23 | platform=linux
24 | else
25 | file="$arg"
26 | fi
27 | done
28 |
29 | java -jar "$(dirname "$0")/util-say.jar" \
30 | --import image --magnified $magnified --file "$file" --balloon n --export cowsay --balloon y --file - --chroma "$chroma" --platform $platform
31 |
32 |
--------------------------------------------------------------------------------
/img2ponysay:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | magnified='1'
4 | file='-'
5 | dash=0
6 | chroma=1
7 | c=0
8 | platform=xterm
9 |
10 | for arg in "$@"; do
11 | if [ $c = 1 ]; then
12 | c=0
13 | chroma="$arg"
14 | elif [ $dash = 1 ]; then
15 | file="$arg"
16 | elif [ "$arg" = "--" ]; then
17 | dash=1
18 | elif [ "$arg" = "-2" ]; then
19 | magnified=2
20 | elif [ "$arg" = "-c" ]; then
21 | c=1
22 | elif [ "$arg" = "-p" ]; then
23 | platform=linux
24 | else
25 | file="$arg"
26 | fi
27 | done
28 |
29 | java -jar "$(dirname "$0")/util-say.jar" \
30 | --import image --magnified $magnified --file "$file" --balloon n --export ponysay --balloon y --file - --chroma "$chroma" --platform $platform
31 |
32 |
--------------------------------------------------------------------------------
/img2unisay:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | magnified='1'
4 | file='-'
5 | dash=0
6 | chroma=1
7 | c=0
8 | platform=xterm
9 |
10 | for arg in "$@"; do
11 | if [ $c = 1 ]; then
12 | c=0
13 | chroma="$arg"
14 | elif [ $dash = 1 ]; then
15 | file="$arg"
16 | elif [ "$arg" = "--" ]; then
17 | dash=1
18 | elif [ "$arg" = "-2" ]; then
19 | magnified=2
20 | elif [ "$arg" = "-c" ]; then
21 | c=1
22 | elif [ "$arg" = "-p" ]; then
23 | platform=linux
24 | else
25 | file="$arg"
26 | fi
27 | done
28 |
29 | java -jar "$(dirname "$0")/util-say.jar" \
30 | --import image --magnified $magnified --file "$file" --balloon n --export unisay --balloon y --file - --chroma "$chroma" --platform $platform
31 |
32 |
--------------------------------------------------------------------------------
/lowcaps.linux.conf:
--------------------------------------------------------------------------------
1 | FREE ZONE::
2 |
3 | This is an example configuration best on Linux VT's cap:s,
4 | without OSI P and with xterms default font.
5 |
6 |
7 | CHROMA::
8 | 1.0
9 |
10 |
11 | FOREGROUND::
12 |
13 | [30m 000000 [39m
14 | [31m AA0000 [39m
15 | [32m 00AA00 [39m
16 | [33m AA5500 [39m
17 | [34m 0000AA [39m
18 | [35m AA00AA [39m
19 | [36m 00AAAA [39m
20 | [37m AAAAAA [39m
21 | [30;1m 555555 [39;21m
22 | [31;1m FF5555 [39;21m
23 | [32;1m 55FF55 [39;21m
24 | [33;1m FFFF55 [39;21m
25 | [34;1m 5555FF [39;21m
26 | [35;1m FF55FF [39;21m
27 | [36;1m 55FFFF [39;21m
28 | [37;1m FFFFFF [39;21m
29 |
30 |
31 | BACKGROUND::
32 |
33 | [41m 000000 [49m
34 | [42m CD0000 [49m
35 | [43m 00CD00 [49m
36 | [44m CDCD00 [49m
37 | [45m 1E90FF [49m
38 | [46m CD00CD [49m
39 | [47m 00CDCD [49m
40 | [48m E5E5E5 [49m
41 |
42 |
43 | DITHERER::
44 |
45 | 78
46 | ▒ 39
47 | ▓ 57
48 | ░ 21
49 | # 20
50 | @ 24
51 | & 16
52 | X 17
53 | Q 22
54 | G 18
55 | g 19
56 | ? 12
57 | B 23
58 | * 11
59 | I 13
60 | f 14
61 | w 15
62 | = 10
63 | + 9
64 | - 5
65 | ~ 7
66 | ' 3
67 | ` 2
68 | , 4
69 |
70 |
71 | FREE ZONE::
72 |
73 | $ 21
74 |
75 | . 5
76 | ^ 5
77 | _ 5
78 | " 6
79 | ! 8
80 | | 9
81 | \ 9
82 | / 9
83 | ; 9
84 | < 9
85 | > 9
86 | : 10
87 | i 10
88 | x 10
89 | r 10
90 | v 11
91 | ( 11
92 | ) 11
93 | l 12
94 | c 12
95 | 7 13
96 | J 13
97 | L 13
98 | T 13
99 | Y 13
100 | j 13
101 | s 13
102 | t 13
103 | u 14
104 | n 14
105 | o 14
106 | z 14
107 | { 14
108 | } 14
109 | k 15
110 | ] 15
111 | [ 15
112 | C 15
113 | 1 15
114 | 0 16
115 | 2 16
116 | F 16
117 | V 16
118 | e 16
119 | a 16
120 | h 17
121 | m 17
122 | Z 17
123 | p 17
124 | q 17
125 | S 17
126 | 4 17
127 | % 17
128 | y 18
129 | 3 18
130 | K 18
131 | P 18
132 | U 19
133 | b 19
134 | d 19
135 | E 20
136 | O 20
137 | 5 20
138 | 6 20
139 | 9 20
140 | A 20
141 | 8 21
142 | H 21
143 | W 22
144 | M 22
145 | R 22
146 | D 22
147 | N 24
148 |
--------------------------------------------------------------------------------
/lowcaps.rxvt.conf:
--------------------------------------------------------------------------------
1 | FREE ZONE::
2 |
3 | This is an example configuration best on xterm's cap:s,
4 | but not with it's full cap:s.
5 |
6 |
7 | CHROMA::
8 | 1.0
9 |
10 |
11 | FOREGROUND::
12 |
13 | [30m 000000 [39m
14 | [31m CD0000 [39m
15 | [32m 00CD00 [39m
16 | [33m CDCD00 [39m
17 | [34m 0000CD [39m
18 | [35m CD00CD [39m
19 | [36m 00CDCD [39m
20 | [37m FAEBD7 [39m
21 | [90m 404040 [39m
22 | [91m FF0000 [39m
23 | [92m 00FF00 [39m
24 | [93m FFFF00 [39m
25 | [94m 0000FF [39m
26 | [95m FF00FF [39m
27 | [96m 00FFFF [39m
28 | [97m FFFFFF [39m
29 |
30 |
31 | BACKGROUND::
32 |
33 | [40m 000000 [49m
34 | [41m CD0000 [49m
35 | [42m 00CD00 [49m
36 | [43m CDCD00 [49m
37 | [44m 0000CD [49m
38 | [45m CD00CD [49m
39 | [46m 00CDCD [49m
40 | [47m FAEBD7 [49m
41 | [100m 404040 [49m
42 | [101m FF0000 [49m
43 | [102m 00FF00 [49m
44 | [103m FFFF00 [49m
45 | [104m 0000FF [49m
46 | [105m FF00FF [49m
47 | [106m 00FFFF [49m
48 | [107m FFFFFF [49m
49 |
50 |
51 | DITHERER::
52 |
53 | 78
54 | ▒ 39
55 | ▓ 57
56 | ░ 21
57 | # 20
58 | @ 24
59 | & 16
60 | X 17
61 | Q 22
62 | G 18
63 | g 19
64 | ? 12
65 | B 23
66 | * 11
67 | I 13
68 | f 14
69 | w 15
70 | = 10
71 | + 9
72 | - 5
73 | ~ 7
74 | ' 3
75 | ` 2
76 | , 4
77 |
78 |
79 | FREE ZONE::
80 |
81 | $ 21
82 |
83 | . 5
84 | ^ 5
85 | _ 5
86 | " 6
87 | ! 8
88 | | 9
89 | \ 9
90 | / 9
91 | ; 9
92 | < 9
93 | > 9
94 | : 10
95 | i 10
96 | x 10
97 | r 10
98 | v 11
99 | ( 11
100 | ) 11
101 | l 12
102 | c 12
103 | 7 13
104 | J 13
105 | L 13
106 | T 13
107 | Y 13
108 | j 13
109 | s 13
110 | t 13
111 | u 14
112 | n 14
113 | o 14
114 | z 14
115 | { 14
116 | } 14
117 | k 15
118 | ] 15
119 | [ 15
120 | C 15
121 | 1 15
122 | 0 16
123 | 2 16
124 | F 16
125 | V 16
126 | e 16
127 | a 16
128 | h 17
129 | m 17
130 | Z 17
131 | p 17
132 | q 17
133 | S 17
134 | 4 17
135 | % 17
136 | y 18
137 | 3 18
138 | K 18
139 | P 18
140 | U 19
141 | b 19
142 | d 19
143 | E 20
144 | O 20
145 | 5 20
146 | 6 20
147 | 9 20
148 | A 20
149 | 8 21
150 | H 21
151 | W 22
152 | M 22
153 | R 22
154 | D 22
155 | N 24
156 |
--------------------------------------------------------------------------------
/lowcaps.tango.conf:
--------------------------------------------------------------------------------
1 | FREE ZONE::
2 |
3 | This is an example configuration best on xterm's cap:s,
4 | but not with it's full cap:s, but with tango colours.
5 |
6 |
7 | CHROMA::
8 | 1.0
9 |
10 |
11 | FOREGROUND::
12 |
13 | [30m 000000 [39m
14 | [31m CC0000 [39m
15 | [32m AE9A06 [39m
16 | [33m C4A000 [39m
17 | [34m 3465A4 [39m
18 | [35m 75507B [39m
19 | [36m 06989A [39m
20 | [37m D3D7CF [39m
21 | [90m 555753 [39m
22 | [91m EF2929 [39m
23 | [92m 8AE234 [39m
24 | [93m FCE94F [39m
25 | [94m 729FCF [39m
26 | [95m AD7FA8 [39m
27 | [96m 34E2E2 [39m
28 | [97m EEEEEC [39m
29 |
30 |
31 | BACKGROUND::
32 |
33 | [40m 000000 [39m
34 | [41m CC0000 [39m
35 | [42m AE9A06 [39m
36 | [43m C4A000 [39m
37 | [44m 3465A4 [39m
38 | [45m 75507B [39m
39 | [46m 06989A [39m
40 | [47m D3D7CF [39m
41 | [100m 555753 [39m
42 | [101m EF2929 [39m
43 | [102m 8AE234 [39m
44 | [193m FCE94F [39m
45 | [104m 729FCF [39m
46 | [105m AD7FA8 [39m
47 | [106m 34E2E2 [39m
48 | [107m EEEEEC [39m
49 |
50 |
51 | DITHERER::
52 |
53 | 78
54 | ▒ 39
55 | ▓ 57
56 | ░ 21
57 | # 20
58 | @ 24
59 | & 16
60 | X 17
61 | Q 22
62 | G 18
63 | g 19
64 | ? 12
65 | B 23
66 | * 11
67 | I 13
68 | f 14
69 | w 15
70 | = 10
71 | + 9
72 | - 5
73 | ~ 7
74 | ' 3
75 | ` 2
76 | , 4
77 |
78 |
79 | FREE ZONE::
80 |
81 | $ 21
82 |
83 | . 5
84 | ^ 5
85 | _ 5
86 | " 6
87 | ! 8
88 | | 9
89 | \ 9
90 | / 9
91 | ; 9
92 | < 9
93 | > 9
94 | : 10
95 | i 10
96 | x 10
97 | r 10
98 | v 11
99 | ( 11
100 | ) 11
101 | l 12
102 | c 12
103 | 7 13
104 | J 13
105 | L 13
106 | T 13
107 | Y 13
108 | j 13
109 | s 13
110 | t 13
111 | u 14
112 | n 14
113 | o 14
114 | z 14
115 | { 14
116 | } 14
117 | k 15
118 | ] 15
119 | [ 15
120 | C 15
121 | 1 15
122 | 0 16
123 | 2 16
124 | F 16
125 | V 16
126 | e 16
127 | a 16
128 | h 17
129 | m 17
130 | Z 17
131 | p 17
132 | q 17
133 | S 17
134 | 4 17
135 | % 17
136 | y 18
137 | 3 18
138 | K 18
139 | P 18
140 | U 19
141 | b 19
142 | d 19
143 | E 20
144 | O 20
145 | 5 20
146 | 6 20
147 | 9 20
148 | A 20
149 | 8 21
150 | H 21
151 | W 22
152 | M 22
153 | R 22
154 | D 22
155 | N 24
156 |
--------------------------------------------------------------------------------
/lowcaps.xterm.conf:
--------------------------------------------------------------------------------
1 | FREE ZONE::
2 |
3 | This is an example configuration best on xterm's cap:s,
4 | but not with it's full cap:s.
5 |
6 |
7 | CHROMA::
8 | 1.0
9 |
10 |
11 | FOREGROUND::
12 |
13 | [30m 000000 [39m
14 | [31m CD0000 [39m
15 | [32m 00CD00 [39m
16 | [33m CDCD00 [39m
17 | [34m 1E90FF [39m
18 | [35m CD00CD [39m
19 | [36m 00CDCD [39m
20 | [37m E5E5E5 [39m
21 | [90m 4C4C4C [39m
22 | [91m FF0000 [39m
23 | [92m 00FF00 [39m
24 | [93m FFFF00 [39m
25 | [94m 4682B4 [39m
26 | [95m FF00FF [39m
27 | [96m 00FFFF [39m
28 | [97m FFFFFF [39m
29 |
30 |
31 | BACKGROUND::
32 |
33 | [40m 000000 [49m
34 | [41m CD0000 [49m
35 | [42m 00CD00 [49m
36 | [43m CDCD00 [49m
37 | [44m 1E90FF [49m
38 | [45m CD00CD [49m
39 | [46m 00CDCD [49m
40 | [47m E5E5E5 [49m
41 | [100m 4C4C4C [49m
42 | [101m FF0000 [49m
43 | [102m 00FF00 [49m
44 | [103m FFFF00 [49m
45 | [104m 4682B4 [49m
46 | [105m FF00FF [49m
47 | [106m 00FFFF [49m
48 | [107m FFFFFF [49m
49 |
50 |
51 | DITHERER::
52 |
53 | 78
54 | ▒ 39
55 | ▓ 57
56 | ░ 21
57 | # 20
58 | @ 24
59 | & 16
60 | X 17
61 | Q 22
62 | G 18
63 | g 19
64 | ? 12
65 | B 23
66 | * 11
67 | I 13
68 | f 14
69 | w 15
70 | = 10
71 | + 9
72 | - 5
73 | ~ 7
74 | ' 3
75 | ` 2
76 | , 4
77 |
78 |
79 | FREE ZONE::
80 |
81 | $ 21
82 |
83 | . 5
84 | ^ 5
85 | _ 5
86 | " 6
87 | ! 8
88 | | 9
89 | \ 9
90 | / 9
91 | ; 9
92 | < 9
93 | > 9
94 | : 10
95 | i 10
96 | x 10
97 | r 10
98 | v 11
99 | ( 11
100 | ) 11
101 | l 12
102 | c 12
103 | 7 13
104 | J 13
105 | L 13
106 | T 13
107 | Y 13
108 | j 13
109 | s 13
110 | t 13
111 | u 14
112 | n 14
113 | o 14
114 | z 14
115 | { 14
116 | } 14
117 | k 15
118 | ] 15
119 | [ 15
120 | C 15
121 | 1 15
122 | 0 16
123 | 2 16
124 | F 16
125 | V 16
126 | e 16
127 | a 16
128 | h 17
129 | m 17
130 | Z 17
131 | p 17
132 | q 17
133 | S 17
134 | 4 17
135 | % 17
136 | y 18
137 | 3 18
138 | K 18
139 | P 18
140 | U 19
141 | b 19
142 | d 19
143 | E 20
144 | O 20
145 | 5 20
146 | 6 20
147 | 9 20
148 | A 20
149 | 8 21
150 | H 21
151 | W 22
152 | M 22
153 | R 22
154 | D 22
155 | N 24
156 |
--------------------------------------------------------------------------------
/ponysay2img:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | magnified='1'
4 | file='-'
5 | dash=0
6 |
7 | for arg in "$@"; do
8 | if [ $dash = 1 ]; then
9 | file="$arg"
10 | elif [ "$arg" = "--" ]; then
11 | dash=1
12 | elif [ "$arg" = "-2" ]; then
13 | magnified=2
14 | else
15 | file="$arg"
16 | fi
17 | done
18 |
19 | java -jar "$(dirname "$0")/util-say.jar" \
20 | --import ponysay --file - --export image --magnified $magnified --file "$file" --left - --right - --bottom - --top -
21 |
22 |
--------------------------------------------------------------------------------
/ponysay2ttyponysay:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | p=0
4 | palette=''
5 |
6 | for arg in "$@"; do
7 | if [ $p = 1 ]; then
8 | p=0
9 | palette="$arg"
10 | elif [ "$arg" = '-p' ]; then
11 | p=1
12 | fi
13 | done
14 |
15 | java -jar "$(dirname "$0")/util-say.jar" \
16 | --import ponysay --file - --export ponysay --file - --left - --right - --bottom - --top - --palette "$palette"
17 |
18 |
--------------------------------------------------------------------------------
/ponytool:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | java -jar "$(dirname "$0")/util-say.jar" "$@"
3 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/Cat.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.io.*;
22 | import java.util.*;
23 |
24 |
25 | /**
26 | *
cat printable pony module
27 | *
28 | * Note that the cat-printablilty may be disrupted by stores and recalls!
29 | *
30 | *
31 | * @author Mattias Andrée, m@maandree.se
32 | */
33 | public class Cat extends Ponysay
34 | {
35 | /**
36 | * Constructor
37 | *
38 | * @param flags Flags passed to the module
39 | */
40 | public Cat(HashMap flags)
41 | {
42 | super(Cat.modifyFlags(flags));
43 | }
44 |
45 |
46 | /**
47 | * Modify the flags to fit this module
48 | *
49 | * @param flag The flags
50 | * @return The flags
51 | */
52 | private static HashMap modifyFlags(HashMap flags)
53 | {
54 | flags.put("ignoreballoon", "y");
55 | flags.put("ignorelink", "y");
56 | flags.put("balloon", "-");
57 | flags.put("version", "2.8");
58 | return flags;
59 | }
60 |
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/Colour.java:
--------------------------------------------------------------------------------
1 | //####################################################################################
2 | //## The following code is pasted from TWT, but the class is made package private ##
3 | //## and the package has been changed to se.kth.maandree.utilsay ##
4 | //## toLab(...) as also been publicised. ##
5 | //####################################################################################
6 |
7 |
8 | /**
9 | * TWT — Terminal Window Toolkit, a free pure Java terminal toolkit.
10 | * Copyright (C) 2011 Mattias Andrée
11 | *
12 | * This library is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This library is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 | *
22 | * You should have received a copy of the GNU General Public License
23 | * along with this library. If not, see .
24 | */
25 | package se.kth.maandree.utilsay;
26 |
27 |
28 | /**
29 | * Terminal colour class
30 | *
31 | * @author Mattias Andrée, m@maandree.se
32 | */
33 | public class Colour
34 | {
35 | /**
36 | * Possible colour intensitivities on mixed colours
37 | */
38 | public static final int[] COLOUR_INTENSITIVITY = {0, 95, 135, 175, 215, 255};
39 |
40 | /**
41 | * Possible intensitivities on grey colours, excluding the mixed colours' intensitivities
42 | */
43 | public static final int[] GREY_EXTRA_INTENSITIVITY = {8, 18, 28, 38, 48, 58, 68, 78, 88, 98, 108, 118, 128,
44 | 138, 148, 158, 168, 178, 188, 198, 208, 218, 228, 238};
45 |
46 | /**
47 | * Possible intensitivities on mixed colours, including the mixed colours' intensitivities
48 | */
49 | public static final int[] GREY_FULL_INTENSITIVITY = {0, 8, 18, 28, 38, 48, 58, 68, 78, 88, 95, 98, 108, 118, 128, 135,
50 | 138, 148, 158, 168, 175, 178, 188, 198, 208, 218, 215, 228, 238, 255};
51 |
52 |
53 |
54 | /**
55 | * Constructor
56 | *
57 | * Selects the colour by index
58 | *
59 | *
60 | * @param index The colour's index [0–255]
61 | */
62 | @SuppressWarnings("hiding")
63 | public Colour(final byte index)
64 | {
65 | final int[] I = COLOUR_INTENSITIVITY;
66 |
67 | int i = index; if (i < 0) i += 1 << 8;
68 |
69 | if ((this.index = i) < 16)
70 | {
71 | this.systemColour = true;
72 | this.red = new int[] { 0, 128, 0, 128, 0, 128, 0, 192,
73 | 128, 255, 0, 255, 0, 255, 0, 255} [i];
74 | this.green = new int[] { 0, 0, 128, 128, 0, 0, 128, 192,
75 | 128, 0, 255, 255, 0, 0, 255, 255} [i];
76 | this.blue = new int[] { 0, 0, 0, 0, 128, 128, 128, 192,
77 | 128, 0, 0, 0, 255, 255, 255, 255} [i];
78 | }
79 | else
80 | {
81 | this.systemColour = false;
82 | if (i < 232)
83 | {
84 | final int j = i - 16, b, g;
85 | this.blue = COLOUR_INTENSITIVITY[b = j % 6];
86 | this.green = COLOUR_INTENSITIVITY[g = ((j - b) / 6) % 6];
87 | this.red = COLOUR_INTENSITIVITY[(j - b - g * 6) / (6 * 6)];
88 | }
89 | else
90 | this.red = this.green = this.blue = (i - 232) * 10 + 8;
91 | }
92 | }
93 |
94 | /**
95 | * Constructor
96 | *
97 | * Selects the colour the closest the a proper terminal colour
98 | *
99 | *
100 | * @param red The red intensity [0–255]
101 | * @param green The green intensity [0–255]
102 | * @param blue The blue intensity [0–255]
103 | */
104 | @SuppressWarnings("hiding")
105 | public Colour(final byte red, final byte green, final byte blue)
106 | {
107 | final int[] I = COLOUR_INTENSITIVITY;
108 |
109 | int r = red ; if (r < 0) r += 1 << 8;
110 | int g = green; if (g < 0) g += 1 << 8;
111 | int b = blue ; if (b < 0) b += 1 << 8;
112 |
113 | int d, ð, dr, db, dg; dr = db = dg = 0;
114 |
115 | int ir = -1, ig = -1, ib = -1, ii = -1;
116 |
117 | d = 500; for (int cr : I) if (d > (ð = Math.abs(cr - r))) {d = ð; dr = cr; ir++;} else break;
118 | d = 500; for (int cg : I) if (d > (ð = Math.abs(cg - g))) {d = ð; dg = cg; ig++;} else break;
119 | d = 500; for (int cb : I) if (d > (ð = Math.abs(cb - b))) {d = ð; db = cb; ib++;} else break;
120 |
121 | d = (dr - r)*(dr - r) + (dg - g)*(dg - g) + (db - b)*(db - b);
122 |
123 | for (int gr = 8; gr <= 238; gr += 10)
124 | {
125 | int ðr = gr - r;
126 | int ðg = gr - g;
127 | int ðb = gr - b;
128 |
129 | ð = ðr*ðr + ðg*ðg + ðb*ðb;
130 |
131 | if (d > ð)
132 | {
133 | d = ð;
134 | dr = gr;
135 | dg = gr;
136 | db = gr;
137 | ii = (gr - 8) / 10;
138 | }
139 | }
140 |
141 | this.systemColour = false;
142 | this.red = dr;
143 | this.green = dg;
144 | this.blue = db;
145 | this.index = ii < 0 ? (16 + (ir * 6 + ig) * 6 + ib) : ii + 232;
146 | }
147 |
148 | /**
149 | * Constructor
150 | *
151 | * Selects the colour by index
152 | *
153 | *
154 | * @param index The colour's index [0–255]
155 | */
156 | @SuppressWarnings("hiding")
157 | public Colour(final int index)
158 | {
159 | this((byte)index);
160 | }
161 |
162 | /**
163 | * Constructor
164 | *
165 | * Selects the colour the closest the a proper terminal colour
166 | *
167 | *
168 | * @param red The red intensity [0–255]
169 | * @param green The green intensity [0–255]
170 | * @param blue The blue intensity [0–255]
171 | */
172 | @SuppressWarnings("hiding")
173 | public Colour(final int red, final int green, final int blue)
174 | {
175 | this((byte)red, (byte)green, (byte)blue);
176 | }
177 |
178 | /**
179 | * Constructor
180 | *
181 | * Selects the colour the closest the a proper terminal colour
182 | *
183 | *
184 | * @param red The red intensity [0–255]
185 | * @param green The green intensity [0–255]
186 | * @param blue The blue intensity [0–255]
187 | * @param chromaWeight The weight of chromaticity [0–∞[, 1 is unweighted
188 | */
189 | @SuppressWarnings("hiding")
190 | public Colour(final int red, final int green, final int blue, final double chromaWeight)
191 | {
192 | if ((labs == null) || (chromaWeight != lastCW))
193 | {
194 | if (labs == null)
195 | labs = new double[240][];
196 | for (int b = 0; b < 6; b++)
197 | for (int g = 0; g < 6; g++)
198 | for (int r = 0; r < 6; r++)
199 | labs[r * 36 + g * 6 + b] = toLab(COLOUR_INTENSITIVITY[r],
200 | COLOUR_INTENSITIVITY[g],
201 | COLOUR_INTENSITIVITY[b],
202 | chromaWeight);
203 |
204 | for (int s = 0; s < 24; s++)
205 | labs[216 + s] = toLab(GREY_EXTRA_INTENSITIVITY[s],
206 | GREY_EXTRA_INTENSITIVITY[s],
207 | GREY_EXTRA_INTENSITIVITY[s],
208 | chromaWeight);
209 | }
210 |
211 | final double[] lab = toLab(red, green, blue, chromaWeight);
212 | final double L = lab[0], a = lab[1], b = lab[2];
213 |
214 | double d = -100.;
215 | int best = 0;
216 |
217 | for (int i = 0; i < 240; i++)
218 | {
219 | final double[] tLab = labs[i];
220 | double ðL = L - tLab[0];
221 | double ða = a - tLab[1];
222 | double ðb = b - tLab[2];
223 |
224 | double ð = ðL*ðL + ða*ða + ðb*ðb;
225 |
226 | if ((d > ð) || (d < -50.))
227 | {
228 | d = ð;
229 | best = i;
230 | }
231 | }
232 |
233 | final Colour that = new Colour(best + 16);
234 |
235 | this.red = that.red;
236 | this.green = that.green;
237 | this.blue = that.blue;
238 | this.index = that.index;
239 | this.systemColour = that.systemColour;
240 | }
241 |
242 |
243 |
244 | /**
245 | * The red intensity [0–255]
246 | */
247 | public final int red;
248 |
249 | /**
250 | * The green intensity [0–255]
251 | */
252 | public final int green;
253 |
254 | /**
255 | * The blue intensity [0–255]
256 | */
257 | public final int blue;
258 |
259 | /**
260 | * The colour's index [0–255]
261 | */
262 | public final int index;
263 |
264 | /**
265 | * Whether the colour is a system colour
266 | */
267 | public final boolean systemColour;
268 |
269 |
270 | /**
271 | * The static colours converted to CIELAB
272 | */
273 | private static double[][] labs = null;
274 |
275 |
276 | /**
277 | * The chroma weight used when creating {@link #labs}
278 | */
279 | private static double lastCW = 0;
280 |
281 |
282 |
283 | /**
284 | * {@inheritDoc}
285 | */
286 | @Override
287 | public int hashCode()
288 | {
289 | return this.index;
290 | }
291 |
292 | /**
293 | * {@inheritDoc}
294 | */
295 | @Override
296 | public boolean equals(final Object o)
297 | {
298 | if ((o == null) || !(o instanceof Colour))
299 | return false;
300 |
301 | return ((Colour)o).index == this.index;
302 | }
303 |
304 |
305 | /**
306 | * Converts from sRGB to CIELAB
307 | *
308 | * @param red The red intensity [0–255]
309 | * @param green The green intensity [0–255]
310 | * @param blue The blue intensity [0–255]
311 | * @param chromaWeight The weight of chromaticity [0–∞[, 1 is unweighted
312 | * @return {L*, a*, b}
313 | */
314 | public static double[] toLab(final int red, final int green, final int blue, final double chromaWeight)
315 | {
316 | int ir = red ; if (ir < 0) ir += 1 << 8;
317 | int ig = green; if (ig < 0) ig += 1 << 8;
318 | int ib = blue ; if (ib < 0) ib += 1 << 8;
319 |
320 | double r = ir / 255.; r = r <= 0.4045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
321 | double g = ig / 255.; g = g <= 0.4045 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
322 | double b = ib / 255.; b = b <= 0.4045 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
323 |
324 | double x = (0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / 0.95047;
325 | double y = (0.2126729 * r + 0.7151522 * g + 0.0721750 * b);
326 | double z = (0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / 1.08883;
327 |
328 | x = x > 0.00885642 ? Math.pow(x, 1. / 3.) : (7.78 + 703. / 99900.) * x + 0.1379310;
329 | y = y > 0.00885642 ? Math.pow(y, 1. / 3.) : (7.78 + 703. / 99900.) * y + 0.1379310;
330 | z = z > 0.00885642 ? Math.pow(z, 1. / 3.) : (7.78 + 703. / 99900.) * z + 0.1379310;
331 |
332 | final double rcL = 116 * y - 16;
333 | final double rca = 500 * (x - y) * chromaWeight;
334 | final double rcb = 200 * (y - z) * chromaWeight;
335 |
336 | return new double[] {rcL, rca, rcb};
337 | }
338 |
339 |
340 |
341 | /**
342 | * System colour initialisation index counter
343 | */
344 | private static byte sciic = 0;
345 |
346 |
347 | /**
348 | * System colour: black
349 | */
350 | public static final Colour SYSTEM_BLACK = new Colour(sciic++);
351 |
352 | /**
353 | * System colour: medium red
354 | */
355 | public static final Colour SYSTEM_RED = new Colour(sciic++);
356 |
357 | /**
358 | * System colour: medium green
359 | */
360 | public static final Colour SYSTEM_GREEN = new Colour(sciic++);
361 |
362 | /**
363 | * System colour: medium yellow, dark orange or brown
364 | */
365 | public static final Colour SYSTEM_YELLOW = new Colour(sciic++);
366 |
367 | /**
368 | * System colour: medium blue
369 | */
370 | public static final Colour SYSTEM_BLUE = new Colour(sciic++);
371 |
372 | /**
373 | * System colour: medium magenta or medium lilac
374 | */
375 | public static final Colour SYSTEM_MAGENTA = new Colour(sciic++);
376 |
377 | /**
378 | * System colour: medium cyan or medium turquoise
379 | */
380 | public static final Colour SYSTEM_CYAN = new Colour(sciic++);
381 |
382 | /**
383 | * System colour: dark grey
384 | */
385 | public static final Colour SYSTEM_GREY = new Colour(sciic++);
386 |
387 | /**
388 | * System colour: light grey
389 | */
390 | public static final Colour SYSTEM_INTENSIVE_BLACK = new Colour(sciic++);
391 |
392 | /**
393 | * System colour: light red
394 | */
395 | public static final Colour SYSTEM_INTENSIVE_RED = new Colour(sciic++);
396 |
397 | /**
398 | * System colour: light green
399 | */
400 | public static final Colour SYSTEM_INTENSIVE_GREEN = new Colour(sciic++);
401 |
402 | /**
403 | * System colour: light yellow or medium orange
404 | */
405 | public static final Colour SYSTEM_INTENSIVE_YELLOW = new Colour(sciic++);
406 |
407 | /**
408 | * System colour: light blue
409 | */
410 | public static final Colour SYSTEM_INTENSIVE_BLUE = new Colour(sciic++);
411 |
412 | /**
413 | * System colour: light magenta or light lilac
414 | */
415 | public static final Colour SYSTEM_INTENSIVE_MAGENTA = new Colour(sciic++);
416 |
417 | /**
418 | * System colour: light cyan or light turquoise
419 | */
420 | public static final Colour SYSTEM_INTENSIVE_CYAN = new Colour(sciic++);
421 |
422 | /**
423 | * System colour: white
424 | */
425 | public static final Colour SYSTEM_INTENSIVE_GREY = new Colour(sciic++);
426 |
427 |
428 | /**
429 | * System independent colour: pitch black
430 | */
431 | public static final Colour PURE_BLACK = new Colour(0, 0, 0);
432 |
433 | /**
434 | * System independent colour: medium red
435 | */
436 | public static final Colour PURE_RED = new Colour(175, 0, 0);
437 |
438 | /**
439 | * System independent colour: medium green
440 | */
441 | public static final Colour PURE_GREEN = new Colour(0, 175, 0);
442 |
443 | /**
444 | * System independent colour: medium yellow
445 | */
446 | public static final Colour PURE_YELLOW = new Colour(175, 175, 0);
447 |
448 | /**
449 | * System independent colour: medium blue
450 | */
451 | public static final Colour PURE_BLUE = new Colour(0, 0, 175);
452 |
453 | /**
454 | * System independent colour: medium magenta
455 | */
456 | public static final Colour PURE_MAGENTA = new Colour(175, 0, 175);
457 |
458 | /**
459 | * System independent colour: medium cyan
460 | */
461 | public static final Colour PURE_CYAN = new Colour(0, 175, 175);
462 |
463 | /**
464 | * System independent colour: dark grey
465 | */
466 | public static final Colour PURE_GREY = new Colour(198, 192, 192);
467 |
468 | /**
469 | * System independent colour: light grey
470 | */
471 | public static final Colour PURE_INTENSIVE_BLACK = new Colour(127, 128, 128);
472 |
473 | /**
474 | * System independent colour: light red
475 | */
476 | public static final Colour PURE_INTENSIVE_RED = new Colour(255, 0, 0);
477 |
478 | /**
479 | * System independent colour: light green
480 | */
481 | public static final Colour PURE_INTENSIVE_GREEN = new Colour(0, 255, 0);
482 |
483 | /**
484 | * System independent colour: light yellow
485 | */
486 | public static final Colour PURE_INTENSIVE_YELLOW = new Colour(255, 255, 0);
487 |
488 | /**
489 | * System independent colour: light blue
490 | */
491 | public static final Colour PURE_INTENSIVE_BLUE = new Colour(0, 0, 255);
492 |
493 | /**
494 | * System independent colour: light magenta
495 | */
496 | public static final Colour PURE_INTENSIVE_MAGENTA = new Colour(255, 0, 255);
497 |
498 | /**
499 | * System independent colour: light cyan
500 | */
501 | public static final Colour PURE_INTENSIVE_CYAN = new Colour(0, 255, 255);
502 |
503 | /**
504 | * System independent colour: pure white
505 | */
506 | public static final Colour PURE_INTENSIVE_GREY = new Colour(0, 255, 255);
507 |
508 | }
509 |
510 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/Common.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 |
22 | /**
23 | * Module common functionallity
24 | *
25 | * @author Mattias Andrée, m@maandree.se
26 | */
27 | public class Common
28 | {
29 | /**
30 | * Non-constructor
31 | */
32 | private Common()
33 | {
34 | assert false : "This class [Common] is not meant to be instansiated.";
35 | }
36 | // TODO padding should not move the balloon
37 |
38 |
39 |
40 | /**
41 | * Place a balloon in the top left of a {@link Pony} and create a link
42 | *
43 | * @param pony The pony to edit
44 | * @param space The additional space at the top
45 | */
46 | public static void insertBalloon(Pony pony, int space)
47 | {
48 | int y = 0, x = 0, h = pony.matrix.length;
49 | outer:
50 | for (; y <= h; y++)
51 | { if (y == h)
52 | { y = x = -1;
53 | break;
54 | }
55 | int w = pony.matrix[y].length;
56 | for (x = 0; x < w; x++)
57 | { Pony.Cell cell = pony.matrix[y][x];
58 | int character = cell == null ? ' ' : cell.character;
59 | if (character >= 0)
60 | { if ((character != ' ') && (character != ' '))
61 | break outer;
62 | }
63 | else if (character == Pony.Cell.PIXELS)
64 | if ((cell.upperColour != null) && (cell.lowerColour != null))
65 | break outer;
66 | } }
67 |
68 | if (y >= 0)
69 | { System.arraycopy(pony.matrix, 0, pony.matrix = new Pony.Cell[h + 1 + space][], 1 + space, h);
70 | System.arraycopy(pony.metamatrix, 0, pony.metamatrix = new Pony.Meta[h + 1 + space][][], 1 + space, h);
71 | int w = pony.matrix[1 + space].length;
72 | for (int i = 0, mw = w + 1; i <= space; i++)
73 | { pony.matrix[i] = new Pony.Cell[w];
74 | pony.metamatrix[i] = new Pony.Meta[mw][];
75 | }
76 | pony.height = h += 1 + space;
77 | y += 1 + space;
78 | if (y > x)
79 | for (int i = 0; i < h; i++)
80 | { w = pony.matrix[i].length;
81 | System.arraycopy(pony.matrix[i], 0, pony.matrix[i] = new Pony.Cell[w], 0, w);
82 | System.arraycopy(pony.metamatrix[i], 0, pony.metamatrix[i] = new Pony.Meta[w + 1][], 0, w + 1);
83 | }
84 | x -= y;
85 | if (x < -1)
86 | x = -1;
87 |
88 | for (int i = 1; i < y; i++)
89 | pony.matrix[i][x + i] = new Pony.Cell(Pony.Cell.NNW_SSE, null, null, null);
90 | }
91 | else if ((h == 0) || (pony.matrix[0].length == 0))
92 | { pony.height = pony.width = 1;
93 | pony.matrix = new Pony.Cell[1][1];
94 | pony.metamatrix = new Pony.Meta[1][1][];
95 | }
96 |
97 | Pony.Balloon speechballoon = new Pony.Balloon(null, null, new Integer(Math.max(x, 5)), null, null, null, Pony.Balloon.NONE);
98 | if (pony.metamatrix[0][0] == null)
99 | pony.metamatrix[0][0] = new Pony.Meta[] { speechballoon };
100 | else
101 | { System.arraycopy(pony.metamatrix[0][0], 0, pony.metamatrix[0][0] = new Pony.Meta[pony.metamatrix[0][0].length + 1], 1, pony.metamatrix[0][0].length - 1);
102 | pony.metamatrix[0][0][0] = speechballoon;
103 | }
104 | }
105 |
106 |
107 | /**
108 | * Change the margins in a {@link Pony}
109 | *
110 | * @param pony The the pony, the attributes {@link Pony#matrix} and {@link Pony#metamatrix} but not {@link Pony#height} nor {@link Pony#width} will be updated
111 | * @param left The left margin, negative for unmodified
112 | * @param right The right margin, negative for unmodified
113 | * @param top The top margin, negative for unmodified
114 | * @param bottom The bottom margin, negative for unmodified
115 | * @return The update {@code {left, right, top, bottom}}
116 | */
117 | public static int[] changeMargins(Pony pony, int left, int right, int top, int bottom)
118 | {
119 | /*if ((bottom >= 0) && (top >= 0))
120 | bottom += top;*/
121 |
122 | Pony.Cell[][] matrix = pony.matrix;
123 | Pony.Meta[][][] metamatrix = pony.metamatrix;
124 |
125 | if (left >= 0)
126 | {
127 | int cur = 0;
128 | outer:
129 | for (int n = matrix[0].length; cur < n; cur++)
130 | for (int j = 0, m = matrix.length; j < m; j++)
131 | {
132 | boolean cellpass = true;
133 | Pony.Cell cell = matrix[j][cur];
134 | if (cell != null)
135 | if ((cell.character != ' ') || (cell.lowerColour != null))
136 | if ((cell.character != Pony.Cell.PIXELS) || (cell.lowerColour != null) || (cell.upperColour != null))
137 | cellpass = false;
138 | Pony.Meta[] meta = metamatrix[j][cur];
139 | if ((meta != null) && (meta.length != 0))
140 | { for (int k = 0, l = meta.length; k < l; k++)
141 | if ((meta[k] != null) && ((meta[k] instanceof Pony.Store) == false))
142 | if ((cellpass == false) || (meta[k] instanceof Pony.Balloon))
143 | break outer;
144 | }
145 | else
146 | if (cellpass == false)
147 | break outer;
148 | }
149 | left -= cur;
150 | // if (left < 0)
151 | // {
152 | // int w = matrix[0].length;
153 | // for (int j = 0, n = matrix.length; j < n; j++)
154 | // { System.arraycopy(matrix[j], 0, matrix[j] = new Pony.Cell[w - left], -left, w);
155 | // System.arraycopy(metamatrix[j], 0, metamatrix[j] = new Pony.Meta[w + 1 - left][], -left, w + 1);
156 | // }
157 | // left = 0;
158 | // }
159 | }
160 | else
161 | left = 0;
162 | if (right >= 0)
163 | {
164 | int cur = 0;
165 | outer:
166 | for (int n = matrix[0].length - 1; cur <= n; cur++)
167 | for (int j = 0, m = matrix.length; j < m; j++)
168 | {
169 | boolean cellpass = true;
170 | Pony.Cell cell = matrix[j][n - cur];
171 | if (cell != null)
172 | if ((cell.character != ' ') || (cell.lowerColour != null))
173 | if ((cell.character != Pony.Cell.PIXELS) || (cell.lowerColour != null) || (cell.upperColour != null))
174 | cellpass = false;
175 | Pony.Meta[] meta = metamatrix[j][n - cur];
176 | if ((meta != null) && (meta.length != 0))
177 | { for (int k = 0, l = meta.length; k < l; k++)
178 | if ((meta[k] != null) && ((meta[k] instanceof Pony.Store) == false))
179 | if ((cellpass == false) || (meta[k] instanceof Pony.Balloon))
180 | break outer;
181 | }
182 | else
183 | if (cellpass == false)
184 | break outer;
185 | }
186 | right -= cur;
187 | // if (right < 0)
188 | // {
189 | // int w = matrix[0].length;
190 | // for (int j = 0, n = matrix.length; j < n; j++)
191 | // { System.arraycopy(matrix[j], 0, matrix[j] = new Pony.Cell[w - right], 0, w);
192 | // System.arraycopy(metamatrix[j], 0, metamatrix[j] = new Pony.Meta[w + 1 - right][], 0, w + 1);
193 | // }
194 | // right = 0;
195 | // }
196 | }
197 | else
198 | right = 0;
199 | if (top >= 0)
200 | {
201 | int cur = 0, m = Math.min(matrix[0].length + right, matrix[0].length);
202 | outer:
203 | for (int n = matrix.length; cur < n; cur++)
204 | { Pony.Cell[] row = matrix[cur];
205 | Pony.Meta[][] metarow = metamatrix[cur];
206 | for (int j = Math.max(-left, 0); j < m; j++)
207 | {
208 | boolean cellpass = true;
209 | Pony.Cell cell = row[j];
210 | if (cell != null)
211 | if ((cell.character != ' ') || (cell.lowerColour != null))
212 | if ((cell.character != Pony.Cell.PIXELS) || (cell.lowerColour != null) || (cell.upperColour != null))
213 | cellpass = false;
214 | Pony.Meta[] meta = metarow[j];
215 | if ((meta != null) && (meta.length != 0))
216 | { for (int k = 0, l = meta.length; k < l; k++)
217 | if ((meta[k] != null) && ((meta[k] instanceof Pony.Store) == false))
218 | if ((cellpass == false) || (meta[k] instanceof Pony.Balloon))
219 | break outer;
220 | }
221 | else
222 | if (cellpass == false)
223 | break outer;
224 | } }
225 | top -= cur;
226 | //if (top < 0)
227 | // {
228 | // int w = matrix[0].length;
229 | // System.arraycopy(matrix, 0, matrix = new Pony.Cell[matrix.length - top][], -top, matrix.length + top);
230 | // System.arraycopy(new Pony.Cell[-top][w], 0, matrix, 0, -top);
231 | // System.arraycopy(metamatrix, 0, metamatrix = new Pony.Meta[metamatrix.length - top][][], -top, metamatrix.length + top);
232 | // System.arraycopy(new Pony.Meta[-top][w + 1][], 0, metamatrix, 0, -top);
233 | // top = 0;
234 | // }
235 | }
236 | else
237 | top = 0;
238 | if (bottom >= 0)
239 | {
240 | int cur = 0, m = Math.min(matrix[0].length + right, matrix[0].length);
241 | outer:
242 | for (int n = matrix.length - 1/* + top*/; cur <= n; cur++)
243 | if (n - cur < matrix.length)
244 | { Pony.Cell[] row = matrix[n - cur];
245 | Pony.Meta[][] metarow = metamatrix[n - cur];
246 | for (int j = Math.max(-left, 0); j < m; j++)
247 | {
248 | boolean cellpass = true;
249 | Pony.Cell cell = row[j];
250 | if (cell != null)
251 | if ((cell.character != ' ') || (cell.lowerColour != null))
252 | if ((cell.character != Pony.Cell.PIXELS) || (cell.lowerColour != null) || (cell.upperColour != null))
253 | cellpass = false;
254 | Pony.Meta[] meta = metarow[j];
255 | if ((meta != null) && (meta.length != 0))
256 | { for (int k = 0, l = meta.length; k < l; k++)
257 | if ((meta[k] != null) && ((meta[k] instanceof Pony.Store) == false))
258 | if ((cellpass == false) || (meta[k] instanceof Pony.Balloon))
259 | break outer;
260 | }
261 | else
262 | if (cellpass == false)
263 | break outer;
264 | } }
265 | bottom -= cur;
266 | // if (bottom < 0)
267 | // {
268 | // int h = matrix.length;
269 | // System.arraycopy(matrix, 0, matrix = new Pony.Cell[matrix.length - bottom][], 0, matrix.length + bottom);
270 | // System.arraycopy(new Pony.Cell[-bottom][matrix[0].length], 0, matrix, h, -bottom);
271 | // System.arraycopy(metamatrix, 0, metamatrix = new Pony.Meta[metamatrix.length - bottom][][], 0, metamatrix.length + bottom);
272 | // System.arraycopy(new Pony.Meta[-bottom][metamatrix[0].length][], 0, metamatrix, h, -bottom);
273 | // bottom = 0;
274 | // }
275 | }
276 | else
277 | bottom = 0;
278 |
279 |
280 | if (left > 0)
281 | { int w = matrix[0].length;
282 | for (int y = 0, h = matrix.length; y < h; y++)
283 | {
284 | System.arraycopy(matrix[y], 0, matrix[y] = new Pony.Cell[w + left], left, w);
285 | System.arraycopy(metamatrix[y], 0, metamatrix[y] = new Pony.Meta[w + 1 + left][], left, w + 1);
286 | }
287 | left = 0;
288 | }
289 | else
290 | left = -left;
291 |
292 | if (right > 0)
293 | { int w = matrix[0].length;
294 | for (int y = 0, h = matrix.length; y < h; y++)
295 | {
296 | System.arraycopy(matrix[y], 0, matrix[y] = new Pony.Cell[w + right], 0, w);
297 | System.arraycopy(metamatrix[y], 0, metamatrix[y] = new Pony.Meta[w + 1 + right][], 0, w + 1);
298 | }
299 | right = 0;
300 | }
301 | else
302 | right = -right;
303 |
304 | if (top > 0)
305 | {
306 | int h = matrix.length, w = matrix[0].length;
307 | Pony.Cell[][] appendix = new Pony.Cell[top][w];
308 | System.arraycopy(matrix, 0, matrix = new Pony.Cell[h + top][], top, h);
309 | System.arraycopy(appendix, 0, matrix, 0, top);
310 | Pony.Meta[][][] metaappendix = new Pony.Meta[top][w + 1][];
311 | System.arraycopy(metamatrix, 0, metamatrix = new Pony.Meta[h + top][w + 1][], top, h);
312 | System.arraycopy(metaappendix, 0, metamatrix, 0, top);
313 | top = 0;
314 | }
315 | else
316 | top = -top;
317 |
318 | if (bottom > 0)
319 | {
320 | int h = matrix.length, w = matrix[0].length;
321 | Pony.Cell[][] appendix = new Pony.Cell[bottom][w];
322 | System.arraycopy(matrix, 0, matrix = new Pony.Cell[h + bottom][], 0, h);
323 | System.arraycopy(appendix, 0, matrix, h, bottom);
324 | Pony.Meta[][][] metaappendix = new Pony.Meta[bottom][w + 1][];
325 | System.arraycopy(metamatrix, 0, metamatrix = new Pony.Meta[h + bottom][][], 0, h);
326 | System.arraycopy(metaappendix, 0, metamatrix, h, bottom);
327 | bottom = 0;
328 | }
329 | else
330 | bottom = -bottom;
331 |
332 | pony.matrix = matrix;
333 | pony.metamatrix = metamatrix;
334 | return new int[] { left, right, top, bottom };
335 | }
336 |
337 |
338 | /**
339 | * Converts an integer array to a string with only 16-bit charaters
340 | *
341 | * @param ints The int array
342 | * @return The string
343 | */
344 | public static String utf32to16(final int... ints)
345 | {
346 | int len = ints.length;
347 | for (final int i : ints)
348 | if (i > 0xFFFF)
349 | len++;
350 | else if (i > 0x10FFFF)
351 | throw new RuntimeException("Be serious, there is no character above plane 16.");
352 |
353 | final char[] chars = new char[len];
354 | int ptr = 0;
355 |
356 | for (final int i : ints)
357 | if (i <= 0xFFFF)
358 | chars[ptr++] = (char)i;
359 | else
360 | {
361 | /* 10000₁₆ + (H − D800₁₆) ⋅ 400₁₆ + (L − DC00₁₆) */
362 |
363 | int c = i - 0x10000;
364 | int L = (c & 0x3FF) + 0xDC00;
365 | int H = (c >>> 10) + 0xD800;
366 |
367 | chars[ptr++] = (char)H;
368 | chars[ptr++] = (char)L;
369 | }
370 |
371 | return new String(chars);
372 | }
373 |
374 | /**
375 | * Parse double value
376 | *
377 | * @param value String representation
378 | * @return Raw representation, -1 if not a number
379 | */
380 | public static double parseDouble(String value)
381 | {
382 | try
383 | { return Double.parseDouble(value);
384 | }
385 | catch (Throwable err)
386 | { return -1.0;
387 | }
388 | }
389 |
390 | /**
391 | * Parse double value
392 | *
393 | * @param value String representation
394 | * @param defaultValue Default value that will be used if that string starts with a ‘y’ or ‘Y’
395 | * @return Raw representation, -1 if not a number
396 | */
397 | public static double parseDouble(String value, double defaultValue)
398 | {
399 | if (value.startsWith("y") || value.startsWith("Y"))
400 | return defaultValue;
401 | try
402 | { return Double.parseDouble(value);
403 | }
404 | catch (Throwable err)
405 | { return -1.0;
406 | }
407 | }
408 |
409 | /**
410 | * Parse integer value
411 | *
412 | * @param value String representation
413 | * @return Raw representation, -1 if not an integer
414 | */
415 | public static int parseInteger(String value)
416 | {
417 | try
418 | { return Integer.parseInt(value);
419 | }
420 | catch (Throwable err)
421 | { return -1;
422 | }
423 | }
424 |
425 | /**
426 | * Parse integer value
427 | *
428 | * @param value String representation
429 | * @param defaultValue Default value that will be used if that string starts with a ‘y’ or ‘Y’
430 | * @return Raw representation, -1 if not an integer
431 | */
432 | public static int parseInteger(String value, int defaultValue)
433 | {
434 | if (value.startsWith("y") || value.startsWith("Y"))
435 | return defaultValue;
436 | try
437 | { return Integer.parseInt(value);
438 | }
439 | catch (Throwable err)
440 | { return -1;
441 | }
442 | }
443 |
444 | }
445 |
446 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/Cowsay.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.io.*;
22 | import java.util.*;
23 |
24 |
25 | /**
26 | * Cowsay support module
27 | *
28 | * @author Mattias Andrée, m@maandree.se
29 | */
30 | public class Cowsay extends Ponysay
31 | {
32 | /**
33 | * Constructor
34 | *
35 | * @param flags Flags passed to the module
36 | */
37 | public Cowsay(HashMap flags)
38 | {
39 | super(Cowsay.modifyFlags(flags));
40 | this.flags = flags;
41 | }
42 |
43 |
44 |
45 | /**
46 | * Flags passed to the module
47 | */
48 | private HashMap flags;
49 |
50 |
51 |
52 | /**
53 | * Import the pony from file
54 | *
55 | * @return The pony
56 | *
57 | * @throws IOException On I/O error
58 | */
59 | public Pony importCow() throws IOException
60 | {
61 | InputStream in = System.in;
62 | if (this.file != null)
63 | in = new BufferedInputStream(new FileInputStream(this.file));
64 | Scanner sc = new Scanner(in, "UTF-8");
65 |
66 |
67 | StringBuilder cow = new StringBuilder();
68 | StringBuilder data = new StringBuilder();
69 | boolean meta = false;
70 |
71 | cow.append("#!/usr/bin/perl\n");
72 | cow.append("$thoughts = \"\\$\\\\\\$\";\n");
73 | cow.append("$tongue = \"\\$tongue\\$\";\n");
74 | cow.append("$eyes = \"\\$eye\\$eye\";\n");
75 | while (sc.hasNextLine())
76 | {
77 | String line = sc.nextLine();
78 | if (line.replace("\t", "").replace(" ", "").startsWith("#"))
79 | {
80 | if (meta == false)
81 | {
82 | meta = true;
83 | data.append("$$$\n");
84 | }
85 | line = line.substring(line.indexOf("#") + 1);
86 | if (line.equals("$$$"))
87 | line = "$$$(!)";
88 | data.append(line + "\n");
89 | data.append('\n');
90 | }
91 | else
92 | {
93 | cow.append(line.replace("chop($eyes);", "\"\\$eye\\$\";\n$eyes = \"\\$eye\\$\";"));
94 | cow.append('\n');
95 | }
96 | }
97 | if (meta)
98 | data.append("$$$\n");
99 | cow.append("print \"$the_cow\";\n");
100 |
101 |
102 | if (in != System.in)
103 | in.close();
104 |
105 |
106 | String pony = new String(execCow(cow.toString()), "UTF-8");
107 | String line = pony.substring(0, pony.indexOf('\n'));
108 | int pos = line.indexOf("$\\$") + 3;
109 |
110 | if (pos > 3)
111 | data.append("$balloon" + pos + "$");
112 | else
113 | data.append("$balloon$");
114 | data.append(pony);
115 |
116 |
117 | InputStream stdin = System.in;
118 | try
119 | {
120 | final byte[] streamdata = data.toString().getBytes("UTF-8");
121 | System.setIn(new InputStream()
122 | {
123 | int ptr = 0;
124 | @Override
125 | public int read()
126 | {
127 | if (this.ptr == streamdata.length)
128 | return -1;
129 | return streamdata[this.ptr++] & 255;
130 | }
131 | @Override
132 | public int available()
133 | {
134 | return streamdata.length - this.ptr;
135 | }
136 | });
137 | this.flags.put("file", null);
138 | Ponysay ponysay = new Ponysay(this.flags);
139 | if (ponysay.version == this.version)
140 | throw new Error("Default ponysay version should not be the cowsay version");
141 | return ponysay.importPony();
142 | }
143 | finally
144 | {
145 | System.setIn(stdin);
146 | }
147 | }
148 |
149 |
150 | /**
151 | * Executes a perl script
152 | *
153 | * @param cow The cow cowsay→ponysay converting script in perl
154 | * @return The cow in ponysay
155 | *
156 | * @throws IOException On perl executing failure
157 | */
158 | public static byte[] execCow(final String cow) throws IOException
159 | {
160 | Process process = (new ProcessBuilder("perl")).start();
161 | OutputStream cowout = process.getOutputStream();
162 | InputStream stream = process.getInputStream();
163 |
164 | cowout.write(cow.getBytes("UTF-8"));
165 | cowout.flush();
166 | try
167 | {
168 | cowout.close();
169 | }
170 | catch (final Throwable err)
171 | {
172 | //Ignore
173 | }
174 |
175 | byte[] buf = new byte[2048];
176 | int ptr = 0;
177 | for (int d; (d = stream.read()) != -1;)
178 | {
179 | buf[ptr++] = (byte)d;
180 | if (ptr == buf.length)
181 | System.arraycopy(buf, 0, buf = new byte[ptr << 1], 0, ptr);
182 | }
183 | try
184 | {
185 | stream.close();
186 | }
187 | catch (final Throwable err)
188 | {
189 | //Ignore
190 | }
191 | System.arraycopy(buf, 0, buf = new byte[ptr], 0, ptr);
192 | return buf;
193 | }
194 |
195 |
196 | /**
197 | * Modify the flags to fit this module
198 | *
199 | * @param flag The flags
200 | * @return The flags
201 | */
202 | private static HashMap modifyFlags(HashMap flags)
203 | {
204 | flags.put("version", "0.1");
205 | return flags;
206 | }
207 |
208 | }
209 |
210 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/Image.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.io.*;
22 | import java.awt.Color;
23 | import java.awt.image.*;
24 | import java.util.*;
25 | import javax.imageio.*;
26 |
27 |
28 | /**
29 | * Non-terminal image support module
30 | *
31 | * @author Mattias Andrée, m@maandree.se
32 | */
33 | public class Image
34 | {
35 | /**
36 | * Constructor
37 | *
38 | * @param flags Flags passed to the module
39 | */
40 | public Image(HashMap flags)
41 | {
42 | this.file = (flags.containsKey("file") ? (this.file = flags.get("file")).equals("-") : true) ? null : this.file;
43 | this.balloon = this.encoded ? false : ((flags.containsKey("balloon") == false) || flags.get("balloon").toLowerCase().startsWith("y"));
44 | this.left = (flags.containsKey("left") == false) ? 3 : Common.parseInteger(flags.get("left"), 3);
45 | this.right = (flags.containsKey("right") == false) ? 0 : Common.parseInteger(flags.get("right"), 0);
46 | this.top = (flags.containsKey("top") == false) ? (this.balloon ? 3 : 1) : Common.parseInteger(flags.get("top"), this.balloon ? 3 : 1);
47 | this.bottom = (flags.containsKey("bottom") == false) ? 1 : Common.parseInteger(flags.get("bottom"), 1);
48 | this.magnified = (flags.containsKey("magnified") == false) ? 2 : Common.parseInteger(flags.get("magnified"), 2);
49 | this.encoded = flags.containsKey("encoded") && flags.get("encoded").toLowerCase().startsWith("y");
50 | this.format = flags.containsKey("format") ? flags.get("format") : null;
51 | }
52 |
53 |
54 |
55 | /**
56 | * Input/output option: pony file
57 | */
58 | protected String file;
59 |
60 | /**
61 | * Input/output option: left margin, negative for unmodified
62 | */
63 | protected int left;
64 |
65 | /**
66 | * Input/output option: right margin, negative for unmodified
67 | */
68 | protected int right;
69 |
70 | /**
71 | * Output option: top margin, negative for unmodified
72 | * Input option: extra number of lines between the pony and balloon (must not be negative)
73 | */
74 | protected int top;
75 |
76 | /**
77 | * Input/Output option: bottom margin, negative for unmodified
78 | */
79 | protected int bottom;
80 |
81 | /**
82 | * Input/output option: pixel magnification
83 | */
84 | protected int magnified;
85 |
86 | /**
87 | * Input/output option: balloon encoding in the image
88 | */
89 | protected boolean encoded;
90 |
91 | /**
92 | * Input/output option: insert balloon into the image
93 | */
94 | protected boolean balloon;
95 |
96 | /**
97 | * Output option: image file format
98 | */
99 | protected String format;
100 |
101 |
102 |
103 | /**
104 | * Import the pony from file
105 | *
106 | * @return The pony
107 | *
108 | * @throws IOException On I/O error
109 | */
110 | public Pony importPony() throws IOException
111 | {
112 | BufferedImage image = ImageIO.read(new BufferedInputStream(this.file == null ? System.in : new FileInputStream(this.file)));
113 | int width = image.getWidth() / this.magnified;
114 | int height = image.getHeight() / this.magnified;
115 | int div = this.magnified * this.magnified;
116 |
117 | Pony.Cell cell;
118 | Pony pony = new Pony((height >> 1) + (height & 1), width, null, null);
119 | for (int y = 0; y < height; y += 2)
120 | for (int x = 0; x < width; x++)
121 | {
122 | int a = 0, r = 0, g = 0, b = 0;
123 | for (int yy = 0; yy < this.magnified; yy++)
124 | for (int xx = 0; xx < this.magnified; xx++)
125 | { int argb = image.getRGB(x * this.magnified + xx, y * this.magnified + yy);
126 | a += (argb >> 24) & 255;
127 | r += (argb >> 16) & 255;
128 | g += (argb >> 8) & 255;
129 | b += argb & 255;
130 | }
131 | a /= div; r /= div; g /= div; b /= div;
132 | pony.matrix[y >> 1][x] = cell = new Pony.Cell(Pony.Cell.PIXELS, a == 0 ? null : new Color(r, g, b, a), null, null);
133 |
134 | if ((y + 2) * this.magnified <= image.getHeight())
135 | {
136 | a = r = g = b = 0;
137 | for (int yy = 0; yy < this.magnified; yy++)
138 | for (int xx = 0; xx < this.magnified; xx++)
139 | { int argb = image.getRGB(x * this.magnified + xx, (y + 1) * this.magnified + yy);
140 | a += (argb >> 24) & 255;
141 | r += (argb >> 16) & 255;
142 | g += (argb >> 8) & 255;
143 | b += argb & 255;
144 | }
145 | a /= div; r /= div; g /= div; b /= div;
146 | cell.lowerColour = a == 0 ? null : new Color(r, g, b, a);
147 | }
148 |
149 | if (encoded && (cell.upperColour.getAlpha() == cell.lowerColour.getAlpha()))
150 | { r = cell.upperColour.getRed();
151 | g = cell.upperColour.getGreen();
152 | b = cell.upperColour.getBlue();
153 | int r2 = cell.upperColour.getRed();
154 | int g2 = cell.upperColour.getGreen();
155 | int b2 = cell.upperColour.getBlue();
156 | switch (cell.upperColour.getAlpha())
157 | {
158 | case 100:
159 | if ((r == 255) && (g == 0) && (b == 0))
160 | pony.matrix[y][x] = new Pony.Cell(Pony.Cell.NNW_SSE, null, null, null);
161 | else if ((r == 0) && (g == 0) && (b == 255))
162 | pony.matrix[y][x] = new Pony.Cell(Pony.Cell.NNE_SSW, null, null, null);
163 | else if ((r == 255) && (g == 0) && (b == 255))
164 | pony.matrix[y][x] = new Pony.Cell(Pony.Cell.CROSS, null, null, null);
165 | else if ((r == 0) && (g == 255) && (b == 0))
166 | {
167 | int bw = x, _x = x;
168 | for (x++; x < width; x++)
169 | { a = r = g = b = 0;
170 | for (int yy = 0; yy < this.magnified; yy++)
171 | for (int xx = 0; xx < this.magnified; xx++)
172 | { int argb = image.getRGB(x * this.magnified + xx, y * this.magnified + yy);
173 | a += (argb >> 24) & 255;
174 | r += (argb >> 16) & 255;
175 | g += (argb >> 8) & 255;
176 | b += argb & 255;
177 | }
178 | if ((a != 100) || (r != 0) || (g != 255) || (b != 0))
179 | break;
180 | }
181 | bw = x-- - bw;
182 | pony.matrix[y][_x] = null;
183 | pony.metamatrix[y][_x] = new Pony.Meta[] { new Pony.Balloon(
184 | null, null, new Integer(bw), null,
185 | null, null, Pony.Balloon.NONE) };
186 | }
187 | break;
188 |
189 | case 99:
190 | boolean jl = (r & 128) == 128;
191 | boolean jr = (g & 128) == 128;
192 | int left = r & 127;
193 | int minw = g & 127;
194 | int maxw = b;
195 | boolean jt = (r2 & 128) == 128;
196 | boolean jb = (g2 & 128) == 128;
197 | int top = r2 & 127;
198 | int minh = g2 & 127;
199 | int maxh = b2;
200 | int justification = (jl ? Pony.Balloon.LEFT : Pony.Balloon.NONE)
201 | | (jr ? Pony.Balloon.RIGHT : Pony.Balloon.NONE)
202 | | (jt ? Pony.Balloon.TOP : Pony.Balloon.NONE)
203 | | (jb ? Pony.Balloon.BOTTOM : Pony.Balloon.NONE);
204 | pony.matrix[y][x] = null;
205 | pony.metamatrix[y][x] = new Pony.Meta[] { new Pony.Balloon(
206 | left == 0 ? null : new Integer(left), top == 0 ? null : new Integer(top),
207 | minw == 0 ? null : new Integer(minw), minh == 0 ? null : new Integer(minh),
208 | maxw == 0 ? null : new Integer(maxw), maxh == 0 ? null : new Integer(maxh),
209 | justification) };
210 | break;
211 | } }
212 | }
213 |
214 | Common.changeMargins(pony, this.left, this.right, this.balloon ? -1 : this.top, this.bottom);
215 |
216 | if (this.balloon)
217 | Common.insertBalloon(pony, this.top);
218 |
219 | pony.height = pony.matrix.length;
220 | pony.width = pony.height == 0 ? 0 : pony.matrix[0].length;
221 | return pony;
222 | }
223 |
224 |
225 | /**
226 | * Export a pony to the file
227 | *
228 | * @param pony The pony
229 | *
230 | * @throws IOException On image export error
231 | */
232 | public void exportPony(Pony pony) throws IOException
233 | {
234 | Common.changeMargins(pony, this.left, this.right, this.top, this.bottom);
235 | int h = Math.max(1, pony.matrix.length);
236 | int w = h == 0 ? 1 : Math.max(1, pony.matrix[0].length);
237 |
238 | BufferedImage img = new BufferedImage(w * this.magnified, (h << 1) * this.magnified, BufferedImage.TYPE_INT_ARGB);
239 | Color TRANSPARENT = new Color(0, 0, 0, 0);
240 |
241 | for (int y = 0; y < h; y++)
242 | { Pony.Cell[] row = pony.matrix[y];
243 | Pony.Meta[][] metarow = pony.metamatrix[y];
244 | x_loop: for (int x = 0; x <= w; x++)
245 | { Pony.Meta[] metacell = metarow[x];
246 | if (metacell != null)
247 | for (Pony.Meta meta : metacell)
248 | if (meta.getClass() == Pony.Recall.class)
249 | System.err.println("\033[01;31mutil-say: warning: ignoring recall in image, no way to parse in an image module\033[00m");
250 | else if (meta.getClass() == Pony.Combining.class)
251 | System.err.println("\033[01;31mutil-say: warning: cannot include text in images\033[00m");
252 | else if (this.encoded && (meta.getClass() == Pony.Balloon.class))
253 | {
254 | Pony.Balloon balloon = (Pony.Balloon)meta;
255 | int r = 0, g = 0, b = 0, r2 = 0, g2 = 0, b2 = 0, j = balloon.justification;
256 | if ((j & Pony.Balloon.LEFT) != 0) r |= 128;
257 | if ((j & Pony.Balloon.RIGHT) != 0) g |= 128;
258 | if ((j & Pony.Balloon.TOP) != 0) r2 |= 128;
259 | if ((j & Pony.Balloon.BOTTOM) != 0) g2 |= 128;
260 | r |= balloon.left == null ? 0 : (balloon.left.intValue() & 127);
261 | g |= balloon.minWidth == null ? 0 : (balloon.minWidth.intValue() & 127);
262 | b |= balloon.maxWidth == null ? 0 : (balloon.maxWidth.intValue() & 255);
263 | r2 |= balloon.top == null ? 0 : (balloon.top.intValue() & 127);
264 | g2 |= balloon.minHeight == null ? 0 : (balloon.minHeight.intValue() & 127);
265 | b2 |= balloon.maxHeight == null ? 0 : (balloon.maxHeight.intValue() & 255);
266 | Color upper = new Color(r, g, b, 99);
267 | Color lower = new Color(r2, g2, b2, 99);
268 | int _x = x * this.magnified;
269 | int uy = (y << 1) * this.magnified;
270 | int ly = ((y << 1) | 1) * this.magnified;
271 | int u = upper.getRGB(), l = lower.getRGB();
272 | for (int my = 0; my < this.magnified; my++)
273 | for (int mx = 0; mx < this.magnified; mx++)
274 | { img.setRGB(_x + mx, uy + my, u);
275 | img.setRGB(_x + mx, ly + my, l);
276 | }
277 | // TODO add warning for if cells should override this
278 | continue x_loop;
279 | }
280 | /*else if (meta.getClass() == Pony.Store.class)
281 | ; // Do nothing*/
282 |
283 | if (x != w)
284 | {
285 | Pony.Cell cell = row[x];
286 | Color upper, lower;
287 | if (cell == null)
288 | upper = lower = TRANSPARENT;
289 | else
290 | { boolean whitespace = (cell.character == ' ') || (cell.character == ' ');
291 | upper = whitespace ? cell.lowerColour : cell.upperColour;
292 | lower = cell.lowerColour;
293 | whitespace |= cell.character == Pony.Cell.PIXELS;
294 | if (cell.character == Pony.Cell.NNW_SSE)
295 | upper = lower = this.encoded ? new Color(255, 0, 0, 100) : TRANSPARENT;
296 | else if (cell.character == Pony.Cell.NNE_SSW)
297 | upper = lower = this.encoded ? new Color(0, 0, 255, 100) : TRANSPARENT;
298 | else if (cell.character == Pony.Cell.CROSS)
299 | upper = lower = this.encoded ? new Color(255, 0, 255, 100) : TRANSPARENT;
300 | else
301 | { if (!whitespace)
302 | System.err.println("\033[01;31mutil-say: warning: cannot include text in images\033[00m");
303 | if ((upper == null) || !whitespace) upper = TRANSPARENT;
304 | if ((lower == null) || !whitespace) lower = TRANSPARENT;
305 | } }
306 | int _x = x * this.magnified;
307 | int uy = (y << 1) * this.magnified;
308 | int ly = ((y << 1) | 1) * this.magnified;
309 | int u = upper.getRGB(), l = lower.getRGB();
310 | for (int my = 0; my < this.magnified; my++)
311 | for (int mx = 0; mx < this.magnified; mx++)
312 | { img.setRGB(_x + mx, uy + my, u);
313 | img.setRGB(_x + mx, ly + my, l);
314 | }
315 | } } }
316 |
317 | if ((pony.comment != null) && (pony.comment.length() != 0))
318 | System.err.println("\033[01;31mutil-say: warning: not capable of exporting metadata to images\033[00m");
319 | else if ((pony.tags != null) && (pony.tags.length != 0))
320 | System.err.println("\033[01;31mutil-say: warning: not capable of exporting metadata to images\033[00m");
321 |
322 | String fmt = this.format;
323 | if (fmt == null)
324 | if (this.file == null)
325 | fmt = "png";
326 | else
327 | { fmt = this.file.contains("/") ? this.file.substring(this.file.lastIndexOf("/") + 1) : this.file;
328 | fmt = this.file.contains(".") ? this.file.substring(this.file.lastIndexOf(".") + 1) : "png";
329 | }
330 | ImageIO.write(img, fmt, new BufferedOutputStream(this.file == null ? System.out : new FileOutputStream(this.file)));
331 | }
332 |
333 | }
334 |
335 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/Pony.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.awt.Color;
22 |
23 |
24 | /**
25 | * I'm a pony!
26 | *
27 | * @author Mattias Andrée, m@maandree.se
28 | */
29 | public class Pony
30 | {
31 | /**
32 | * Constructor
33 | *
34 | * @param heigth The height of the pony, in lines (paired pixels)
35 | * @param width The width of the pony, in columns (pixels)
36 | * @param comment Metadata comment on pony, may be {@code null}
37 | * @param tags Metadata tags, one {key, value} format, may be {@code null}
38 | */
39 | public Pony(int height, int width, String comment, String[][] tags)
40 | {
41 | this.height = height;
42 | this.width = width;
43 | this.comment = comment;
44 | this.tags = tags;
45 |
46 | this.matrix = new Pony.Cell[height][width];
47 | this.metamatrix = new Pony.Meta[height][width + 1][];
48 | }
49 |
50 |
51 |
52 | /**
53 | * The height of the pony, in lines (paired pixels)
54 | */
55 | public int height;
56 |
57 | /**
58 | * The width of the pony, in columns (pixels)
59 | */
60 | public int width;
61 |
62 | /**
63 | * Metadata comment on pony, may be {@code null}
64 | */
65 | public String comment;
66 |
67 | /**
68 | * Metadata tags, one {key, value} format, may be {@code null}
69 | */
70 | public String[][] tags;
71 |
72 | /**
73 | * The cells in the pony
74 | */
75 | public Pony.Cell[][] matrix;
76 |
77 | /**
78 | * The metacells in the pony
79 | */
80 | public Pony.Meta[][][] metamatrix;
81 |
82 |
83 |
84 | /**
85 | * {@inheritDoc}
86 | */
87 | @Override
88 | public Pony clone()
89 | {
90 | String[][] _tags = this.tags == null ? null : new String[this.tags.length][2];
91 | if (this.tags != null)
92 | for (int i = 0, n = this.tags.length; i < n; i ++)
93 | { _tags[i][0] = this.tags[i][0];
94 | _tags[i][1] = this.tags[i][1];
95 | }
96 | Pony rc = new Pony(this.height, this.width, this.comment, _tags);
97 | for (int y = 0; y < this.height; y++)
98 | {
99 | Cell[] trow = this.matrix[y];
100 | Cell[] rrow = rc.matrix[y];
101 | Meta[][] tmetarow = this.metamatrix[y];
102 | Meta[][] rmetarow = rc.metamatrix[y];
103 | for (int x = 0; x <= this.width; x++)
104 | { if (x != this.width)
105 | rrow[x] = trow[x] == null ? null : trow[x].clone();
106 | if (tmetarow[x] != null)
107 | { Meta[] tmetacell = tmetarow[x];
108 | Meta[] rmetacell = rmetarow[x] = new Meta[tmetacell.length];
109 | for (int z = 0, m = tmetacell.length; z < m; z++)
110 | rmetacell[z] = tmetacell[z] == null ? null : tmetacell[z].clone();
111 | } }
112 | }
113 | return rc;
114 | }
115 |
116 |
117 |
118 | /**
119 | * A charcter cell in the pony
120 | */
121 | public static class Cell
122 | {
123 | /**
124 | * Pixel pair
125 | */
126 | public static final int PIXELS = -1;
127 |
128 | /**
129 | * NNE–SSW link
130 | */
131 | public static final int NNE_SSW = -2;
132 |
133 | /**
134 | * NNW–SSE link
135 | */
136 | public static final int NNW_SSE = -3;
137 |
138 | /**
139 | * Cross link
140 | */
141 | public static final int CROSS = -4;
142 |
143 |
144 |
145 | /**
146 | * Constructor
147 | *
148 | * @param character The character duo in UTF-32, if negative it will have a special meaning, for example pixels or boolean link
149 | * @param upperColour The colour to apply to the upper pixed if a pixel, foreground colour if character, otherwise ignored, {@code null} is preferable for fully transparent
150 | * @param lowerColour The colour to apply to the lower pixed if a pixel, background colour if character, otherwise ignored, {@code null} is preferable for fully transparent
151 | * @param format Formatting to apply, nine booleans
152 | */
153 | public Cell(int character, Color upperColour, Color lowerColour, boolean[] format)
154 | {
155 | this.character = character;
156 | this.upperColour = upperColour;
157 | this.lowerColour = lowerColour;
158 | if (format == null)
159 | this.format = new boolean[9];
160 | else
161 | System.arraycopy(format, 0, this.format = new boolean[9], 0, 9);
162 | if ((character == PIXELS) || (character == ' ') || (character == ' '))
163 | this.format[0] = false;
164 | }
165 |
166 |
167 |
168 | /**
169 | * The character in UTF-32, if negative it will have a special meaning, for example pixels or boolean link
170 | */
171 | public int character;
172 |
173 | /**
174 | * The colour to apply to the upper pixed if a pixel, foreground colour if character, otherwise ignored, {@code null} is preferable for fully transparent
175 | */
176 | public Color upperColour;
177 |
178 | /**
179 | * The colour to apply to the lower pixed if a pixel, background colour if character, otherwise ignored, {@code null} is preferable for fully transparent
180 | */
181 | public Color lowerColour;
182 |
183 | /**
184 | * Formatting to apply, nine booleans
185 | */
186 | public boolean[] format;
187 |
188 |
189 |
190 | /**
191 | * {@inheritDoc}
192 | */
193 | @Override
194 | public Cell clone()
195 | {
196 | boolean[] _format = this.format == null ? null : new boolean[this.format.length];
197 | if (this.format != null)
198 | System.arraycopy(this.format, 0, _format, 0, this.format.length);
199 | return new Cell(this.character, this.upperColour, this.lowerColour, _format);
200 | }
201 |
202 | }
203 |
204 |
205 |
206 | /**
207 | * Weird stuff going on before a cell
208 | */
209 | public interface Meta
210 | {
211 | // Marker interface with clone support
212 |
213 | /**
214 | * {@inheritDoc}
215 | */
216 | public Meta clone();
217 | }
218 |
219 |
220 |
221 | /**
222 | * Combining character
223 | */
224 | public static class Combining implements Meta
225 | {
226 | /**
227 | * Constructor
228 | *
229 | * @param character The character in UTF-32
230 | * @param foregroundColour Foreground colour to apply to the character
231 | * @param backgroundColour Background colour to apply to the character
232 | * @param format Formatting to apply, nine booleans
233 | */
234 | public Combining(int character, Color foregroundColour, Color backgroundColour, boolean[] format)
235 | {
236 | this.character = character;
237 | this.foregroundColour = foregroundColour;
238 | this.backgroundColour = backgroundColour;
239 | if (format == null)
240 | this.format = new boolean[9];
241 | else
242 | System.arraycopy(format, 0, this.format = new boolean[9], 0, 9);
243 | }
244 |
245 |
246 |
247 | /**
248 | * The character in UTF-32
249 | */
250 | public int character;
251 |
252 | /**
253 | * Foreground colour to apply to the character
254 | */
255 | public Color foregroundColour;
256 |
257 | /**
258 | * Background colour to apply to the character
259 | */
260 | public Color backgroundColour;
261 |
262 | /**
263 | * Formatting to apply, nine booleans
264 | */
265 | public boolean[] format;
266 |
267 |
268 |
269 | /**
270 | * {@inheritDoc}
271 | */
272 | @Override
273 | public Combining clone()
274 | {
275 | boolean[] _format = this.format == null ? null : new boolean[this.format.length];
276 | if (this.format != null)
277 | System.arraycopy(this.format, 0, _format, 0, this.format.length);
278 | return new Combining(this.character, this.foregroundColour, this.backgroundColour, _format);
279 | }
280 |
281 | }
282 |
283 |
284 | /**
285 | * Variable usage
286 | */
287 | public static class Recall implements Meta
288 | {
289 | /**
290 | * Constructor
291 | *
292 | * @param name The name of the variable
293 | * @param foregroundColour Foreground colour to apply to the region
294 | * @param backgroundColour Background colour to apply to the region
295 | * @param format Formatting to apply, nine booleans
296 | */
297 | public Recall(String name, Color foregroundColour, Color backgroundColour, boolean[] format)
298 | {
299 | this.name = name;
300 | this.foregroundColour = foregroundColour;
301 | this.backgroundColour = backgroundColour;
302 | if (format == null)
303 | this.format = new boolean[9];
304 | else
305 | System.arraycopy(format, 0, this.format = new boolean[9], 0, 9);
306 | }
307 |
308 |
309 |
310 | /**
311 | * The name of the variable
312 | */
313 | public String name;
314 |
315 | /**
316 | * Foreground colour to apply to the region
317 | */
318 | public Color foregroundColour;
319 |
320 | /**
321 | * Background colour to apply to the region
322 | */
323 | public Color backgroundColour;
324 |
325 | /**
326 | * Formatting to apply, nine booleans
327 | */
328 | public boolean[] format;
329 |
330 |
331 |
332 | /**
333 | * {@inheritDoc}
334 | */
335 | @Override
336 | public Recall clone()
337 | {
338 | boolean[] _format = this.format == null ? null : new boolean[this.format.length];
339 | if (this.format != null)
340 | System.arraycopy(this.format, 0, _format, 0, this.format.length);
341 | return new Recall(this.name, this.foregroundColour, this.backgroundColour, _format);
342 | }
343 |
344 | }
345 |
346 |
347 | /**
348 | * Variable storing
349 | */
350 | public static class Store implements Meta
351 | {
352 | /**
353 | * Constructor
354 | *
355 | * @param name The name of the variable
356 | * @parma value The value of the variable
357 | */
358 | public Store(String name, String value)
359 | {
360 | this.name = name;
361 | this.value = value;
362 | }
363 |
364 |
365 |
366 | /**
367 | * The name of the variable
368 | */
369 | public String name;
370 |
371 | /**
372 | * The value of the variable
373 | */
374 | public String value;
375 |
376 |
377 |
378 | /**
379 | * {@inheritDoc}
380 | */
381 | @Override
382 | public Store clone()
383 | {
384 | return new Store(this.name, this.value);
385 | }
386 |
387 | }
388 |
389 |
390 | /**
391 | * Balloon
392 | */
393 | public static class Balloon implements Meta
394 | {
395 | /**
396 | * No justification applied
397 | */
398 | public static final int NONE = 0;
399 |
400 | /**
401 | * Left justification, fill to right
402 | */
403 | public static final int LEFT = 1;
404 |
405 | /**
406 | * Right justification, fill to left
407 | */
408 | public static final int RIGHT = 2;
409 |
410 | /**
411 | * Centre justification, center the balloon
412 | */
413 | public static final int CENTRE = 3;
414 |
415 | /**
416 | * Top vertical justification, fill down
417 | */
418 | public static final int TOP = 4;
419 |
420 | /**
421 | * Bottom vertical justification, fill up
422 | */
423 | public static final int BOTTOM = 8;
424 |
425 | /**
426 | * Middle vertical justification, center vertically
427 | */
428 | public static final int MIDDLE = 12;
429 |
430 |
431 |
432 | /**
433 | * Constructor
434 | *
435 | * @param left Extra left offset
436 | * @param top Extra top offset
437 | * @param minWidth The minimum width of the balloon
438 | * @param minHeight The minimum height of the balloon
439 | * @param maxWidth The minimum width of the balloon
440 | * @param maxHeight The maximum height of the balloon
441 | * @param justification Balloon placement justification
442 | */
443 | public Balloon(Integer left, Integer top, Integer minWidth, Integer minHeight, Integer maxWidth, Integer maxHeigth, int justification)
444 | {
445 | this.left = left;
446 | this.top = top;
447 | this.minWidth = minWidth;
448 | this.minHeight = minHeight;
449 | this.maxWidth = maxWidth;
450 | this.maxHeight = maxHeight;
451 | this.justification = justification;
452 | }
453 |
454 |
455 |
456 | /**
457 | * Extra left offset
458 | */
459 | public Integer left;
460 |
461 | /**
462 | * Extra top offset
463 | */
464 | public Integer top;
465 |
466 | /**
467 | * The minimum width of the balloon
468 | */
469 | public Integer minWidth;
470 |
471 | /**
472 | * The minimum height of the balloon
473 | */
474 | public Integer minHeight;
475 |
476 | /**
477 | * The maximum width of the balloon
478 | */
479 | public Integer maxWidth;
480 |
481 | /**
482 | * The maximum height of the balloon
483 | */
484 | public Integer maxHeight;
485 |
486 | /**
487 | * Balloon placement justification
488 | */
489 | public int justification;
490 |
491 |
492 |
493 | /**
494 | * {@inheritDoc}
495 | */
496 | @Override
497 | public Balloon clone()
498 | {
499 | return new Balloon(this.left, this.top, this.minWidth, this.minHeight, this.maxWidth, this.maxHeight, this.justification);
500 | }
501 |
502 | }
503 |
504 | }
505 |
506 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/PonysayHaiku.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.awt.*;
22 | import java.util.*;
23 |
24 |
25 | /**
26 | * Haiku xterm submodule for {@link Ponysay}
27 | *
28 | * @author Mattias Andrée, m@maandree.se
29 | */
30 | public class PonysayHaiku extends PonysaySubmodule
31 | {
32 | /**
33 | * Constructor
34 | *
35 | * @param flags Flags passed to the module
36 | */
37 | public PonysayHaiku(HashMap flags)
38 | {
39 | this.chroma = (flags.containsKey("chroma") == false) ? 1 : Common.parseDouble(flags.get("chroma"));
40 | this.colourful = (flags.containsKey("colourful") == false) || flags.get("colourful").toLowerCase().startsWith("y");
41 | this.fullcolour = flags.containsKey("fullcolour") && flags.get("fullcolour").toLowerCase().startsWith("y");
42 | this.palette = (flags.containsKey("palette") == false) ? null : PonysayXterm.parsePalette(flags.get("palette"));
43 | }
44 |
45 |
46 |
47 | /**
48 | * Output option: chroma weight, negative for sRGB distance
49 | */
50 | protected double chroma;
51 |
52 | /**
53 | * Output option: colourful TTY
54 | */
55 | protected boolean colourful;
56 |
57 | /**
58 | * Output option: do not limit to xterm 256 standard colours
59 | */
60 | protected boolean fullcolour;
61 |
62 | /**
63 | * Input/output option: colour palette
64 | */
65 | protected Color[] palette;
66 |
67 | /**
68 | * Auxiliary: whether the parsing is currectly in a CSI sequence
69 | */
70 | private boolean csi = false;
71 |
72 | /**
73 | * Auxiliary: whether the parsing is currectly in a OSI sequence
74 | */
75 | private boolean osi = false;
76 |
77 | /**
78 | * Auxiliary: parsing buffer
79 | */
80 | private int[] buf = new int[256];
81 |
82 | /**
83 | * Auxiliary: parsing buffer pointer
84 | */
85 | private int ptr = 0;
86 |
87 | /**
88 | * Auxiliary: parsing return array
89 | */
90 | private Object[] rcbuf = new Object[3];
91 |
92 |
93 |
94 | /**
95 | * {@inheritDoc}
96 | */
97 | public boolean[][] getPlains()
98 | {
99 | boolean bold = this.fullcolour;
100 | return new boolean[][] {
101 | {false, false, false, false, false, false, false, false, false},
102 | {bold, false, false, false, false, false, false, false, false, false},
103 | {bold, false, false, false, false, false, false, false, false}};
104 | }
105 |
106 |
107 | /**
108 | * {@inheritDoc}
109 | */
110 | public void initImport(Color[] colours)
111 | {
112 | if (this.palette != null)
113 | System.arraycopy(this.palette, 0, colours, 0, 16);
114 | else
115 | this.palette = parsePalette("");
116 | }
117 |
118 |
119 | /**
120 | * {@inheritDoc}
121 | */
122 | public String initExport(Color[] colours)
123 | {
124 | if (this.palette != null)
125 | System.arraycopy(this.palette, 0, colours, 0, 16);
126 | else
127 | this.palette = parsePalette("");
128 |
129 | StringBuilder resetPalette = null;
130 | if (this.fullcolour)
131 | { resetPalette = new StringBuilder();
132 | if (this.colourful)
133 | for (int i = 0; i < 16; i++)
134 | { Colour colour = new Colour(i);
135 | resetPalette.append("\033]4;");
136 | resetPalette.append(i);
137 | resetPalette.append(";rgb:");
138 | resetPalette.append("0123456789ABCDEF".charAt(colour.red >>> 4));
139 | resetPalette.append("0123456789ABCDEF".charAt(colour.red & 15));
140 | resetPalette.append('/');
141 | resetPalette.append("0123456789ABCDEF".charAt(colour.green >>> 4));
142 | resetPalette.append("0123456789ABCDEF".charAt(colour.green & 15));
143 | resetPalette.append('/');
144 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue >>> 4));
145 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue & 15));
146 | resetPalette.append("\033\\");
147 | }
148 | else
149 | for (int i : new int[] { 7, 15 })
150 | { Colour colour = new Colour(i);
151 | resetPalette.append("\033]4;");
152 | resetPalette.append(i);
153 | resetPalette.append(";rgb:");
154 | resetPalette.append("0123456789ABCDEF".charAt(colour.red >>> 4));
155 | resetPalette.append("0123456789ABCDEF".charAt(colour.red & 15));
156 | resetPalette.append('/');
157 | resetPalette.append("0123456789ABCDEF".charAt(colour.green >>> 4));
158 | resetPalette.append("0123456789ABCDEF".charAt(colour.green & 15));
159 | resetPalette.append('/');
160 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue >>> 4));
161 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue & 15));
162 | resetPalette.append("\033\\");
163 | } }
164 |
165 | return resetPalette == null ? null : resetPalette.toString();
166 | }
167 |
168 |
169 | /**
170 | * {@inheritDoc}
171 | */ // TODO cache colour matching
172 | public String applyColour(Color[] palette, Color oldBackground, Color oldForeground, boolean[] oldFormat, Color newBackground, Color newForeground, boolean[] newFormat)
173 | {
174 | StringBuilder rc = new StringBuilder();
175 |
176 | int colourindex1back = -1, colourindex2back = -1;
177 | int colourindex1fore = -1, colourindex2fore = -1;
178 |
179 | if ((oldBackground != null) && (newBackground == null))
180 | rc.append(";40");
181 | else if ((oldBackground == null) || (oldBackground.equals(newBackground) == false))
182 | if (newBackground != null)
183 | {
184 | colourindex1back = matchColour(newBackground, palette, 16, 256, this.chroma);
185 | if (this.fullcolour)
186 | colourindex2back = this.colourful ? matchColour(this.fullcolour ? newBackground : palette[colourindex1back], this.palette, 1, 6, this.chroma) : 7;
187 | else
188 | colourindex2back = colourindex1back;
189 | }
190 |
191 | if ((oldForeground != null) && (newForeground == null))
192 | rc.append(";37");
193 | else if ((oldForeground == null) || (oldForeground.equals(newForeground) == false))
194 | if (newForeground != null)
195 | {
196 | colourindex1fore = matchColour(newForeground, palette, 16, 256, this.chroma);
197 | if (this.fullcolour)
198 | { int s = ((newFormat.length > 9) && newFormat[9]) ? 0 : (newFormat[0] ? 9 : 1);
199 | int e = ((newFormat.length > 9) && newFormat[9]) ? 16 : (s + 5);
200 | colourindex2fore = this.colourful ? matchColour(this.fullcolour ? newForeground : palette[colourindex1fore], this.palette, s, e, this.chroma) : 15;
201 | if (((colourindex2fore == 0) && (newBackground == null)) || (colourindex2fore == colourindex2back))
202 | colourindex2fore ^= 8;
203 | }
204 | else
205 | colourindex2fore = colourindex1fore;
206 | }
207 |
208 | if (colourindex2back != -1)
209 | if (this.fullcolour)
210 | { Color colour = newBackground;
211 | rc.append("m\033]4;");
212 | rc.append(colourindex2back);
213 | rc.append(";rgb:");
214 | rc.append("0123456789ABCDEF".charAt(colour.getRed() >>> 4));
215 | rc.append("0123456789ABCDEF".charAt(colour.getRed() & 15));
216 | rc.append('/');
217 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() >>> 4));
218 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() & 15));
219 | rc.append('/');
220 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() >>> 4));
221 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() & 15));
222 | rc.append("\033\\\033[4");
223 | rc.append(colourindex2back);
224 | palette[colourindex2back] = colour;
225 | }
226 | else if (colourindex2back < 16)
227 | { rc.append(";4");
228 | rc.append(colourindex2back);
229 | }
230 | else
231 | { rc.append(";48;5;");
232 | rc.append(colourindex2back);
233 | }
234 |
235 | if (colourindex2fore != -1)
236 | if (this.fullcolour)
237 | { Color colour = newForeground;
238 | rc.append("m\033]4;");
239 | rc.append(colourindex2fore);
240 | rc.append(";rgb:");
241 | rc.append("0123456789ABCDEF".charAt(colour.getRed() >>> 4));
242 | rc.append("0123456789ABCDEF".charAt(colour.getRed() & 15));
243 | rc.append('/');
244 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() >>> 4));
245 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() & 15));
246 | rc.append('/');
247 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() >>> 4));
248 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() & 15));
249 | rc.append("\033\\\033[3");
250 | rc.append(colourindex2fore & 7);
251 | palette[colourindex2fore] = colour;
252 | }
253 | else if (colourindex2fore < 16)
254 | { rc.append(";3");
255 | rc.append(colourindex2fore & 7);
256 | }
257 | else
258 | { rc.append(";38;5;");
259 | rc.append(colourindex2fore);
260 | }
261 |
262 | boolean temp = newFormat[0];
263 | newFormat[0] = (colourindex2fore == -1) ? oldFormat[0] : ((8 <= colourindex2fore) && (colourindex2fore < 16));
264 | for (int i = 0; i < 9; i++)
265 | if (newFormat[i] ^ oldFormat[i])
266 | if ((oldFormat[i] = newFormat[i]))
267 | { rc.append(";0");
268 | rc.append(i + 1);
269 | }
270 | else
271 | { rc.append(";2");
272 | rc.append(i + 1);
273 | }
274 | newFormat[0] = temp;
275 |
276 | String _rc = rc.toString();
277 | if (_rc.isEmpty())
278 | return "";
279 | return ("\033[" + _rc.substring(1)).replace("\033[\033]", "\033]") + "m";
280 | }
281 |
282 |
283 | /**
284 | * {@inheritDoc}
285 | */
286 | public Object[] parseEscape(int c, Color background, Color foreground, boolean[] format, Color[] colours)
287 | {
288 | boolean escape = true;
289 | if (osi)
290 | if (this.ptr > 0)
291 | { this.buf[this.ptr++ - 1] = c;
292 | if (this.ptr == 8)
293 | { this.ptr = 0;
294 | osi = escape = false;
295 | int index = (this.buf[0] <= '9') ? (this.buf[0] & 15) : ((this.buf[0] & 15) + 9);
296 | int red = (this.buf[1] <= '9') ? (this.buf[1] & 15) : ((this.buf[1] & 15) + 9);
297 | red = (red << 4) | ((this.buf[2] <= '9') ? (this.buf[2] & 15) : ((this.buf[2] & 15) + 9));
298 | int green = (this.buf[3] <= '9') ? (this.buf[3] & 15) : ((this.buf[3] & 15) + 9);
299 | green = (green << 4) | ((this.buf[4] <= '9') ? (this.buf[4] & 15) : ((this.buf[4] & 15) + 9));
300 | int blue = (this.buf[5] <= '9') ? (this.buf[5] & 15) : ((this.buf[5] & 15) + 9);
301 | blue = (blue << 4) | ((this.buf[6] <= '9') ? (this.buf[6] & 15) : ((this.buf[6] & 15) + 9));
302 | colours[index] = new Color(red, green, blue);
303 | }
304 | }
305 | else if (this.ptr < 0)
306 | { if (~this.ptr == this.buf.length)
307 | System.arraycopy(this.buf, 0, this.buf = new int[~this.ptr << 1], 0, ~this.ptr);
308 | if (c == '\\')
309 | { this.ptr = ~this.ptr;
310 | this.ptr--;
311 | if ((this.ptr > 8) && (this.buf[this.ptr] == '\033') && (this.buf[0] == ';'))
312 | { int[] _code = new int[this.ptr - 1];
313 | System.arraycopy(this.buf, 1, _code, 0, this.ptr - 1);
314 | String[] code = Common.utf32to16(_code).split(";");
315 | if (code.length == 2)
316 | { int index = Integer.parseInt(code[0]);
317 | code = code[1].split("/");
318 | if ((code.length == 3) && (code[0].startsWith("rgb:")))
319 | { code[0] = code[0].substring(4);
320 | int red = Integer.parseInt(code[0], 16);
321 | int green = Integer.parseInt(code[1], 16);
322 | int blue = Integer.parseInt(code[2], 16);
323 | colours[index] = new Color(red, green, blue);
324 | } } }
325 | this.ptr = 0;
326 | osi = escape = false;
327 | }
328 | else
329 | { this.buf[~this.ptr] = c;
330 | this.ptr--;
331 | }
332 | }
333 | else if (c == 'P') this.ptr = 1;
334 | else if (c == '4') this.ptr = ~0;
335 | else
336 | { osi = escape = false;
337 | /*items.add(new Pony.Cell('\033', foreground, background, format));
338 | items.add(new Pony.Cell(']', foreground, background, format));
339 | items.add(new Pony.Cell(c, foreground, background, format));*/
340 | System.err.println("\033[01;31mutil-say: warning: bad escape sequence: OSI 0x" + Integer.toString(c) + "\033[00m");
341 | }
342 | else if (csi)
343 | { if (this.ptr == this.buf.length)
344 | System.arraycopy(this.buf, 0, this.buf = new int[this.ptr << 1], 0, this.ptr);
345 | this.buf[this.ptr++] = c;
346 | if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) || (c == '~'))
347 | { csi = escape = false;
348 | this.ptr--;
349 | if (c == 'm')
350 | { int[] _code = new int[this.ptr];
351 | System.arraycopy(this.buf, 0, _code, 0, this.ptr);
352 | String[] code = Common.utf32to16(_code).split(";");
353 | int xterm256 = 0;
354 | boolean back = false;
355 | int forei = -2;
356 | for (String seg : code)
357 | { int value = Integer.parseInt(seg);
358 | if (xterm256 == 2)
359 | { xterm256 = 0;
360 | if (back) background = colours[value];
361 | else forei = value;
362 | }
363 | else if (value == 0)
364 | { for (int i = 0; i < 9; i++)
365 | format[i] = false;
366 | background = null;
367 | forei = -1;
368 | }
369 | else if (xterm256 == 1)
370 | xterm256 = value == 5 ? 2 : 0;
371 | else if (value < 10)
372 | format[value - 1] = true;
373 | else if ((20 < value) && (value < 30))
374 | format[value - 21] = false;
375 | else if (value == 37) forei = -1; /* Haiku uses 37 instead instead of 39 */
376 | else if (value == 40) background = null; /* Haiku uses 40 instead instead of 49 */
377 | else if (value == 38) xterm256 = 1;
378 | else if (value == 48) xterm256 = 1;
379 | else if (value < 38) forei = value - 30;
380 | else if (value < 48) background = colours[value - 40];
381 | else if ((90 <= value) && (value < 98))
382 | background = colours[value - 90 + 8];
383 | else if ((100 <= value) && (value < 108))
384 | forei = value - 100 + 8;
385 | if (xterm256 == 1)
386 | back = value == 48;
387 | }
388 | if (forei == -1)
389 | foreground = null;
390 | else if (forei >= 0)
391 | if ((forei < 8) && format[0])
392 | foreground = colours[forei | 8];
393 | else
394 | foreground = colours[forei];
395 | }
396 | this.ptr = 0;
397 | }
398 | }
399 | else if (c == '[')
400 | { csi = true;
401 | this.ptr = 0;
402 | }
403 | else if (c == ']')
404 | osi = true;
405 | else
406 | { escape = false;
407 | /*items.add(new Pony.Cell('\033', foreground, background, format));
408 | items.add(new Pony.Cell(c, foreground, background, format));*/
409 | System.err.println("\033[01;31mutil-say: warning: bad escape sequence: ESC 0x" + Integer.toString(c, 16) + "\033[00m");
410 | }
411 |
412 | this.rcbuf[0] = background;
413 | this.rcbuf[1] = foreground;
414 | this.rcbuf[2] = escape ? Boolean.TRUE : Boolean.FALSE;
415 | return this.rcbuf;
416 | }
417 |
418 |
419 |
420 | /**
421 | * Parse palette
422 | *
423 | * @param value String representation, without ESC, ] or P
424 | * @return Raw representation
425 | */
426 | public static Color[] parsePalette(String value)
427 | {
428 | String val = null;
429 | { int ptr = 0;
430 | char[] buf = new char[value.length()];
431 | for (int i = 0, n = buf.length; i < n; i++)
432 | { char c = value.charAt(i);
433 | if ((c != '\033') && (c != ']'))
434 | if (c == ';')
435 | if ((i > 0) && (buf[ptr - 1] == '4'))
436 | buf[ptr - 1] = '/';
437 | else
438 | buf[ptr++] = '/';
439 | else if (c == ':')
440 | ptr -= 3;
441 | else
442 | buf[ptr++] = c;
443 | }
444 | val = (new String(buf, 0, ptr)).toUpperCase();
445 | }
446 | String defvalue = "00000001CD0000200CD003CDCD0041E90FF5CD00CD600CDCD7E5E5E5"
447 | + "84C4C4C9FF0000A00FF00BFFFF00C4682B4DFF00FFE00FFFFFFFFFFF";
448 | Color[] palette = new Color[16];
449 | for (int ptr = 0, n = defvalue.length(); ptr < n; ptr += 7)
450 | {
451 | int index = Integer.parseInt(defvalue.substring(ptr + 0, ptr + 1), 16);
452 | int red = Integer.parseInt(defvalue.substring(ptr + 1, ptr + 3), 16);
453 | int green = Integer.parseInt(defvalue.substring(ptr + 3, ptr + 5), 16);
454 | int blue = Integer.parseInt(defvalue.substring(ptr + 5, ptr + 7), 16);
455 | palette[index] = new Color(red, green, blue);
456 | }
457 | for (int ptr = 0, n = val.length(); ptr < n;)
458 | { String v = val.substring(ptr + 1, val.indexOf('\\', ptr));
459 | ptr = v.length() + 2;
460 | String[] vs = v.split("/");
461 | int index = Integer.parseInt(vs[0], 10);
462 | int red = Integer.parseInt(vs[1], 16);
463 | int green = Integer.parseInt(vs[2], 16);
464 | int blue = Integer.parseInt(vs[3], 16);
465 | palette[index] = new Color(red, green, blue);
466 | }
467 | return palette;
468 | }
469 |
470 | }
471 |
472 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/PonysayLinux.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.awt.*;
22 | import java.util.*;
23 |
24 |
25 | /**
26 | * linux (Linux VT) submodule for {@link Ponysay}
27 | *
28 | * @author Mattias Andrée, m@maandree.se
29 | */
30 | public class PonysayLinux extends PonysaySubmodule
31 | {
32 | /**
33 | * Constructor
34 | *
35 | * @param flags Flags passed to the module
36 | */
37 | public PonysayLinux(HashMap flags)
38 | {
39 | this.chroma = (flags.containsKey("chroma") == false) ? 1 : Common.parseDouble(flags.get("chroma"));
40 | this.colourful = (flags.containsKey("colourful") == false) || flags.get("colourful").toLowerCase().startsWith("y");
41 | this.fullcolour = flags.containsKey("fullcolour") && flags.get("fullcolour").toLowerCase().startsWith("y");
42 | this.palette = (flags.containsKey("palette") == false) ? null : PonysayXterm.parsePalette(flags.get("palette"));
43 | }
44 |
45 |
46 |
47 | /**
48 | * Output option: chroma weight, negative for sRGB distance
49 | */
50 | protected double chroma;
51 |
52 | /**
53 | * Output option: colourful TTY
54 | */
55 | protected boolean colourful;
56 |
57 | /**
58 | * Output option: do not limit to xterm 256 standard colours
59 | */
60 | protected boolean fullcolour;
61 |
62 | /**
63 | * Input/output option: colour palette
64 | */
65 | protected Color[] palette;
66 |
67 | /**
68 | * Auxiliary: whether the parsing is currectly in a CSI sequence
69 | */
70 | private boolean csi = false;
71 |
72 | /**
73 | * Auxiliary: whether the parsing is currectly in a OSI sequence
74 | */
75 | private boolean osi = false;
76 |
77 | /**
78 | * Auxiliary: parsing buffer
79 | */
80 | private int[] buf = new int[256];
81 |
82 | /**
83 | * Auxiliary: parsing buffer pointer
84 | */
85 | private int ptr = 0;
86 |
87 | /**
88 | * Auxiliary: parsing return array
89 | */
90 | private Object[] rcbuf = new Object[3];
91 |
92 |
93 |
94 | /**
95 | * {@inheritDoc}
96 | */
97 | public boolean[][] getPlains()
98 | {
99 | return new boolean[][] {
100 | {false, false, false, false, false, false, false, false, false},
101 | {true, false, false, false, false, false, false, false, false, false},
102 | {true, false, false, false, false, false, false, false, false}};
103 | }
104 |
105 |
106 | /**
107 | * {@inheritDoc}
108 | */
109 | public void initImport(Color[] colours)
110 | {
111 | if (this.palette != null)
112 | System.arraycopy(this.palette, 0, colours, 0, 16);
113 | else
114 | this.palette = parsePalette("");
115 | }
116 |
117 |
118 | /**
119 | * {@inheritDoc}
120 | */
121 | public String initExport(Color[] colours)
122 | {
123 | if (this.palette != null)
124 | System.arraycopy(this.palette, 0, colours, 0, 16);
125 | else
126 | this.palette = parsePalette("");
127 |
128 | StringBuilder resetPalette = new StringBuilder();
129 | if (this.colourful)
130 | for (int i = 0; i < 16; i++)
131 | { Colour colour = new Colour(i);
132 | resetPalette.append("\033]P");
133 | resetPalette.append("0123456789ABCDEF".charAt(i));
134 | resetPalette.append("0123456789ABCDEF".charAt(colour.red >>> 4));
135 | resetPalette.append("0123456789ABCDEF".charAt(colour.red & 15));
136 | resetPalette.append("0123456789ABCDEF".charAt(colour.green >>> 4));
137 | resetPalette.append("0123456789ABCDEF".charAt(colour.green & 15));
138 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue >>> 4));
139 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue & 15));
140 | }
141 | else
142 | for (int i : new int[] { 7, 15 })
143 | { Colour colour = new Colour(i);
144 | resetPalette.append("\033]P");
145 | resetPalette.append("0123456789ABCDEF".charAt(i));
146 | resetPalette.append("0123456789ABCDEF".charAt(colour.red >>> 4));
147 | resetPalette.append("0123456789ABCDEF".charAt(colour.red & 15));
148 | resetPalette.append("0123456789ABCDEF".charAt(colour.green >>> 4));
149 | resetPalette.append("0123456789ABCDEF".charAt(colour.green & 15));
150 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue >>> 4));
151 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue & 15));
152 | }
153 |
154 | return resetPalette == null ? null : resetPalette.toString();
155 | }
156 |
157 |
158 | /**
159 | * {@inheritDoc}
160 | */ // TODO cache colour matching
161 | public String applyColour(Color[] palette, Color oldBackground, Color oldForeground, boolean[] oldFormat, Color newBackground, Color newForeground, boolean[] newFormat)
162 | {
163 | StringBuilder rc = new StringBuilder();
164 |
165 | int colourindex1back = -1, colourindex2back = -1;
166 | int colourindex1fore = -1, colourindex2fore = -1;
167 |
168 | if ((oldBackground != null) && (newBackground == null))
169 | { Color colour = palette[0] = this.palette[0];
170 | rc.append("m\033]P0");
171 | rc.append("0123456789ABCDEF".charAt(colour.getRed() >>> 4));
172 | rc.append("0123456789ABCDEF".charAt(colour.getRed() & 15));
173 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() >>> 4));
174 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() & 15));
175 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() >>> 4));
176 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() & 15));
177 | rc.append("\033[49");
178 | }
179 | else if ((oldBackground == null) || (oldBackground.equals(newBackground) == false))
180 | if (newBackground != null)
181 | { if (this.fullcolour == false)
182 | colourindex1back = matchColour(newBackground, palette, 16, 256, this.chroma);
183 | colourindex2back = this.colourful ? matchColour(this.fullcolour ? newBackground : palette[colourindex1back], this.palette, 0, 8, this.chroma) : 7;
184 | }
185 |
186 | if ((oldForeground != null) && (newForeground == null))
187 | { Color colour = palette[7] = this.palette[7];
188 | rc.append("m\033]P7");
189 | rc.append("0123456789ABCDEF".charAt(colour.getRed() >>> 4));
190 | rc.append("0123456789ABCDEF".charAt(colour.getRed() & 15));
191 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() >>> 4));
192 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() & 15));
193 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() >>> 4));
194 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() & 15));
195 | rc.append("\033[39");
196 | }
197 | else if ((oldForeground == null) || (oldForeground.equals(newForeground) == false))
198 | if (newForeground != null)
199 | { if (this.fullcolour == false)
200 | colourindex1fore = matchColour(newForeground, palette, 16, 256, this.chroma);
201 | int s = ((newFormat.length > 9) && newFormat[9]) ? 0 : (newFormat[0] ? 8 : 0);
202 | int e = ((newFormat.length > 9) && newFormat[9]) ? 16 : (s + 8);
203 | colourindex2fore = this.colourful ? matchColour(this.fullcolour ? newForeground : palette[colourindex1fore], this.palette, s, e, this.chroma) : 15;
204 | if (((colourindex2fore == 0) && (newBackground == null)) || (colourindex2fore == colourindex2back))
205 | colourindex2fore ^= 8;
206 | }
207 |
208 | if (colourindex2back != -1)
209 | { Color colour = this.fullcolour ? newBackground : palette[colourindex1back];
210 | rc.append("m\033]P");
211 | rc.append("0123456789ABCDEF".charAt(colourindex2back));
212 | rc.append("0123456789ABCDEF".charAt(colour.getRed() >>> 4));
213 | rc.append("0123456789ABCDEF".charAt(colour.getRed() & 15));
214 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() >>> 4));
215 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() & 15));
216 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() >>> 4));
217 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() & 15));
218 | rc.append("\033[4");
219 | rc.append(colourindex2back);
220 | }
221 |
222 | if (colourindex2fore != -1)
223 | { Color colour = this.fullcolour ? newForeground : palette[colourindex1fore];
224 | rc.append("m\033]P");
225 | rc.append("0123456789ABCDEF".charAt(colourindex2fore));
226 | rc.append("0123456789ABCDEF".charAt(colour.getRed() >>> 4));
227 | rc.append("0123456789ABCDEF".charAt(colour.getRed() & 15));
228 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() >>> 4));
229 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() & 15));
230 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() >>> 4));
231 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() & 15));
232 | rc.append("\033[3");
233 | rc.append(colourindex2fore & 7);
234 | }
235 |
236 | boolean temp = newFormat[0];
237 | newFormat[0] = (colourindex2fore == -1) ? oldFormat[0] : ((8 <= colourindex2fore) && (colourindex2fore < 16));
238 | for (int i = 0; i < 9; i++)
239 | if (newFormat[i] ^ oldFormat[i])
240 | if ((oldFormat[i] = newFormat[i]))
241 | { rc.append(";0");
242 | rc.append(i + 1);
243 | }
244 | else
245 | { rc.append(";2");
246 | rc.append(i + 1);
247 | }
248 | newFormat[0] = temp;
249 |
250 | String _rc = rc.toString();
251 | if (_rc.isEmpty())
252 | return "";
253 | return ("\033[" + _rc.substring(1)).replace("\033[\033]", "\033]") + "m";
254 | }
255 |
256 |
257 | /**
258 | * {@inheritDoc}
259 | */
260 | public Object[] parseEscape(int c, Color background, Color foreground, boolean[] format, Color[] colours)
261 | {
262 | boolean escape = true;
263 | if (osi)
264 | if (this.ptr > 0)
265 | { this.buf[this.ptr++ - 1] = c;
266 | if (this.ptr == 8)
267 | { this.ptr = 0;
268 | osi = escape = false;
269 | int index = (this.buf[0] <= '9') ? (this.buf[0] & 15) : ((this.buf[0] & 15) + 9);
270 | int red = (this.buf[1] <= '9') ? (this.buf[1] & 15) : ((this.buf[1] & 15) + 9);
271 | red = (red << 4) | ((this.buf[2] <= '9') ? (this.buf[2] & 15) : ((this.buf[2] & 15) + 9));
272 | int green = (this.buf[3] <= '9') ? (this.buf[3] & 15) : ((this.buf[3] & 15) + 9);
273 | green = (green << 4) | ((this.buf[4] <= '9') ? (this.buf[4] & 15) : ((this.buf[4] & 15) + 9));
274 | int blue = (this.buf[5] <= '9') ? (this.buf[5] & 15) : ((this.buf[5] & 15) + 9);
275 | blue = (blue << 4) | ((this.buf[6] <= '9') ? (this.buf[6] & 15) : ((this.buf[6] & 15) + 9));
276 | colours[index] = new Color(red, green, blue);
277 | }
278 | }
279 | else if (this.ptr < 0)
280 | { if (~this.ptr == this.buf.length)
281 | System.arraycopy(this.buf, 0, this.buf = new int[~this.ptr << 1], 0, ~this.ptr);
282 | if (c == '\\')
283 | { this.ptr = ~this.ptr;
284 | this.ptr--;
285 | if ((this.ptr > 8) && (this.buf[this.ptr] == '\033') && (this.buf[0] == ';'))
286 | { int[] _code = new int[this.ptr - 1];
287 | System.arraycopy(this.buf, 1, _code, 0, this.ptr - 1);
288 | String[] code = Common.utf32to16(_code).split(";");
289 | if (code.length == 2)
290 | { int index = Integer.parseInt(code[0]);
291 | code = code[1].split("/");
292 | if ((code.length == 3) && (code[0].startsWith("rgb:")))
293 | { code[0] = code[0].substring(4);
294 | int red = Integer.parseInt(code[0], 16);
295 | int green = Integer.parseInt(code[1], 16);
296 | int blue = Integer.parseInt(code[2], 16);
297 | colours[index] = new Color(red, green, blue);
298 | } } }
299 | this.ptr = 0;
300 | osi = escape = false;
301 | }
302 | else
303 | { this.buf[~this.ptr] = c;
304 | this.ptr--;
305 | }
306 | }
307 | else if (c == 'P') this.ptr = 1;
308 | else if (c == '4') this.ptr = ~0;
309 | else
310 | { osi = escape = false;
311 | /*items.add(new Pony.Cell('\033', foreground, background, format));
312 | items.add(new Pony.Cell(']', foreground, background, format));
313 | items.add(new Pony.Cell(c, foreground, background, format));*/
314 | System.err.println("\033[01;31mutil-say: warning: bad escape sequence: OSI 0x" + Integer.toString(c) + "\033[00m");
315 | }
316 | else if (csi)
317 | { if (this.ptr == this.buf.length)
318 | System.arraycopy(this.buf, 0, this.buf = new int[this.ptr << 1], 0, this.ptr);
319 | this.buf[this.ptr++] = c;
320 | if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) || (c == '~'))
321 | { csi = escape = false;
322 | this.ptr--;
323 | if (c == 'm')
324 | { int[] _code = new int[this.ptr];
325 | System.arraycopy(this.buf, 0, _code, 0, this.ptr);
326 | String[] code = Common.utf32to16(_code).split(";");
327 | int xterm256 = 0;
328 | boolean back = false;
329 | int forei = -2;
330 | for (String seg : code)
331 | { int value = Integer.parseInt(seg);
332 | if (xterm256 == 2)
333 | { xterm256 = 0;
334 | if (back) background = colours[value];
335 | else forei = value;
336 | }
337 | else if (value == 0)
338 | { for (int i = 0; i < 9; i++)
339 | format[i] = false;
340 | background = colours[0].equals(this.palette[0]) ? null : colours[0];
341 | forei = colours[7].equals(this.palette[7]) ? -1 : 7;
342 | }
343 | else if (xterm256 == 1)
344 | xterm256 = value == 5 ? 2 : 0;
345 | else if (value < 10)
346 | format[value - 1] = true;
347 | else if ((20 < value) && (value < 30))
348 | format[value - 21] = false;
349 | else if (value == 39) forei = colours[7].equals(this.palette[7]) ? -1 : 7;
350 | else if (value == 49) background = colours[0].equals(this.palette[0]) ? null : colours[0];
351 | else if (value == 38) xterm256 = 1;
352 | else if (value == 48) xterm256 = 1;
353 | else if (value < 38) forei = value - 30;
354 | else if (value < 48) background = colours[value - 40];
355 | if (xterm256 == 1)
356 | back = value == 48;
357 | }
358 | if (forei == -1)
359 | foreground = null;
360 | else if (forei >= 0)
361 | if ((forei < 8) && format[0])
362 | foreground = colours[forei | 8];
363 | else
364 | foreground = colours[forei];
365 | }
366 | this.ptr = 0;
367 | }
368 | }
369 | else if (c == '[')
370 | { csi = true;
371 | this.ptr = 0;
372 | }
373 | else if (c == ']')
374 | osi = true;
375 | else
376 | { escape = false;
377 | /*items.add(new Pony.Cell('\033', foreground, background, format));
378 | items.add(new Pony.Cell(c, foreground, background, format));*/
379 | System.err.println("\033[01;31mutil-say: warning: bad escape sequence: ESC 0x" + Integer.toString(c, 16) + "\033[00m");
380 | }
381 |
382 | this.rcbuf[0] = background;
383 | this.rcbuf[1] = foreground;
384 | this.rcbuf[2] = escape ? Boolean.TRUE : Boolean.FALSE;
385 | return this.rcbuf;
386 | }
387 |
388 |
389 |
390 | /**
391 | * Parse palette
392 | *
393 | * @param value String representation, without ESC, ] or P
394 | * @return Raw representation
395 | */
396 | public static Color[] parsePalette(String value)
397 | {
398 | String val = null;
399 | { int ptr = 0;
400 | char[] buf = new char[value.length()];
401 | for (int i = 0, n = buf.length; i < n; i++)
402 | { char c = value.charAt(i);
403 | if ((c != '\033') && (c != ']') && (c != 'P'))
404 | buf[ptr++] = c;
405 | }
406 | val = (new String(buf, 0, ptr)).toUpperCase();
407 | }
408 | String defvalue = "00000001AA0000200AA003AA550040000AA5AA00AA600AAAA7AAAAAA"
409 | + "85555559FF5555A55FF55BFFFF55C5555FFDFF55FFE55FFFFFFFFFFF";
410 | Color[] palette = new Color[16];
411 | for (int ptr = 0, n = defvalue.length(); ptr < n; ptr += 7)
412 | {
413 | int index = Integer.parseInt(defvalue.substring(ptr + 0, ptr + 1), 16);
414 | int red = Integer.parseInt(defvalue.substring(ptr + 1, ptr + 3), 16);
415 | int green = Integer.parseInt(defvalue.substring(ptr + 3, ptr + 5), 16);
416 | int blue = Integer.parseInt(defvalue.substring(ptr + 5, ptr + 7), 16);
417 | palette[index] = new Color(red, green, blue);
418 | }
419 | for (int ptr = 0, n = val.length(); ptr < n; ptr += 7)
420 | {
421 | int index = Integer.parseInt(val.substring(ptr + 0, ptr + 1), 16);
422 | int red = Integer.parseInt(val.substring(ptr + 1, ptr + 3), 16);
423 | int green = Integer.parseInt(val.substring(ptr + 3, ptr + 5), 16);
424 | int blue = Integer.parseInt(val.substring(ptr + 5, ptr + 7), 16);
425 | palette[index] = new Color(red, green, blue);
426 | }
427 | return palette;
428 | }
429 |
430 | }
431 |
432 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/PonysaySubmodule.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.awt.*;
22 | import java.util.*;
23 |
24 |
25 | /**
26 | * Platform submodule interface for {@link Ponysay}
27 | *
28 | * @author Mattias Andrée, m@maandree.se
29 | */
30 | public abstract class PonysaySubmodule
31 | {
32 | /**
33 | * Get the plain format styles to use
34 | *
35 | * @return {plain for text, plain for one pixel, plain for two pixels}
36 | */
37 | public abstract boolean[][] getPlains();
38 |
39 | /**
40 | * Initialise the import
41 | *
42 | * @param colours The supermodule's colour palette
43 | */
44 | public abstract void initImport(Color[] colours);
45 |
46 | /**
47 | * Initialise the export and return a string used to reset the colour palette
48 | *
49 | * @param colours The supermodule's colour palette
50 | * @return String to print to reset the colour palette
51 | */
52 | public abstract String initExport(Color[] colours);
53 |
54 | /**
55 | * Get ANSI colour sequence to append to the output
56 | *
57 | * @param palette The current colour palette
58 | * @param oldBackground The current background colour
59 | * @param oldForeground The current foreground colour
60 | * @param oldFormat The current text format
61 | * @param newBackground The new background colour
62 | * @param newForeground The new foreground colour
63 | * @param newFormat The new text format
64 | */
65 | public abstract String applyColour(Color[] palette, Color oldBackground, Color oldForeground, boolean[] oldFormat, Color newBackground, Color newForeground, boolean[] newFormat);
66 |
67 | /**
68 | * Parse escape sequences
69 | *
70 | * @param c The current character in the parsing
71 | * @param background The current background colour
72 | * @param foreground The current foreground colour
73 | * @param format The current format, may be updated in-place
74 | * @param colours The current palette, may be updated in-place
75 | * @return The background colour, the foreground colour and state: {@code {background, foreground, Boolean.TRUE|Boolean.FALSE}},
76 | * wheere the state is true as along as the escape parsing has not completed
77 | */
78 | public abstract Object[] parseEscape(int c, Color background, Color foreground, boolean[] format, Color[] colours);
79 |
80 |
81 |
82 | /**
83 | * Colour CIELAB value cache
84 | */
85 | private static ThreadLocal> labMap = new ThreadLocal>();
86 |
87 | /**
88 | * Chroma weight using in {@link #labMap}
89 | */
90 | private static ThreadLocal labMapWeight = new ThreadLocal();
91 |
92 |
93 |
94 | /**
95 | * Get the closest matching colour
96 | *
97 | * @param colour The colour to match
98 | * @param palette The palette for which to match
99 | * @param paletteStart The beginning of the usable part of the palette
100 | * @param paletteEnd The exclusive end of the usable part of the palette
101 | * @param chromaWeight The chroma weight, negative for sRGB distance
102 | * @return The index of the closest colour in the palette
103 | */
104 | protected static int matchColour(Color colour, Color[] palette, int paletteStart, int paletteEnd, double chromaWeight)
105 | {
106 | if (chromaWeight < 0.0)
107 | {
108 | int bestI = paletteStart;
109 | int bestD = 4 * 256 * 256;
110 | for (int i = paletteStart; i < paletteEnd; i++)
111 | {
112 | int ðr = colour.getRed() - palette[i].getRed();
113 | int ðg = colour.getGreen() - palette[i].getGreen();
114 | int ðb = colour.getBlue() - palette[i].getBlue();
115 |
116 | int ð = ðr*ðr + ðg*ðg + ðb*ðb;
117 | if (bestD > ð)
118 | { bestD = ð;
119 | bestI = i;
120 | }
121 | }
122 | return bestI;
123 | }
124 |
125 | Double _chroma = labMapWeight.get();
126 | HashMap _labMap = ((_chroma == null) || (_chroma.doubleValue() != chromaWeight)) ? null : labMap.get();
127 | if (_labMap == null)
128 | { labMap.set(_labMap = new HashMap());
129 | labMapWeight.set(new Double(chromaWeight));
130 | }
131 |
132 | double[] lab = _labMap.get(colour);
133 | /* if (lab == null) */ // FIXME Why does this not work!?
134 | _labMap.put(colour, lab = Colour.toLab(colour.getRed(), colour.getGreen(), colour.getBlue(), chromaWeight));
135 | double L = lab[0], a = lab[1], b = lab[2];
136 |
137 | int bestI = -1;
138 | double bestD = 0.0;
139 | Color p;
140 | for (int i = paletteStart; i < paletteEnd; i++)
141 | {
142 | double[] tLab = _labMap.get(p = palette[i]);
143 | /* if (tLab == null) */ // FIXME Why does this not work!?
144 | _labMap.put(colour, tLab = Colour.toLab(p.getRed(), p.getGreen(), p.getBlue(), chromaWeight));
145 | double ðL = L - tLab[0];
146 | double ða = a - tLab[1];
147 | double ðb = b - tLab[2];
148 |
149 | double ð = ðL*ðL + ða*ða + ðb*ðb;
150 | if ((bestD > ð) || (bestI < 0))
151 | { bestD = ð;
152 | bestI = i;
153 | }
154 | }
155 |
156 | return bestI;
157 | }
158 | }
159 |
160 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/PonysayXterm.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.awt.*;
22 | import java.util.*;
23 |
24 |
25 | /**
26 | * xterm-256color submodule for {@link Ponysay}
27 | *
28 | * @author Mattias Andrée, m@maandree.se
29 | */
30 | public class PonysayXterm extends PonysaySubmodule
31 | {
32 | /**
33 | * Constructor
34 | *
35 | * @param flags Flags passed to the module
36 | */
37 | public PonysayXterm(HashMap flags)
38 | {
39 | this.chroma = (flags.containsKey("chroma") == false) ? 1 : Common.parseDouble(flags.get("chroma"));
40 | this.colourful = (flags.containsKey("colourful") == false) || flags.get("colourful").toLowerCase().startsWith("y");
41 | this.fullcolour = flags.containsKey("fullcolour") && flags.get("fullcolour").toLowerCase().startsWith("y");
42 | this.palette = (flags.containsKey("palette") == false) ? null : PonysayXterm.parsePalette(flags.get("palette"));
43 | }
44 |
45 |
46 |
47 | /**
48 | * Output option: chroma weight, negative for sRGB distance
49 | */
50 | protected double chroma;
51 |
52 | /**
53 | * Output option: colourful TTY
54 | */
55 | protected boolean colourful;
56 |
57 | /**
58 | * Output option: do not limit to xterm 256 standard colours
59 | */
60 | protected boolean fullcolour;
61 |
62 | /**
63 | * Input/output option: colour palette
64 | */
65 | protected Color[] palette;
66 |
67 | // KEYWORD when colourlabs supports convertion from sRGB, enabled preceptional distance
68 |
69 | /**
70 | * Auxiliary: whether the parsing is currectly in a CSI sequence
71 | */
72 | private boolean csi = false;
73 |
74 | /**
75 | * Auxiliary: whether the parsing is currectly in a OSI sequence
76 | */
77 | private boolean osi = false;
78 |
79 | /**
80 | * Auxiliary: parsing buffer
81 | */
82 | private int[] buf = new int[256];
83 |
84 | /**
85 | * Auxiliary: parsing buffer pointer
86 | */
87 | private int ptr = 0;
88 |
89 | /**
90 | * Auxiliary: parsing return array
91 | */
92 | private Object[] rcbuf = new Object[3];
93 |
94 |
95 |
96 | /**
97 | * {@inheritDoc}
98 | */
99 | public boolean[][] getPlains()
100 | {
101 | boolean bold = this.fullcolour;
102 | return new boolean[][] {
103 | {false, false, false, false, false, false, false, false, false},
104 | {bold, false, false, false, false, false, false, false, false, false},
105 | {bold, false, false, false, false, false, false, false, false}};
106 | }
107 |
108 |
109 | /**
110 | * {@inheritDoc}
111 | */
112 | public void initImport(Color[] colours)
113 | {
114 | if (this.palette != null)
115 | System.arraycopy(this.palette, 0, colours, 0, 16);
116 | else
117 | this.palette = parsePalette("");
118 | }
119 |
120 |
121 | /**
122 | * {@inheritDoc}
123 | */
124 | public String initExport(Color[] colours)
125 | {
126 | if (this.palette != null)
127 | System.arraycopy(this.palette, 0, colours, 0, 16);
128 | else
129 | this.palette = parsePalette("");
130 |
131 | StringBuilder resetPalette = null;
132 | if (this.fullcolour)
133 | { resetPalette = new StringBuilder();
134 | if (this.colourful)
135 | for (int i = 0; i < 16; i++)
136 | { Colour colour = new Colour(i);
137 | resetPalette.append("\033]4;");
138 | resetPalette.append(i);
139 | resetPalette.append(";rgb:");
140 | resetPalette.append("0123456789ABCDEF".charAt(colour.red >>> 4));
141 | resetPalette.append("0123456789ABCDEF".charAt(colour.red & 15));
142 | resetPalette.append('/');
143 | resetPalette.append("0123456789ABCDEF".charAt(colour.green >>> 4));
144 | resetPalette.append("0123456789ABCDEF".charAt(colour.green & 15));
145 | resetPalette.append('/');
146 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue >>> 4));
147 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue & 15));
148 | resetPalette.append("\033\\");
149 | }
150 | else
151 | for (int i : new int[] { 7, 15 })
152 | { Colour colour = new Colour(i);
153 | resetPalette.append("\033]4;");
154 | resetPalette.append(i);
155 | resetPalette.append(";rgb:");
156 | resetPalette.append("0123456789ABCDEF".charAt(colour.red >>> 4));
157 | resetPalette.append("0123456789ABCDEF".charAt(colour.red & 15));
158 | resetPalette.append('/');
159 | resetPalette.append("0123456789ABCDEF".charAt(colour.green >>> 4));
160 | resetPalette.append("0123456789ABCDEF".charAt(colour.green & 15));
161 | resetPalette.append('/');
162 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue >>> 4));
163 | resetPalette.append("0123456789ABCDEF".charAt(colour.blue & 15));
164 | resetPalette.append("\033\\");
165 | } }
166 |
167 | return resetPalette == null ? null : resetPalette.toString();
168 | }
169 |
170 |
171 | /**
172 | * {@inheritDoc}
173 | */ // TODO cache colour matching
174 | public String applyColour(Color[] palette, Color oldBackground, Color oldForeground, boolean[] oldFormat, Color newBackground, Color newForeground, boolean[] newFormat)
175 | {
176 | StringBuilder rc = new StringBuilder();
177 |
178 | int colourindex1back = -1, colourindex2back = -1;
179 | int colourindex1fore = -1, colourindex2fore = -1;
180 |
181 | if ((oldBackground != null) && (newBackground == null))
182 | rc.append(";49");
183 | else if ((oldBackground == null) || (oldBackground.equals(newBackground) == false))
184 | if (newBackground != null)
185 | {
186 | colourindex1back = matchColour(newBackground, palette, 16, 256, this.chroma);
187 | if (this.fullcolour)
188 | colourindex2back = this.colourful ? matchColour(this.fullcolour ? newBackground : palette[colourindex1back], this.palette, 0, 8, this.chroma) : 7;
189 | else
190 | colourindex2back = colourindex1back;
191 | }
192 |
193 | if ((oldForeground != null) && (newForeground == null))
194 | rc.append(";39");
195 | else if ((oldForeground == null) || (oldForeground.equals(newForeground) == false))
196 | if (newForeground != null)
197 | {
198 | colourindex1fore = matchColour(newForeground, palette, 16, 256, this.chroma);
199 | if (this.fullcolour)
200 | { int s = ((newFormat.length > 9) && newFormat[9]) ? 0 : (newFormat[0] ? 8 : 0);
201 | int e = ((newFormat.length > 9) && newFormat[9]) ? 16 : (s + 8);
202 | colourindex2fore = this.colourful ? matchColour(this.fullcolour ? newForeground : palette[colourindex1fore], this.palette, s, e, this.chroma) : 15;
203 | if (((colourindex2fore == 0) && (newBackground == null)) || (colourindex2fore == colourindex2back))
204 | colourindex2fore ^= 8;
205 | }
206 | else
207 | colourindex2fore = colourindex1fore;
208 | }
209 |
210 | if (colourindex2back != -1)
211 | if (this.fullcolour)
212 | { Color colour = newBackground;
213 | rc.append("m\033]4;");
214 | rc.append(colourindex2back);
215 | rc.append(";rgb:");
216 | rc.append("0123456789ABCDEF".charAt(colour.getRed() >>> 4));
217 | rc.append("0123456789ABCDEF".charAt(colour.getRed() & 15));
218 | rc.append('/');
219 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() >>> 4));
220 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() & 15));
221 | rc.append('/');
222 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() >>> 4));
223 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() & 15));
224 | rc.append("\033\\\033[4");
225 | rc.append(colourindex2back);
226 | palette[colourindex2back] = colour;
227 | }
228 | else if (colourindex2back < 16)
229 | { rc.append(";4");
230 | rc.append(colourindex2back);
231 | }
232 | else
233 | { rc.append(";48;5;");
234 | rc.append(colourindex2back);
235 | }
236 |
237 | if (colourindex2fore != -1)
238 | if (this.fullcolour)
239 | { Color colour = newForeground;
240 | rc.append("m\033]4;");
241 | rc.append(colourindex2fore);
242 | rc.append(";rgb:");
243 | rc.append("0123456789ABCDEF".charAt(colour.getRed() >>> 4));
244 | rc.append("0123456789ABCDEF".charAt(colour.getRed() & 15));
245 | rc.append('/');
246 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() >>> 4));
247 | rc.append("0123456789ABCDEF".charAt(colour.getGreen() & 15));
248 | rc.append('/');
249 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() >>> 4));
250 | rc.append("0123456789ABCDEF".charAt(colour.getBlue() & 15));
251 | rc.append("\033\\\033[3");
252 | rc.append(colourindex2fore & 7);
253 | palette[colourindex2fore] = colour;
254 | }
255 | else if (colourindex2fore < 16)
256 | { rc.append(";3");
257 | rc.append(colourindex2fore & 7);
258 | }
259 | else
260 | { rc.append(";38;5;");
261 | rc.append(colourindex2fore);
262 | }
263 |
264 | boolean temp = newFormat[0];
265 | newFormat[0] = (colourindex2fore == -1) ? oldFormat[0] : ((8 <= colourindex2fore) && (colourindex2fore < 16));
266 | for (int i = 0; i < 9; i++)
267 | if (newFormat[i] ^ oldFormat[i])
268 | if ((oldFormat[i] = newFormat[i]))
269 | { rc.append(";0");
270 | rc.append(i + 1);
271 | }
272 | else
273 | { rc.append(";2");
274 | rc.append(i + 1);
275 | }
276 | newFormat[0] = temp;
277 |
278 | String _rc = rc.toString();
279 | if (_rc.isEmpty())
280 | return "";
281 | return ("\033[" + _rc.substring(1)).replace("\033[\033]", "\033]") + "m";
282 | }
283 |
284 |
285 | /**
286 | * {@inheritDoc}
287 | */
288 | public Object[] parseEscape(int c, Color background, Color foreground, boolean[] format, Color[] colours)
289 | {
290 | boolean escape = true;
291 | if (osi)
292 | if (this.ptr > 0)
293 | { this.buf[this.ptr++ - 1] = c;
294 | if (this.ptr == 8)
295 | { this.ptr = 0;
296 | osi = escape = false;
297 | int index = (this.buf[0] <= '9') ? (this.buf[0] & 15) : ((this.buf[0] & 15) + 9);
298 | int red = (this.buf[1] <= '9') ? (this.buf[1] & 15) : ((this.buf[1] & 15) + 9);
299 | red = (red << 4) | ((this.buf[2] <= '9') ? (this.buf[2] & 15) : ((this.buf[2] & 15) + 9));
300 | int green = (this.buf[3] <= '9') ? (this.buf[3] & 15) : ((this.buf[3] & 15) + 9);
301 | green = (green << 4) | ((this.buf[4] <= '9') ? (this.buf[4] & 15) : ((this.buf[4] & 15) + 9));
302 | int blue = (this.buf[5] <= '9') ? (this.buf[5] & 15) : ((this.buf[5] & 15) + 9);
303 | blue = (blue << 4) | ((this.buf[6] <= '9') ? (this.buf[6] & 15) : ((this.buf[6] & 15) + 9));
304 | colours[index] = new Color(red, green, blue);
305 | }
306 | }
307 | else if (this.ptr < 0)
308 | { if (~this.ptr == this.buf.length)
309 | System.arraycopy(this.buf, 0, this.buf = new int[~this.ptr << 1], 0, ~this.ptr);
310 | if (c == '\\')
311 | { this.ptr = ~this.ptr;
312 | this.ptr--;
313 | if ((this.ptr > 8) && (this.buf[this.ptr] == '\033') && (this.buf[0] == ';'))
314 | { int[] _code = new int[this.ptr - 1];
315 | System.arraycopy(this.buf, 1, _code, 0, this.ptr - 1);
316 | String[] code = Common.utf32to16(_code).split(";");
317 | if (code.length == 2)
318 | { int index = Integer.parseInt(code[0]);
319 | code = code[1].split("/");
320 | if ((code.length == 3) && (code[0].startsWith("rgb:")))
321 | { code[0] = code[0].substring(4);
322 | int red = Integer.parseInt(code[0], 16);
323 | int green = Integer.parseInt(code[1], 16);
324 | int blue = Integer.parseInt(code[2], 16);
325 | colours[index] = new Color(red, green, blue);
326 | } } }
327 | this.ptr = 0;
328 | osi = escape = false;
329 | }
330 | else
331 | { this.buf[~this.ptr] = c;
332 | this.ptr--;
333 | }
334 | }
335 | else if (c == 'P') this.ptr = 1;
336 | else if (c == '4') this.ptr = ~0;
337 | else
338 | { osi = escape = false;
339 | /*items.add(new Pony.Cell('\033', foreground, background, format));
340 | items.add(new Pony.Cell(']', foreground, background, format));
341 | items.add(new Pony.Cell(c, foreground, background, format));*/
342 | System.err.println("\033[01;31mutil-say: warning: bad escape sequence: OSI 0x" + Integer.toString(c) + "\033[00m");
343 | }
344 | else if (csi)
345 | { if (this.ptr == this.buf.length)
346 | System.arraycopy(this.buf, 0, this.buf = new int[this.ptr << 1], 0, this.ptr);
347 | this.buf[this.ptr++] = c;
348 | if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) || (c == '~'))
349 | { csi = escape = false;
350 | this.ptr--;
351 | if (c == 'm')
352 | { int[] _code = new int[this.ptr];
353 | System.arraycopy(this.buf, 0, _code, 0, this.ptr);
354 | String[] code = Common.utf32to16(_code).split(";");
355 | int xterm256 = 0;
356 | boolean back = false;
357 | int forei = -2;
358 | for (String seg : code)
359 | { int value = Integer.parseInt(seg);
360 | if (xterm256 == 2)
361 | { xterm256 = 0;
362 | if (back) background = colours[value];
363 | else forei = value;
364 | }
365 | else if (value == 0)
366 | { for (int i = 0; i < 9; i++)
367 | format[i] = false;
368 | background = null;
369 | forei = -1;
370 | }
371 | else if (xterm256 == 1)
372 | xterm256 = value == 5 ? 2 : 0;
373 | else if (value < 10)
374 | format[value - 1] = true;
375 | else if ((20 < value) && (value < 30))
376 | format[value - 21] = false;
377 | else if (value == 39) forei = -1;
378 | else if (value == 49) background = null;
379 | else if (value == 38) xterm256 = 1;
380 | else if (value == 48) xterm256 = 1;
381 | else if (value < 38) forei = value - 30;
382 | else if (value < 48) background = colours[value - 40];
383 | else if ((90 <= value) && (value < 98))
384 | background = colours[value - 90 + 8];
385 | else if ((100 <= value) && (value < 108))
386 | forei = value - 100 + 8;
387 | if (xterm256 == 1)
388 | back = value == 48;
389 | }
390 | if (forei == -1)
391 | foreground = null;
392 | else if (forei >= 0)
393 | if ((forei < 8) && format[0])
394 | foreground = colours[forei | 8];
395 | else
396 | foreground = colours[forei];
397 | }
398 | this.ptr = 0;
399 | }
400 | }
401 | else if (c == '[')
402 | { csi = true;
403 | this.ptr = 0;
404 | }
405 | else if (c == ']')
406 | osi = true;
407 | else
408 | { escape = false;
409 | /*items.add(new Pony.Cell('\033', foreground, background, format));
410 | items.add(new Pony.Cell(c, foreground, background, format));*/
411 | System.err.println("\033[01;31mutil-say: warning: bad escape sequence: ESC 0x" + Integer.toString(c, 16) + "\033[00m");
412 | }
413 |
414 | this.rcbuf[0] = background;
415 | this.rcbuf[1] = foreground;
416 | this.rcbuf[2] = escape ? Boolean.TRUE : Boolean.FALSE;
417 | return this.rcbuf;
418 | }
419 |
420 |
421 |
422 | /**
423 | * Parse palette
424 | *
425 | * @param value String representation, without ESC, ] or P
426 | * @return Raw representation
427 | */
428 | public static Color[] parsePalette(String value)
429 | {
430 | String val = null;
431 | { int ptr = 0;
432 | char[] buf = new char[value.length()];
433 | for (int i = 0, n = buf.length; i < n; i++)
434 | { char c = value.charAt(i);
435 | if ((c != '\033') && (c != ']') && (c != 'P'))
436 | if (c == ';')
437 | if ((i > 0) && (buf[ptr - 1] == '4'))
438 | buf[ptr - 1] = '/';
439 | else
440 | buf[ptr++] = '/';
441 | else if (c == ':')
442 | ptr -= 3;
443 | else
444 | buf[ptr++] = c;
445 | }
446 | val = (new String(buf, 0, ptr)).toUpperCase();
447 | }
448 | String defvalue = "00000001AA0000200AA003AA550040000AA5AA00AA600AAAA7AAAAAA"
449 | + "85555559FF5555A55FF55BFFFF55C5555FFDFF55FFE55FFFFFFFFFFF";
450 | Color[] palette = new Color[16];
451 | for (int ptr = 0, n = defvalue.length(); ptr < n; ptr += 7)
452 | {
453 | int index = Integer.parseInt(defvalue.substring(ptr + 0, ptr + 1), 16);
454 | int red = Integer.parseInt(defvalue.substring(ptr + 1, ptr + 3), 16);
455 | int green = Integer.parseInt(defvalue.substring(ptr + 3, ptr + 5), 16);
456 | int blue = Integer.parseInt(defvalue.substring(ptr + 5, ptr + 7), 16);
457 | palette[index] = new Color(red, green, blue);
458 | }
459 | for (int ptr = 0, n = val.length(); ptr < n;)
460 | { int index, red, green, blue;
461 | if (val.charAt(ptr) == '/')
462 | { String v = val.substring(ptr + 1, val.indexOf('\\', ptr));
463 | ptr = v.length() + 2;
464 | String[] vs = v.split("/");
465 | index = Integer.parseInt(vs[0], 10);
466 | red = Integer.parseInt(vs[1], 16);
467 | green = Integer.parseInt(vs[2], 16);
468 | blue = Integer.parseInt(vs[3], 16);
469 | }
470 | else
471 | { index = Integer.parseInt(val.substring(ptr + 0, ptr + 1), 16);
472 | red = Integer.parseInt(val.substring(ptr + 1, ptr + 3), 16);
473 | green = Integer.parseInt(val.substring(ptr + 3, ptr + 5), 16);
474 | blue = Integer.parseInt(val.substring(ptr + 5, ptr + 7), 16);
475 | ptr += 7;
476 | }
477 | palette[index] = new Color(red, green, blue);
478 | }
479 | return palette;
480 | }
481 |
482 | }
483 |
484 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/Program.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.io.*;
22 | import java.util.*;
23 |
24 |
25 | /**
26 | * Program selector for util-say
27 | *
28 | * @author Mattias Andrée, m@maandree.se
29 | */
30 | public class Program
31 | {
32 | /**
33 | * Non-constructor
34 | */
35 | private Program()
36 | {
37 | assert false : "This class [Program] is not meant to be instansiated.";
38 | }
39 |
40 |
41 |
42 | /**
43 | * This is the main entry point of the program
44 | *
45 | * @param args Startup arguments
46 | *
47 | * @throws IOException On I/O exception
48 | */
49 | public static void main(final String... args) throws IOException
50 | {
51 | if ((args.length == 0) || ((args.length == 1) && args[0].equals("--help")))
52 | {
53 | System.out.println("Copyright (C) 2012, 2013 Mattias Andrée ");
54 | System.out.println();
55 | System.out.println("USAGE: ponytool --import module [param*] {--export module [param*]}");
56 | System.out.println();
57 | System.out.println();
58 | System.out.println("This program is free software: you can redistribute it and/or modify");
59 | System.out.println("it under the terms of the GNU General Public License as published by");
60 | System.out.println("the Free Software Foundation, either version 3 of the License, or");
61 | System.out.println("(at your option) any later version.");
62 | System.out.println();
63 | System.out.println("This program is distributed in the hope that it will be useful,");
64 | System.out.println("but WITHOUT ANY WARRANTY; without even the implied warranty of");
65 | System.out.println("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the");
66 | System.out.println("GNU General Public License for more details.");
67 | System.out.println();
68 | System.out.println("You should have received a copy of the GNU General Public License");
69 | System.out.println("along with this program. If not, see .");
70 | System.out.println();
71 | System.out.println();
72 | return;
73 | }
74 |
75 | HashMap params = new HashMap();
76 | String pname = null;
77 | HashMap inparams = null;
78 | String intype = null;
79 | final ArrayList> outparams = new ArrayList>();
80 | final ArrayList outtypes = new ArrayList();
81 |
82 | for (final String arg : args)
83 | if (arg.equals("--in") || arg.equals("--import") || arg.equals("--out") || arg.equals("--export"))
84 | { if (pname != null)
85 | params.put(pname, "yes");
86 | pname = arg.intern();
87 | }
88 | else if ((pname == "--in") || (pname == "--import"))
89 | { inparams = params = new HashMap();
90 | intype = arg.toLowerCase().intern();
91 | pname = null;
92 | }
93 | else if ((pname == "--out") || (pname == "--export"))
94 | { outparams.add(params = new HashMap());
95 | outtypes.add(arg.toLowerCase().intern());
96 | pname = null;
97 | }
98 | else if (arg.startsWith("--") || (pname == null))
99 | { if (pname != null)
100 | params.put(pname, "yes");
101 | int eq = arg.indexOf("=");
102 | if (eq < 0)
103 | pname = arg.replace("-", "");
104 | else
105 | { pname = null;
106 | params.put(arg.substring(0, eq).replace("-", ""), arg.substring(eq + 1));
107 | } }
108 | else
109 | { params.put(pname, arg);
110 | pname = null;
111 | }
112 |
113 | Pony pony = null;
114 | if (intype == "ponysay") pony = (new Ponysay(inparams)).importPony();
115 | else if (intype == "unisay") pony = (new Unisay (inparams)).importPony();
116 | else if (intype == "cowsay") pony = (new Cowsay (inparams)).importPony();
117 | else if (intype == "cat") pony = (new Cat (inparams)).importPony();
118 | else if (intype == "image") pony = (new Image (inparams)).importPony();
119 | else if (intype == "test") pony = (new Test (inparams)).importPony();
120 | //TODO add warning
121 |
122 | for (int i = 0, n = outtypes.size(); i < n; i++)
123 | { final String outtype = outtypes.get(i);
124 | params = outparams.get(i);
125 |
126 | if (outtype == "ponysay") (new Ponysay(params)).exportPony(pony);
127 | else if (outtype == "unisay") (new Unisay (params)).exportPony(pony);
128 | else if (outtype == "cowsay") (new Cowsay (params)).exportPony(pony);
129 | else if (outtype == "cat") (new Cat (params)).exportPony(pony);
130 | else if (outtype == "image") (new Image (params)).exportPony(pony);
131 | else if (outtype == "test") (new Test (params)).exportPony(pony);
132 | //TODO add warning
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/Raw.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.io.*;
22 | import java.awt.Color;
23 | import java.util.*;
24 |
25 |
26 | /**
27 | * Uncooked pony module
28 | *
29 | * @author Mattias Andrée, m@maandree.se
30 | */
31 | public class Raw
32 | {
33 | /**
34 | * Constructor
35 | *
36 | * @param flags Flags passed to the module
37 | */
38 | public Raw(HashMap flags)
39 | {
40 | this.file = (flags.containsKey("file") ? (this.file = flags.get("file")).equals("-") : true) ? null : this.file;
41 | }
42 |
43 |
44 |
45 | /**
46 | * Input/output option: pony file
47 | */
48 | protected String file;
49 |
50 |
51 |
52 | /**
53 | * Import the pony from file
54 | *
55 | * @return The pony
56 | *
57 | * @throws IOException On I/O error
58 | */
59 | public Pony importPony() throws IOException
60 | {
61 | return null;
62 | }
63 |
64 |
65 | /**
66 | * Export a pony to the file
67 | *
68 | * @param pony The pony
69 | *
70 | * @throws IOException On I/O error
71 | */
72 | public void exportPony(Pony pony) throws IOException
73 | {
74 | OutputStream out = null;
75 | try
76 | { out = this.file == null ? System.out : new BufferedOutputStream(new FileOutputStream(this.file));
77 |
78 | print(pony.height, out);
79 | print(pony.width, out);
80 | print(pony.comment, out);
81 |
82 | if (pony.tags == null)
83 | out.write('-');
84 | else
85 | { out.write('{');
86 | for (String[] tag : pony.tags)
87 | { if (tag == null)
88 | { out.write('-');
89 | continue;
90 | }
91 | out.write('(');
92 | for (String s : tag)
93 | print(s, out);
94 | out.write(')');
95 | }
96 | out.write('}');
97 | }
98 |
99 | if (pony.matrix == null)
100 | out.write('-');
101 | else
102 | { out.write('{');
103 | for (Pony.Cell[] row : pony.matrix)
104 | { if (row == null)
105 | { out.write('-');
106 | continue;
107 | }
108 | out.write('[');
109 | for (Pony.Cell cell : row)
110 | { if (cell == null)
111 | { out.write('-');
112 | continue;
113 | }
114 | print(cell.character, out);
115 | print(cell.upperColour, out);
116 | print(cell.lowerColour, out);
117 | print(cell.format, out);
118 | }
119 | out.write(']');
120 | }
121 | out.write('}');
122 | }
123 |
124 | if (pony.metamatrix == null)
125 | out.write('-');
126 | else
127 | { out.write('{');
128 | for (Pony.Meta[][] row : pony.metamatrix)
129 | { if (row == null)
130 | { out.write('-');
131 | continue;
132 | }
133 | out.write('[');
134 | for (Pony.Meta[] cell : row)
135 | { if (cell == null)
136 | { out.write('-');
137 | continue;
138 | }
139 | out.write('(');
140 | for (Pony.Meta meta : cell)
141 | if (meta == null)
142 | out.write('-');
143 | else if (meta instanceof Pony.Combining)
144 | { out.write('T');
145 | Pony.Combining m = (Pony.Combining)meta;
146 | print(m.character, out);
147 | print(m.foregroundColour, out);
148 | print(m.backgroundColour, out);
149 | print(m.format, out);
150 | }
151 | else if (meta instanceof Pony.Recall)
152 | { out.write('$');
153 | Pony.Recall m = (Pony.Recall)meta;
154 | print(m.name, out);
155 | print(m.foregroundColour, out);
156 | print(m.backgroundColour, out);
157 | print(m.format, out);
158 | }
159 | else if (meta instanceof Pony.Store)
160 | { out.write('=');
161 | Pony.Store m = (Pony.Store)meta;
162 | print(m.name, out);
163 | print(m.value, out);
164 | }
165 | else if (meta instanceof Pony.Balloon)
166 | { out.write('B');
167 | Pony.Balloon m = (Pony.Balloon)meta;
168 | print(m.left, out);
169 | print(m.top, out);
170 | print(m.minWidth, out);
171 | print(m.minHeight, out);
172 | print(m.maxWidth, out);
173 | print(m.maxHeight, out);
174 | print(m.justification, out);
175 | }
176 | out.write(')');
177 | }
178 | out.write(']');
179 | }
180 | out.write('}');
181 | }
182 |
183 | out.flush();
184 | }
185 | finally
186 | { if ((out != null) && (out != System.out))
187 | try
188 | { out.close();
189 | }
190 | catch (Throwable ignore)
191 | { // Ignore
192 | } }
193 | }
194 |
195 |
196 | private void print(byte value, OutputStream out) throws IOException
197 | {
198 | if ((value >>> 4) != 0)
199 | { out.write((value & 15) + 'a');
200 | value >>>= 4;
201 | }
202 | out.write((value & 15) + 'A');
203 | }
204 |
205 | private void print(int value, OutputStream out) throws IOException
206 | {
207 | if (value < 0)
208 | { out.write('/');
209 | value = ~value;
210 | }
211 | while ((value >>> 4) != 0)
212 | { out.write((value & 15) + 'a');
213 | value >>>= 4;
214 | }
215 | out.write((value & 15) + 'A');
216 | }
217 |
218 | private void print(Integer value, OutputStream out) throws IOException
219 | {
220 | if (value == null)
221 | out.write('-');
222 | else
223 | print(value.intValue(), out);
224 | }
225 |
226 | private void print(String value, OutputStream out) throws IOException
227 | {
228 | if (value == null)
229 | { out.write(1);
230 | return;
231 | }
232 | for (byte c : value.getBytes("UTF-8"))
233 | if ((c == 0) || (c == 1))
234 | { out.write(192);
235 | out.write(128 | c);
236 | }
237 | else
238 | out.write(c);
239 | out.write(0);
240 | }
241 |
242 | private void print(boolean[] value, OutputStream out) throws IOException
243 | {
244 | if (value == null)
245 | { out.write('-');
246 | return;
247 | }
248 | if (value.length == 0)
249 | { out.write('@');
250 | return;
251 | }
252 | _if:{
253 | if (value.length <= 18)
254 | { for (boolean b : value)
255 | if (b)
256 | break _if;
257 | out.write(value.length + '-');
258 | return;
259 | }}
260 | for (int i = 0, n = value.length; i < n; i += 4)
261 | {
262 | int c = Math.max(n - i, 4);
263 | int v = 0;
264 | for (int j = 0; j < c; j++)
265 | v |= value[i + j] ? (1 << c) : 0;
266 | if (c == 4) v += 'a';
267 | else if (c == 3) v += 'q';
268 | else if (c == 2) v += 'y';
269 | else if (c == 1) v += ']';
270 | if (i + 4 < n)
271 | v += 0x20;
272 | out.write(v);
273 | }
274 | }
275 |
276 | private void print(Color value, OutputStream out) throws IOException
277 | {
278 | if (value == null)
279 | { out.write('-');
280 | return;
281 | }
282 | print(value.getAlpha(), out);
283 | print(value.getRed(), out);
284 | print(value.getGreen(), out);
285 | print(value.getBlue(), out);
286 | }
287 |
288 | }
289 |
290 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/Test.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.io.*;
22 | import java.awt.Color;
23 | import java.util.*;
24 |
25 |
26 | /**
27 | * Test module
28 | *
29 | * @author Mattias Andrée, m@maandree.se
30 | */
31 | public class Test
32 | {
33 | /**
34 | * Constructor
35 | *
36 | * @param flags Flags passed to the module
37 | */
38 | public Test(HashMap flags)
39 | {
40 | // Do nothing
41 | }
42 |
43 |
44 |
45 | /**
46 | * Import a test pony
47 | *
48 | * @return The pony
49 | *
50 | * @throws IOException On I/O error
51 | */
52 | public Pony importPony() throws IOException
53 | {
54 | int Y = 10, X = 20;
55 | Pony pony = new Pony(Y, X, "Test pony", new String[][] {{"PONY", "test"}});
56 | /**/
57 | for (int y = 0; y < Y; y++)
58 | for (int x = 0; x < X; x++)
59 | if ((y < 5) ^ (x < 10))
60 | if ((x & 2) == 2)
61 | pony.matrix[y][x] = new Pony.Cell(Pony.Cell.PIXELS, Color.BLUE, Color.RED, null);
62 | else
63 | pony.matrix[y][x] = new Pony.Cell(Pony.Cell.PIXELS, Color.RED, Color.BLUE, null);
64 | else
65 | if ((x & 2) == 2)
66 | pony.matrix[y][x] = new Pony.Cell(Pony.Cell.PIXELS, Color.GREEN, Color.YELLOW, null);
67 | else
68 | pony.matrix[y][x] = new Pony.Cell(Pony.Cell.PIXELS, Color.YELLOW, Color.GREEN, null);
69 | /**/
70 | return pony;
71 | }
72 |
73 |
74 | /**
75 | * Test a pony against a test pony
76 | *
77 | * @param pony The pony
78 | */
79 | public void exportPony(Pony pony)
80 | {
81 | }
82 |
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/src/se/kth/maandree/utilsay/Unisay.java:
--------------------------------------------------------------------------------
1 | /**
2 | * util-say — Utilities for cowsay and cowsay-like programs
3 | *
4 | * Copyright © 2012, 2013 Mattias Andrée (m@maandree.se)
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 | package se.kth.maandree.utilsay;
20 |
21 | import java.util.*;
22 |
23 |
24 | /**
25 | * Unisay support module
26 | *
27 | * @author Mattias Andrée, m@maandree.se
28 | */
29 | public class Unisay extends Ponysay
30 | {
31 | /**
32 | * Constructor
33 | *
34 | * @param flags Flags passed to the module
35 | */
36 | public Unisay(HashMap flags)
37 | {
38 | super(Unisay.modifyFlags(flags));
39 | }
40 |
41 |
42 |
43 | /**
44 | * Modify the flags to fit this module
45 | *
46 | * @param flag The flags
47 | * @return The flags
48 | */
49 | private static HashMap modifyFlags(HashMap flags)
50 | {
51 | flags.put("version", "2.1");
52 | return flags;
53 | }
54 |
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/unisay2img:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | magnified='1'
4 | file='-'
5 | dash=0
6 |
7 | for arg in "$@"; do
8 | if [ $dash = 1 ]; then
9 | file="$arg"
10 | elif [ "$arg" = "--" ]; then
11 | dash=1
12 | elif [ "$arg" = "-2" ]; then
13 | magnified=2
14 | else
15 | file="$arg"
16 | fi
17 | done
18 |
19 | java -jar "$(dirname "$0")/util-say.jar" \
20 | --import unisay --file - --export image --magnified $magnified --file "$file" --left - --right - --bottom - --top -
21 |
22 |
--------------------------------------------------------------------------------
/util-say.texinfo:
--------------------------------------------------------------------------------
1 | \input texinfo @c -*-texinfo-*-
2 |
3 | @c %**start of header
4 | @setfilename util-say.info
5 | @settitle util-say
6 | @afourpaper
7 | @documentencoding UTF-8
8 | @documentlanguage en
9 | @finalout
10 | @c %**end of header
11 | @set VERSION 3.0
12 |
13 | @defindex op
14 |
15 |
16 | @copying
17 | This manual is for util-say
18 | (version @value{VERSION}).
19 |
20 | Copyright @copyright{} 2013 Mattias Andrée
21 |
22 | @quotation
23 | Permission is granted to copy, distribute and/or modify this document
24 | under the terms of the GNU Free Documentation License, Version 1.3 or
25 | any later version published by the Free Software Foundation; with no
26 | Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
27 | Texts. A copy of the license is included in the section entitled
28 | ``GNU Free Documentation License''.
29 | @end quotation
30 | @end copying
31 |
32 | @ifnottex
33 | @node Top
34 | @top util-say: Tools for creating ponies for ponysay and ponysay-like programs
35 | @insertcopying
36 | @end ifnottex
37 |
38 | @titlepage
39 | @title util-say
40 | @subtitle Tools for creating ponies for ponysay and ponysay-like programs
41 | @c ** start of front page image **
42 | @c If print make a pdf or hard copy with the front cover
43 | @c you may or may not want to remove this.
44 | @c @image{infoimage,423.5px}
45 | @c ** end of front page image **
46 | @author by Mattias Andrée (maandree)
47 |
48 | @page
49 | @vskip 0pt plus 1filll
50 | @insertcopying
51 | @end titlepage
52 |
53 | @contents
54 |
55 |
56 | @menu
57 | * Overview:: Brief overview of util-say.
58 | * Background:: Brief background.
59 | * Using the converter:: Using the converter, @command{ponytool}.
60 | * Usage examples:: Examples of basic commands.
61 | * GNU Free Documentation License:: Copying and sharing this manual.
62 | * Concept index:: Concept index.
63 | * Option index:: Option index.
64 | @end menu
65 |
66 |
67 |
68 |
69 | @node Overview
70 | @chapter Overview
71 | @cindex overview
72 |
73 | util-say was historically collection of utilities for creating images for ponysay,
74 | cowsay and similiar programs, hence its name. Nowadays however, it is basically
75 | one utility with a set of modules, called @command{ponytool}, but more utilities
76 | will be added over time.
77 |
78 | @command{ponytool} is used convert an image into another format or change the image's
79 | configurations. Theses images are images be simply rendered in a terminal, and
80 | naturally normal images formats are supported so normal images can be made into
81 | terminal renderable.
82 |
83 |
84 |
85 | @node Background
86 | @chapter Background
87 | @cindex background
88 | @cindex terminal images
89 | @cindex images, terminal
90 |
91 | @cindex glyphs
92 | @cindex Unicode
93 | @cindex UCS
94 | @cindex monospaced fonts
95 | @cindex fonts, monospaces
96 | @cindex block elements
97 | Unicode defines glyphs made for drawing, specifically it defines block elements,
98 | these include glyphs that splits the glyph area vertically in half and definied
99 | all for combinations for filling or keeping empty each half. The empty glyphs
100 | beginng the blankspace character. In monospaced fonts theses are definied to
101 | be of same size.
102 |
103 | @cindex font dimensions
104 | @cindex dimensions, font
105 | @cindex pixel perfect
106 | @cindex mosiac, structure
107 | A font that precisly adheres to the previous paragraph and have the total font
108 | exactly height twice of the width is called pixel perfect to the extend of the
109 | our usage. This lets or use just four, or even only three, glyphs to build
110 | mosiac pictures of characters representing two pixels each, vertically stacked.
111 |
112 | @cindex colour
113 | An essential part of letting one glyph represent two pixels is that terminals
114 | support both foreground and background colours, as well as 240 well definied
115 | colours as well as full transparency.
116 |
117 | This is the foundation that lets use print nice looking images in the terminal,
118 | and it can be done in @command{cat}:able text files, for details on the formats
119 | please refer to the documentation for that specific program.
120 |
121 |
122 |
123 | @node Using the converter
124 | @chapter Using the converter
125 | @cindex converter
126 | @cindex @command{ponytool}
127 |
128 | @cindex importing
129 | @cindex exporting
130 | The command @command{ponytool} is used to convert images between formats and
131 | configurations, it has the capability of importing one file and exporting
132 | multiple files. As you may notice, @command{ponytool} does not support short
133 | options, only long options, and all options takes exactly one argument.
134 |
135 | @cindex invoking
136 | @cindex selecting file
137 | @cindex file, select
138 | @opindex @option{import}
139 | @opindex @option{export}
140 | @opindex @option{in}
141 | @opindex @option{out}
142 | @opindex @option{file}
143 | To use the converter, run command
144 | @command{ponytool --import module [parameters...] @{--export module [parameters...]@}}.
145 | Note that parameters must be added after their @option{--import} or
146 | @option{--export}. Alternatively you can use @option{--in} instead of
147 | @option{--import} or @option{--out} instead of @option{--export}.
148 | Associated with @option{--import} and @option{--export} is a module take
149 | must follow directly. All modules, before for export and import, honors
150 | @option{--file} that takes the file to read to or write from and defaults
151 | to stdin or stdout, @code{-} begin the explicit value for those, and will
152 | note be listed in the module's documention's. If you want your file to
153 | start with @code{--} you will either need to prepend @code{./} or make
154 | @option{--file} and the file name one argument seperated with @code{=},
155 | the latter works for all options.
156 |
157 | @cindex modules
158 | Supported modules are @code{ponysay}, @code{unisay}, @code{cowsay} and
159 | @code{image}, all being case insensitive and support both import and export.
160 |
161 |
162 | @menu
163 | * Ponysay module:: Using the @code{ponysay} module.
164 | * Unisay module:: Using the @code{unisay} module.
165 | * Cowsay module:: Using the @code{cowsay} module.
166 | * Cat module:: Using the @code{cat} module.
167 | * Image module:: Using the @code{image} module.
168 | @end menu
169 |
170 |
171 | @node Ponysay module
172 | @section @code{ponysay} module
173 | @cindex @code{ponysay} module
174 | @cindex module, @code{ponysay}
175 |
176 | @opindex @option{version}
177 | The @code{ponysay} module lets you import and export @command{ponysay}
178 | ponies of any @command{ponysay} version. To select the which version of
179 | @command{ponysay} to use, use the option @option{--version}, the value
180 | is version string (numerals seperated by dots). The version will always
181 | default to the latest version of @command{ponysay}, if not yet stabil.
182 |
183 | The following version spans exists:
184 |
185 | @table @asis
186 | @item @bullet{} 0 @math{<=} @option{version} @math{<} 2.1
187 | @cindex @command{cowsay}
188 | @command{cowsay} format.
189 | @item @bullet{} 2.1 @math{<=} @option{version} @math{<} 2.9
190 | @cindex @command{unisay}
191 | @command{unisay} format.
192 | @item @bullet{} 2.9 @math{<=} @option{version} @math{<} 3
193 | Metadata support is added.
194 | @item @bullet{} 3 @math{<=} @option{version}
195 | Horizontal balloon justification is added.
196 | @end table
197 |
198 | The additional options are supported:
199 |
200 | @table @asis
201 | @item @option{--ignoreballoon} (export/import)
202 | @opindex @option{ignoreballoon}
203 | @cindex ignore balloons
204 | @cindex balloons, ignore
205 | Specifies whether to remove all balloons but not links and substitute with
206 | transparent pixels. To enable this, use a value starting with @code{y} or
207 | @code{Y}.
208 |
209 | @item @option{--ignorelink} (export/import)
210 | @opindex @option{ignorelink}
211 | @cindex ignore links
212 | @cindex links, ignore
213 | Specifies whether to remove all balloons links and substitute with
214 | transparent pixels. To enable this, use a value starting with @code{y} or
215 | @code{Y}, the value defaults to the value of @option{--ignoreballoon}.
216 |
217 | @item @option{--even} (export)
218 | @opindex @option{even}
219 | @cindex right padding
220 | @cindex padding, right
221 | @cindex padding, even
222 | @cindex even out
223 | Specifies whether to pad the the lines to make all lines of same visual
224 | lenght. To disable this, use a value starting with @code{n} or @code{N}.
225 | This option is only available in @option{--export}.
226 |
227 | @item @option{--fullblocks} (export)
228 | @opindex @option{fullblocks}
229 | @cindex block elements
230 | @cindex full blocks
231 | Specifies whether full block elements can be used when a pixel pair has the
232 | same colours; in modes where the paletter is modified, this allows better
233 | selection of colour index. To disable this, use a value starting with
234 | @code{n} or @code{N}. This option is only available in @option{--export}.
235 |
236 | @item @option{--spacesave} (export)
237 | @opindex @option{spacesave}
238 | @cindex compression
239 | @cindex file size
240 | Specifies whether to prefer small files over making the image look good
241 | while marked in a terminal. To enable this, use a value starting with
242 | @code{y} or @code{Y}. This option is only available in @option{--export}.
243 |
244 | @item @option{--zebra} (export)
245 | @opindex @option{zebra}
246 | @cindex zebra effect
247 | Specifies whether to use half block elements when the pixel's an pixel
248 | pair has the same colours. To enable this, use a value starting with
249 | @code{y} or @code{Y}. This option is only available in @option{--export}.
250 |
251 | @item @option{--utf8} (export)
252 | @opindex @option{utf8}
253 | @cindex cowsay encoding
254 | @cindex encoding, escaping
255 | @cindex UTF-8
256 | This option is only available when using the @command{cowsay} format in
257 | @option{--export}, it is manditorly enabled when not using the
258 | @command{cowsay} format. It specifies whether to encode the files in
259 | UTF-8, rather then using escaped strings. To enable this, use a value
260 | starting with @code{y} or @code{Y}.
261 |
262 | @item @option{--escesc} (export)
263 | @opindex @option{escesc}
264 | @cindex cowsay encoding
265 | @cindex encoding, escaping
266 | This option is only available when using the @command{cowsay} format in
267 | @option{--export}, it is manditorly disabled when not using the
268 | @command{cowsay} format. It specifies whether to escape the escape
269 | characters in the files. To enable this, use a value starting with
270 | @code{y} or @code{Y}.
271 |
272 | @item @option{--left} (export)
273 | @opindex @option{left}
274 | @cindex margins
275 | Fix the number emptying columns at the left side of the pony, if the value
276 | cannot be parsed as a non-negative integer, for example @code{-}, the margin
277 | will not be modified from the original image. This options is import
278 | supported in @option{--export}.
279 | Use a value starting with a @code{y} or @code{Y} make the program use a
280 | default value.
281 |
282 | @item @option{--right} (export)
283 | @opindex @option{right}
284 | @cindex margins
285 | Fix the number emptying columns at the right side of the pony, if the value
286 | cannot be parsed as a non-negative integer, for example @code{-}, the margin
287 | will not be modified from the original image. This options is import
288 | supported in @option{--export}.
289 |
290 | Use a value starting with a @code{y} or @code{Y} make the program use a
291 | default value.
292 |
293 | @item @option{--top} (export)
294 | @opindex @option{top}
295 | @cindex margins
296 | Fix the number emptying lines at the top of the pony, if the value cannot
297 | be parsed as a non-negative integer, for example @code{-}, the margin will
298 | not be modified from the original image. This options is import supported
299 | in @option{--export}.
300 |
301 | Use a value starting with a @code{y} or @code{Y} make the program use a
302 | default value.
303 |
304 | @item @option{--bottom} (export)
305 | @opindex @option{bottom}
306 | @cindex margins
307 | Fix the number emptying lines at the bottom of the pony, if the value cannot
308 | be parsed as a non-negative integer, for example @code{-}, the margin will
309 | not be modified from the original image. This options is import supported
310 | in @option{--export}.
311 |
312 | Use a value starting with a @code{y} or @code{Y} make the program use a
313 | default value.
314 |
315 | @item @option{--balloon} (export/import)
316 | @opindex @option{balloon}
317 | @cindex balloon, insert
318 | This specifies whether to insert a balloon and its link at the top left of
319 | the image. Specift the number of lines between the balloon and the pony or
320 | a value starting with a @code{y} or @code{Y} for a default value.
321 |
322 | @item @option{--platform} (export/import)
323 | @opindex @option{platform}
324 | @cindex platform
325 | @cindex system
326 | Specifies a submodule for which platform the pony is or should be encoded.
327 | These submodules supports additional options. The platform string is case
328 | insensitive and ignores hyphens, underscores and blankspaces and trets
329 | @code{colours}, @code{colour}, @code{colors} and @code{color} all as the
330 | same word.
331 | @end table
332 |
333 |
334 | @menu
335 | * XTerm submodule:: Using the @code{xterm-256color} submodule.
336 | * Linux VT submodule:: Using the @code{linux} submodule.
337 | * Haiku submodule:: Using the @code{haiku} submodule.
338 | @end menu
339 |
340 |
341 | @node XTerm submodule
342 | @subsection XTerm submodule
343 | @cindex @code{xterm}, platform
344 | @cindex platform, @code{xterm}
345 | @cindex system, @code{xterm}
346 |
347 | @code{xterm}, or @code{xterm-256color}, is the default module, in @option{--import}
348 | is reading files created with the @code{linux} submodule. @code{xterm} is used for
349 | normal @code{xterm-256color} capable terminals.
350 |
351 | @opindex @option{fullcolour}
352 | @opindex @option{colourful}
353 | @cindex 24-bit colour support
354 | @cindex colour support, 24 bits
355 | @code{xterm} will use the well defined colours with the indices 16 through 255
356 | (inclusive.) If you want to enable use any colour @code{xterm} can modify the palette,
357 | however terminals will normally not support this as the palette will be reset and
358 | normally everything is redrawn when the palette is modified. To do this, use the
359 | option @option{--fullcolour} with a value starting with @code{y} or @code{Y}. In this
360 | mode only the colour indices 7 (white) and 15 (bright white) will be modified and
361 | used, if you want 16 colour indices to be used, use the @option{--colourful} with a
362 | value starting with @code{y} or @code{Y}.
363 |
364 | @opindex @option{palette}
365 | @cindex palette, custom
366 | @cindex custom palette
367 | @cindex @option{fullcolour}
368 | You can specify which palette you want to use by adding it as the value of the option
369 | @option{--palette}, the value does not need to contain the characters ESC, @code{[}
370 | and @code{P}, and both XTerm and Linux VT palette strings are supported. When using
371 | @option{--fullcolour} it is a good idea to use this so the palette you are using does
372 | not get changed when displaying the image.
373 |
374 | @opindex @option{chroma}
375 | @cindex colour matching
376 | @cindex colour distance
377 | @cindex matching, colour
378 | @cindex distance, colour
379 | @cindex CIELAB
380 | @cindex sRGB
381 | @cindex standard RGB
382 | @cindex RGB, standard RGB
383 | The select which colour index to use, as it is limited, the best colour is choosen
384 | by selecting the first enumerated colour with minimal distance. By default the
385 | distances aer calculated as CIELAB distances. If you want to make the chroma more
386 | important than distance, you can specify a non-negative floating value in the
387 | option @option{--chroma}, which as the 1 as its default value. If you prefer
388 | sRGB distances, you can use an invalid value for @option{--chroma}, for example,
389 | @code{-}.
390 |
391 |
392 | @node Linux VT submodule
393 | @subsection Linux VT submodule
394 | @cindex @code{linux}, platform
395 | @cindex platform, @code{linux}
396 | @cindex system, @code{linux}
397 | @cindex @code{tty}, platform
398 | @cindex platform, @code{tty}
399 | @cindex system, @code{tty}
400 |
401 | @code{linux}, or @code{tty}, is the submodule for parse or, primarly, create images
402 | printable in the Linux virtual terminal. You may use @code{xterm} for parsing Linux VT
403 | image, if but if you use @code{linux}, errors the pony will be visible.
404 |
405 | @opindex @option{fullcolour}
406 | @opindex @option{colourful}
407 | @cindex 24-bit colour support
408 | @cindex colour support, 24 bits
409 | @cindex VT switching
410 | @cindex switching VT
411 | @code{linux} will use XTerm's the well defined colours with the indices 16 through 255
412 | (inclusive.), use the option @option{--fullcolour} with a value starting with @code{y}
413 | or @code{Y}, to support any colour. By default ony the colour indices 7 (white) and 15
414 | (bright white) will be used and modified, if you want 16 colour indices to be used,
415 | use the @option{--colourful} with a value starting with @code{y} or @code{Y}.
416 |
417 | @opindex @option{palette}
418 | @cindex palette, custom
419 | @cindex custom palette
420 | @cindex @option{colourful}
421 | You can specify which palette you want to use by adding it as the value of the option
422 | @option{--palette}, the value does not need to contain the characters ESC, @code{[} and
423 | @code{P}. It is recommand no to use @option{--colourful} unless this option is used.
424 |
425 |
426 | @opindex @option{chroma}
427 | @cindex colour matching
428 | @cindex colour distance
429 | @cindex matching, colour
430 | @cindex distance, colour
431 | @cindex CIELAB
432 | @cindex sRGB
433 | @cindex standard RGB
434 | @cindex RGB, standard RGB
435 | The select which colour index to use, as it is limited, the best colour is choosen
436 | by selecting the first enumerated colour with minimal distance. By default the
437 | distances aer calculated as CIELAB distances. If you want to make the chroma more
438 | important than distance, you can specify a non-negative floating value in the
439 | option @option{--chroma}, which as the 1 as its default value. If you prefer
440 | sRGB distances, you can use an invalid value for @option{--chroma}, for example,
441 | @code{-}.
442 |
443 |
444 | @node Haiku submodule
445 | @subsection Haiku submodule
446 | @cindex @code{haiku}, platform
447 | @cindex platform, @code{haiku}
448 | @cindex system, @code{haiku}
449 |
450 | The @code{haiku} submodule works as the @code{xterm} submodule, but does not
451 | support @code{linux} import. The difference between @code{haiku} and @code{xterm}
452 | files is that transparency/default is encoded in conflicting escape sequences.
453 |
454 | @code{haiku} uses @code{CSI 40m} instead of @code{CSI 49m} for transparent
455 | backgrounds, and @code{CSI 37m} instead of @code{CSI 39m} for default
456 | foreground colour. More precisly, colour index 0 is used for the background
457 | colour instead of black, and colour index 7 is used for the foreground colour,
458 | while @code{CSI 49m} and @code{CSI 39m} is not recognised.
459 |
460 |
461 |
462 | @node Unisay module
463 | @section @code{unisay} module
464 | @cindex @code{unisay} module
465 | @cindex module, @code{unisay}
466 |
467 | The @code{unisay} module is identical to @code{ponysay} with
468 | @option{--version=2.1}. (Which as the version of @command{ponysay}, that
469 | dropped the use of cowsay and switch to @command{unisay}'s format.)
470 |
471 |
472 | @node Cowsay module
473 | @section @code{cowsay} module
474 | @cindex @code{cowsay} module
475 | @cindex module, @code{cowsay}
476 |
477 | The @code{cowsay} module is an extension of the @code{ponysay} with
478 | @option{--version=0.1}, so the same options are supported, except
479 | @option{--version}. It can construct images usable with @code{cowsay}.
480 | For import you will need @command{perl} installed as it is used to
481 | parse the cow file, which is a partial @command{perl} script.
482 |
483 |
484 | @node Cat module
485 | @section @code{cat} module
486 | @cindex @code{cat} module
487 | @cindex module, @code{cat}
488 |
489 | The @code{cat} module is identical to @code{ponysay} with
490 | @option{--version=2.8 --balloon=- --ignoreballoon=y --ignorelink=y}.
491 | It is designed to create pure images that are displayable by just
492 | printing them to the terminal as is, for example with @command{cat}.
493 | However the purity will be disrupted if the image contains stores
494 | and recalls, which they does not do as it is not intended for
495 | cross-format use.
496 |
497 |
498 | @node Image module
499 | @section @code{image} module
500 | @cindex @code{image} module
501 | @cindex module, @code{image}
502 |
503 | The @code{image} module lets you import and export regular graphics images,
504 | such as Portable Network Graphics (PNG) files. The module suports the
505 | following options.
506 |
507 | @table @asis
508 | @item @option{--left} (export/import)
509 | @opindex @option{left}
510 | @cindex margins
511 | Fix the number emptying columns at the left side of the pony, if the value
512 | cannot be parsed as a non-negative integer, for example @code{-}, the margin
513 | will not be modified from the original image.
514 |
515 | Use a value starting with a @code{y} or @code{Y} make the program use a
516 | default value.
517 |
518 | @item @option{--right} (export/import)
519 | @opindex @option{right}
520 | @cindex margins
521 | Fix the number emptying columns at the right side of the pony, if the value
522 | cannot be parsed as a non-negative integer, for example @code{-}, the margin
523 | will not be modified from the original image.
524 |
525 | Use a value starting with a @code{y} or @code{Y} make the program use a
526 | default value.
527 |
528 | @item @option{--top} (export/import)
529 | @opindex @option{top}
530 | @cindex margins
531 | Fix the number emptying lines at the top of the pony, if the value cannot
532 | be parsed as a non-negative integer, for example @code{-}, the margin will
533 | not be modified from the original image. However, in @option{--import}
534 | this value must be a non-negative integer, and is the number of additional
535 | lines between the pony and the balloon. Defaults to 3 in @option{--import}.
536 |
537 | Use a value starting with a @code{y} or @code{Y} make the program use a
538 | default value.
539 |
540 | @item @option{--bottom} (export/import)
541 | @opindex @option{bottom}
542 | @cindex margins
543 | Fix the number emptying lines at the bottom of the pony, if the value cannot
544 | be parsed as a non-negative integer, for example @code{-}, the margin will
545 | not be modified from the original image.
546 |
547 | Use a value starting with a @code{y} or @code{Y} make the program use a
548 | default value.
549 |
550 | @item @option{--magnified} (export/import)
551 | @opindex @option{magnified}
552 | @cindex scale up
553 | @cindex magnification
554 | @cindex pixel dimension
555 | Pixel magnification, this specifies the nearest neighbour scale up used on
556 | the image, and default to 2. In @option{--export} this means that every
557 | pixel in the pony be @math{M} by @math{M} pixels if the value is @math{M}.
558 | In @option{--import} it means that the imported image has that magnification
559 | and the avarage pixel value will be used for the created pony. The value
560 | must be a positive integer.
561 |
562 | Use a value starting with a @code{y} or @code{Y} make the program use a
563 | default value.
564 |
565 | @item @option{--encoded} (export/import)
566 | @opindex @option{encoded}
567 | @cindex balloon, encode
568 | @cindex balloon link, encode
569 | @cindex link, encode
570 | @cindex encoded images
571 | @cindex image, encoded
572 | This specifies whether the balloon and balloon link is or should be encoded
573 | into to image. Use a value starting with a @code{y} or @code{Y} to enable this.
574 |
575 | @item @option{--balloon} (export/import)
576 | @opindex @option{balloon}
577 | @cindex balloon, insert
578 | This specifies whether to insert a balloon and its link at the top left of
579 | the image. Use a value starting with a @code{y} or @code{Y} to enable this.
580 |
581 | @item @option{--format} (export)
582 | @opindex @option{format}
583 | @cindex image format
584 | @cindex format, image
585 | @cindex PNG
586 | @cindex Portable Network Graphics
587 | @cindex GIF
588 | @cindex Graphics Interchange Format
589 | This specified what format to export the image with, the image is automatically
590 | select on import. If a value is not specified it will be determined from the
591 | file name and if fall back to Portable Network Graphics (PNG) if it is not
592 | possible to determine. Note that the program will fail if the format is not
593 | recognised, which is a possibility even for determination by file name.
594 | All formats support by your Java installation will be supported; you count on
595 | PNG and Graphics Interchange Format (GIF) being supported.
596 | @end table
597 |
598 |
599 |
600 | @node Usage examples
601 | @chapter Usage examples
602 | @cindex usage examples
603 | @cindex examples, usage
604 |
605 | @cindex create pony file
606 | @cindex make pony file
607 | @cindex pony file, create
608 | @cindex image to pony
609 | @cindex pony from image
610 | To create a pony file from an image, use the command
611 | @command{ponytool --import image --file file.png --export ponysay --balloon y}.
612 |
613 | @cindex make TTY pony
614 | @cindex make Linux VT pony
615 | @cindex create TTY pony
616 | @cindex create Linux VT pony
617 | @cindex TTY pony, create
618 | @cindex Linux VT pony, create
619 | To create a Linux VT pony file from and XTerm pony file, use the command
620 | @command{ponytool --import ponysay --file file.pony --export ponysay --platform tty --left - --right - --top - --bottom - --file tty.pony}.
621 |
622 |
623 |
624 | @node GNU Free Documentation License
625 | @appendix GNU Free Documentation License
626 | @include fdl.texinfo
627 |
628 |
629 | @node Concept index
630 | @appendix Concept index
631 | @printindex cp
632 |
633 | @node Option index
634 | @appendix Option index
635 | @printindex op
636 |
637 |
638 | @bye
639 |
640 |
--------------------------------------------------------------------------------