Merge lp:~philpem/ubuntu/utopic/ptouch-driver/ptouch-driver-fixup into lp:ubuntu/utopic/ptouch-driver

Proposed by Phil Pemberton
Status: Merged
Merge reported by: Till Kamppeter
Merged at revision: not available
Proposed branch: lp:~philpem/ubuntu/utopic/ptouch-driver/ptouch-driver-fixup
Merge into: lp:ubuntu/utopic/ptouch-driver
Diff against target: 5152 lines (+3005/-1764)
23 files modified
.pc/applied-patches (+1/-1)
.pc/philpem-ptouch-fixes/Makefile.am (+91/-0)
.pc/philpem-ptouch-fixes/opt/Brother-Ptouch-AdvanceMedia.xml (+84/-0)
.pc/philpem-ptouch-fixes/opt/Brother-Ptouch-RollFedMedia.xml (+84/-0)
.pc/philpem-ptouch-fixes/printer/Brother-QL-500.xml (+97/-0)
.pc/philpem-ptouch-fixes/printer/Brother-QL-550.xml (+97/-0)
.pc/philpem-ptouch-fixes/printer/Brother-QL-650TD.xml (+97/-0)
.pc/philpem-ptouch-fixes/ptouch-driver-foomatic.spec.in (+102/-0)
.pc/philpem-ptouch-fixes/rastertoptch.c (+1590/-0)
.pc/send-esc-i-A-for-QL-only.patch/rastertoptch.c (+0/-1590)
Makefile.am (+0/-1)
debian/changelog (+7/-0)
debian/patches/foomatic-data-fixes.patch (+0/-11)
debian/patches/philpem-ptouch-fixes (+622/-0)
debian/patches/send-esc-i-A-for-QL-only.patch (+1/-1)
debian/patches/series (+1/-1)
opt/Brother-Ptouch-AdvanceMedia.xml (+0/-84)
opt/Brother-Ptouch-RollFedMedia.xml (+0/-13)
printer/Brother-QL-500.xml (+9/-0)
printer/Brother-QL-550.xml (+10/-1)
printer/Brother-QL-650TD.xml (+9/-0)
ptouch-driver-foomatic.spec.in (+0/-1)
rastertoptch.c (+103/-60)
To merge this branch: bzr merge lp:~philpem/ubuntu/utopic/ptouch-driver/ptouch-driver-fixup
Reviewer Review Type Date Requested Status
Till Kamppeter Approve
Ubuntu Development Team Pending
Review via email: mp+255895@code.launchpad.net

Description of the change

Following up from discussion at https://code.launchpad.net/~philpem/ubuntu/utopic/ptouch-driver/fix-for-1342979/+merge/255190

This patch fixes a number of issues with the ptouch-driver printer driver:

  * Update the driver to use current CUPS APIs (not the older deprecated ones)
    and fix some compile-time warnings
  * Use the PPD API to get the value of the MediaType flag, which is used to
    pass the "Roll-fed media" flag into the driver
  * Correct the margins for QL-series P-Touch paper-label printers - these
    have a fixed 3mm margin (see the command spec) while the PT-series
    laminated plastic label printers have no appreciable margins.
  * Correct the format of the "ESC i z" (Print Information) command to match
    what is specified in the P-touch 500 raster command spec. Notably set the
    "passed parameter valid" bits, and send valid values for die-cut labels
    and continuous paper rolls.
  * Send the "ESC i d" (Set Margin) command for QL series printers. This is
    required by the command spec. The margin is set to 3mm for continuous
    paper and zero for die-cut (see the command spec)
  * Fix an issue with margins in the driver (disable blank-line padding). This
    was partly responsible for the "excess paper feed" issue.
  * Suppress the spurious "ESC i z" which was sent with incorrect contents at
    the start of the job.
  * Fix the Enable Cutter command.
  * Send 350 bytes of NULL/no-op commands at the start of the job. This allows
    the driver to recover the printer into a known state if communication was
    interrupted mid-transfer. This is recommended in the command spec.
  * Remove the "determined by page size" option from "Roll-fed media" as this
    no longer works.
  * Remove the "Advance Media" option, as this allowed users to configure the
    driver to generate print control codes which are illegal per the Brother
    documentation. This is now fixed at "Advance at end of job" (send a Form
    Feed at the end of every page, except the last which has an Eject
    command instead).
  * Merge in the changes formerly provided by send-esc-i-A-for-QL-only.patch.

To post a comment you must log in.
Revision history for this message
Till Kamppeter (till-kamppeter) wrote :

Generally it looks OK, but we need to consider the following:

1. GIT repositories of a package (or any changes on it) should be done always with the quilt patches not applied and without .pc directory, to avoid redundancies and to make it easy to modify a patch without needing to modify a whole bunch of other files along with it.

2. Such a lot of changes should go upstream and not kept as distro patches to the eternity. If the upstream maintainer has disappeared, I suggest that you overtake upstream maintainership.

Revision history for this message
Till Kamppeter (till-kamppeter) wrote :

More remarks:

- You need to update the debian/changelog file. It should mention what you actually have changed/fixed. It seems to be unchanged from your previous merge proposal.

- 80 % of your patch are changes in the .pc directory and so redundant. also every change in your new patches appears a second time as change in the upstream source code. Please first clone the original GIT of the current package, "quilt pop -a", remove or exclude .pc/ and then recommit, after that do your changes and commit under the same conditions (patches unapplied and no .pc/ directory), propose the resulting repo for merge then.

Revision history for this message
Till Kamppeter (till-kamppeter) wrote :

I ave accepted your changes by replacing debian/patches/send-esc-i-A-for-QL-only.patch by your debian/patches/philpem-ptouch-fixes in the Ubuntu package and adding the description of your patch to debian/changelog. The resulting package I have uploaded as ptouch-driver 1.3-8ubuntu1 to Vivid. This should make up exactly the same package as your merge proposal. So I am closing this thread.

Thanks a lot for all the fixes. Make sure they get upstream as I told you earlier.

review: Approve
Revision history for this message
Phil Pemberton (philpem) wrote :

Thanks, Till!

The upstream developer is no longer maintaining the driver -- he says he no longer has time, which is fair enough. So I guess my Mercurial repository is the "latest" at the moment, and probably counts as a fork. I'll maintain it for my own use, but I don't intend to go any further with it. I certainly don't intend to, say, start buying P-touch printers and add support for them. I guess what I'm trying to say is, at the moment, it's good enough for me.

As for cloning the current Git repo - this version was done from the version in Bazaar, which may have had the existing patches already applied. Though that was after I'd run a build... perhaps I was misinterpreting what I saw. In any case, point noted. Committing patched source files did seem weird to me.

It'd be nice to see this fix make it into Utopic too (I guess that would be a backport?), though if that's not possible I'll probably take the package from Vivid and build it in a PPA for my own use.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.pc/applied-patches'
2--- .pc/applied-patches 2014-03-06 16:23:54 +0000
3+++ .pc/applied-patches 2015-04-10 21:18:54 +0000
4@@ -1,2 +1,2 @@
5 foomatic-data-fixes.patch
6-send-esc-i-A-for-QL-only.patch
7+philpem-ptouch-fixes
8
9=== added file '.pc/foomatic-data-fixes.patch/.timestamp'
10=== added directory '.pc/philpem-ptouch-fixes'
11=== added file '.pc/philpem-ptouch-fixes/.timestamp'
12=== added file '.pc/philpem-ptouch-fixes/Makefile.am'
13--- .pc/philpem-ptouch-fixes/Makefile.am 1970-01-01 00:00:00 +0000
14+++ .pc/philpem-ptouch-fixes/Makefile.am 2015-04-10 21:18:54 +0000
15@@ -0,0 +1,91 @@
16+## Process this file with automake to produce Makefile.in
17+## Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
18+##
19+## This file is part of ptouch-driver.
20+##
21+## ptouch-driver is free software; you can redistribute it and/or modify
22+## it under the terms of the GNU General Public License as published by
23+## the Free Software Foundation; either version 2 of the License, or (at
24+## your option) any later version.
25+##
26+## ptouch-driver is distributed in the hope that it will be useful, but
27+## WITHOUT ANY WARRANTY; without even the implied warranty of
28+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29+## General Public License for more details.
30+##
31+## You should have received a copy of the GNU General Public License
32+## along with ptouch-driver; if not, write to the Free Software
33+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
34+## USA
35+
36+execfilterdir = $(libdir)/cups/filter
37+execfilter_PROGRAMS = rastertoptch
38+rastertoptch_CPPFLAGS = -D_GNU_SOURCE
39+
40+foomaticdbdir = $(datadir)/foomatic/db/source
41+nobase_dist_foomaticdb_DATA = driver/ptouch.xml \
42+ printer/Brother-QL-500.xml \
43+ printer/Brother-QL-550.xml \
44+ printer/Brother-QL-650TD.xml \
45+ printer/Brother-PT-PC.xml \
46+ printer/Brother-PT-18R.xml \
47+ printer/Brother-PT-1500PC.xml \
48+ printer/Brother-PT-1950VP.xml \
49+ printer/Brother-PT-1950.xml \
50+ printer/Brother-PT-1960.xml \
51+ printer/Brother-PT-2300.xml \
52+ printer/Brother-PT-2420PC.xml \
53+ printer/Brother-PT-2450DX.xml \
54+ printer/Brother-PT-2500PC.xml \
55+ printer/Brother-PT-2600.xml \
56+ printer/Brother-PT-2610.xml \
57+ printer/Brother-PT-3600.xml \
58+ printer/Brother-PT-550A.xml \
59+ printer/Brother-PT-9200DX.xml \
60+ printer/Brother-PT-9200PC.xml \
61+ printer/Brother-PT-9400.xml \
62+ printer/Brother-PT-9500PC.xml \
63+ printer/Brother-PT-9600.xml \
64+ opt/Brother-Ptouch-AdvanceDistance.xml \
65+ opt/Brother-Ptouch-AdvanceMedia.xml \
66+ opt/Brother-Ptouch-Align.xml \
67+ opt/Brother-Ptouch-BytesPerLine.xml \
68+ opt/Brother-Ptouch-ConcatPages.xml \
69+ opt/Brother-Ptouch-CutMark.xml \
70+ opt/Brother-Ptouch-CutMedia.xml \
71+ opt/Brother-Ptouch-HalfCut.xml \
72+ opt/Brother-Ptouch-SoftwareMirror.xml \
73+ opt/Brother-Ptouch-LabelPreamble.xml \
74+ opt/Brother-Ptouch-MirrorPrint.xml \
75+ opt/Brother-Ptouch-NegativePrint.xml \
76+ opt/Brother-Ptouch-PageSize.xml \
77+ opt/Brother-Ptouch-PixelTransfer.xml \
78+ opt/Brother-Ptouch-PrintDensity.xml \
79+ opt/Brother-Ptouch-PrintQuality.xml \
80+ opt/Brother-Ptouch-Resolution.xml \
81+ opt/Brother-Ptouch-RollFedMedia.xml \
82+ opt/Brother-Ptouch-TransferMode.xml
83+
84+EXTRA_DIST = Doxyfile $(PACKAGE).spec.in \
85+ $(PACKAGE)-foomatic.spec.in
86+
87+RPMBUILD = rpmbuild -ba
88+RPMSOURCESDIR = $(HOME)/src/SOURCES
89+
90+dist-rpm: $(RPMSOURCESDIR)/$(distdir).tar.gz \
91+ $(PACKAGE).spec $(PACKAGE)-foomatic.spec
92+ $(RPMBUILD) $(PACKAGE).spec
93+ $(RPMBUILD) $(PACKAGE)-foomatic.spec
94+
95+$(RPMSOURCESDIR)/$(distdir).tar.gz: $(distdir).tar.gz
96+ cp $< $@
97+
98+%.spec: $(srcdir)/%.spec.in $(top_builddir)/config.status
99+ @case '$?' in \
100+ *config.status*) \
101+ echo ' $(SHELL) ./config.status'; \
102+ $(SHELL) ./config.status;; \
103+ *) \
104+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
105+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
106+ esac;
107
108=== added directory '.pc/philpem-ptouch-fixes/opt'
109=== added file '.pc/philpem-ptouch-fixes/opt/Brother-Ptouch-AdvanceMedia.xml'
110--- .pc/philpem-ptouch-fixes/opt/Brother-Ptouch-AdvanceMedia.xml 1970-01-01 00:00:00 +0000
111+++ .pc/philpem-ptouch-fixes/opt/Brother-Ptouch-AdvanceMedia.xml 2015-04-10 21:18:54 +0000
112@@ -0,0 +1,84 @@
113+<!--
114+Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
115+
116+This file is part of ptouch-driver.
117+
118+ptouch-driver is free software; you can redistribute it and/or modify
119+it under the terms of the GNU General Public License as published by
120+the Free Software Foundation; either version 2 of the License, or (at
121+your option) any later version.
122+
123+ptouch-driver is distributed in the hope that it will be useful, but
124+WITHOUT ANY WARRANTY; without even the implied warranty of
125+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
126+General Public License for more details.
127+
128+You should have received a copy of the GNU General Public License
129+along with ptouch-driver; if not, write to the Free Software
130+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
131+USA
132+-->
133+<option type='enum' id='Brother-Ptouch-AdvanceMedia'>
134+ <!-- A multilingual <comments> block can appear here, too;
135+ it should be treated as documentation for the user. -->
136+ <arg_longname>
137+ <en>Advance Media</en>
138+ </arg_longname>
139+ <arg_shortname>
140+ <en>AdvanceMedia</en><!-- backends only know <en> shortnames! -->
141+ </arg_shortname>
142+ <arg_execution>
143+ <arg_group>Finishing</arg_group>
144+ <arg_order>110</arg_order>
145+ <arg_spot>A</arg_spot>
146+ <arg_postscript />
147+ <arg_proto>&lt;&lt;/AdvanceMedia %s&gt;&gt;setpagedevice</arg_proto>
148+ </arg_execution>
149+ <constraints>
150+ <constraint sense='true'>
151+ <driver>ptouch</driver>
152+ <arg_defval>ev/Off</arg_defval>
153+ </constraint>
154+ </constraints>
155+ <enum_vals>
156+ <enum_val id="ev/Off">
157+ <ev_longname>
158+ <en>Do not advance the tape</en>
159+ </ev_longname>
160+ <!-- A multilingual <comments> block can appear here, too;
161+ it should be treated as documentation for the user. -->
162+ <ev_shortname>
163+ <en>Off</en>
164+ <!-- Until someone tells me how to learn the user locale in
165+ backends, the shortname must be monolingual in <en>! -->
166+ </ev_shortname>
167+ <ev_driverval>0</ev_driverval>
168+ </enum_val>
169+ <enum_val id="ev/LabelEnd">
170+ <ev_longname>
171+ <en>Advance the tape after each label</en>
172+ </ev_longname>
173+ <!-- A multilingual <comments> block can appear here, too;
174+ it should be treated as documentation for the user. -->
175+ <ev_shortname>
176+ <en>LabelEnd</en>
177+ <!-- Until someone tells me how to learn the user locale in
178+ backends, the shortname must be monolingual in <en>! -->
179+ </ev_shortname>
180+ <ev_driverval>4</ev_driverval>
181+ </enum_val>
182+ <enum_val id="ev/JobEnd">
183+ <ev_longname>
184+ <en>Advance the tape at the end of the job</en>
185+ </ev_longname>
186+ <!-- A multilingual <comments> block can appear here, too;
187+ it should be treated as documentation for the user. -->
188+ <ev_shortname>
189+ <en>JobEnd</en>
190+ <!-- Until someone tells me how to learn the user locale in
191+ backends, the shortname must be monolingual in <en>! -->
192+ </ev_shortname>
193+ <ev_driverval>2</ev_driverval>
194+ </enum_val>
195+ </enum_vals>
196+</option>
197
198=== added file '.pc/philpem-ptouch-fixes/opt/Brother-Ptouch-RollFedMedia.xml'
199--- .pc/philpem-ptouch-fixes/opt/Brother-Ptouch-RollFedMedia.xml 1970-01-01 00:00:00 +0000
200+++ .pc/philpem-ptouch-fixes/opt/Brother-Ptouch-RollFedMedia.xml 2015-04-10 21:18:54 +0000
201@@ -0,0 +1,84 @@
202+<!--
203+Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
204+
205+This file is part of ptouch-driver.
206+
207+ptouch-driver is free software; you can redistribute it and/or modify
208+it under the terms of the GNU General Public License as published by
209+the Free Software Foundation; either version 2 of the License, or (at
210+your option) any later version.
211+
212+ptouch-driver is distributed in the hope that it will be useful, but
213+WITHOUT ANY WARRANTY; without even the implied warranty of
214+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
215+General Public License for more details.
216+
217+You should have received a copy of the GNU General Public License
218+along with ptouch-driver; if not, write to the Free Software
219+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
220+USA
221+-->
222+<option type="enum" id="opt/Brother-Ptouch-RollFedMedia">
223+ <!-- A multilingual <comments> block can appear here, too;
224+ it should be treated as documentation for the user. -->
225+ <arg_longname>
226+ <en>Roll Fed Media</en>
227+ </arg_longname>
228+ <arg_shortname>
229+ <en>RollFedMedia</en><!-- backends only know <en> shortnames! -->
230+ </arg_shortname>
231+ <arg_execution>
232+ <arg_group>General</arg_group>
233+ <arg_order>110</arg_order>
234+ <arg_spot>A</arg_spot>
235+ <arg_postscript />
236+ <arg_proto>%s</arg_proto>
237+ </arg_execution>
238+ <constraints>
239+ <constraint sense='true'>
240+ <driver>ptouch</driver>
241+ <arg_defval>ev/Auto</arg_defval>
242+ </constraint>
243+ </constraints>
244+ <enum_vals>
245+ <enum_val id="ev/Auto">
246+ <ev_longname>
247+ <en>Automatically determined by page size</en>
248+ </ev_longname>
249+ <!-- A multilingual <comments> block can appear here, too;
250+ it should be treated as documentation for the user. -->
251+ <ev_shortname>
252+ <en>Auto</en>
253+ <!-- Until someone tells me how to learn the user locale in
254+ backends, the shortname must be monolingual in <en>! -->
255+ </ev_shortname>
256+ <ev_driverval></ev_driverval>
257+ </enum_val>
258+ <enum_val id="ev/Roll">
259+ <ev_longname>
260+ <en>Continuous roll</en>
261+ </ev_longname>
262+ <!-- A multilingual <comments> block can appear here, too;
263+ it should be treated as documentation for the user. -->
264+ <ev_shortname>
265+ <en>Roll</en>
266+ <!-- Until someone tells me how to learn the user locale in
267+ backends, the shortname must be monolingual in <en>! -->
268+ </ev_shortname>
269+ <ev_driverval>&lt;&lt;/MediaType (roll)&gt;&gt;setpagedevice</ev_driverval>
270+ </enum_val>
271+ <enum_val id="ev/Labels">
272+ <ev_longname>
273+ <en>Labels</en>
274+ </ev_longname>
275+ <!-- A multilingual <comments> block can appear here, too;
276+ it should be treated as documentation for the user. -->
277+ <ev_shortname>
278+ <en>Labels</en>
279+ <!-- Until someone tells me how to learn the user locale in
280+ backends, the shortname must be monolingual in <en>! -->
281+ </ev_shortname>
282+ <ev_driverval>&lt;&lt;/MediaType (labels)&gt;&gt;setpagedevice</ev_driverval>
283+ </enum_val>
284+ </enum_vals>
285+</option>
286
287=== added directory '.pc/philpem-ptouch-fixes/printer'
288=== added file '.pc/philpem-ptouch-fixes/printer/Brother-QL-500.xml'
289--- .pc/philpem-ptouch-fixes/printer/Brother-QL-500.xml 1970-01-01 00:00:00 +0000
290+++ .pc/philpem-ptouch-fixes/printer/Brother-QL-500.xml 2015-04-10 21:18:54 +0000
291@@ -0,0 +1,97 @@
292+<!--
293+Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
294+
295+This file is part of ptouch-driver.
296+
297+ptouch-driver is free software; you can redistribute it and/or modify
298+it under the terms of the GNU General Public License as published by
299+the Free Software Foundation; either version 2 of the License, or (at
300+your option) any later version.
301+
302+ptouch-driver is distributed in the hope that it will be useful, but
303+WITHOUT ANY WARRANTY; without even the implied warranty of
304+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
305+General Public License for more details.
306+
307+You should have received a copy of the GNU General Public License
308+along with ptouch-driver; if not, write to the Free Software
309+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
310+USA
311+-->
312+<printer id="printer/Brother-QL-500">
313+ <make>Brother</make>
314+ <model>QL-500</model>
315+ <pcmodel>BRQ500</pcmodel>
316+ <mechanism>
317+ <thermal/>
318+ <!--not "color"-->
319+ <resolution>
320+ <dpi>
321+ <x>300</x>
322+ <y>300</y>
323+ </dpi>
324+ </resolution>
325+ <consumables>
326+ <comments>
327+ <en>
328+ Special &quot;DK&quot; adhesive labels or adhesive tape thermal paper.
329+ No ink or ribbons needed.
330+ Die Cut Standard Address Labels 29mm x 90mm, 400 Labels - $7.99
331+ Die Cut Shipping Labels 62mm x 100mm, 300 Labels - $13.99
332+ Die Cut File Folder Labels 17mm x 87mm, 300 labels - $6.99
333+ Multipurpose Die Cut Labels 17mm x 54mm, 400 Labels - $7.99
334+ CD/DVD Film Labels 58mm x 58mm, 100 Labels - $14.99
335+ Large Die Cut Address Labels 38mm x 90mm, 400 Labels/Roll - $10.99
336+ Small Address Label 29mm x 62mm, 800 Labels - $13.99
337+ Clear Continuous Film Roll 62mm x 15.24m, Clear - $44.99
338+ White Continuous Film Roll 62mm x 30.48m, White - $13.99
339+ White Continuous Film Roll 29mm x 30.48m, White - $8.99
340+ White Continuous Film Roll 29mm x 15.24m, White - $15.99
341+ White Continuous Film Roll 62mm x 15.24m, White - $30.99
342+ White Continuous Film Roll 12mm x 30.48m, White - $7.99
343+ Yellow Continuous Film Roll 62mm x 15.24m, Yellow - $44.99
344+ Cutter Unit, 2 pcs
345+ Cleaning Sheets, 10 sheets
346+ </en>
347+ </comments>
348+ <partno>DK-11201</partno>
349+ <partno>DK-11202</partno>
350+ <partno>DK-11203</partno>
351+ <partno>DK-11204</partno>
352+ <partno>DK-11207</partno>
353+ <partno>DK-11208</partno>
354+ <partno>DK-11209</partno>
355+ <partno>DK-22113</partno>
356+ <partno>DK-22205</partno>
357+ <partno>DK-22210</partno>
358+ <partno>DK-22211</partno>
359+ <partno>DK-22212</partno>
360+ <partno>DK-22214</partno>
361+ <partno>DK-22606</partno>
362+ <partno>DKBU99</partno>
363+ <partno>DKCL99</partno>
364+ </consumables>
365+ </mechanism>
366+ <url>http://www.brother.co.uk/cms.cfm/s_page/55570/s_level/17510/s_product/QL500</url>
367+ <lang>
368+ <proprietary />
369+ </lang>
370+ <autodetect>
371+ <general>
372+ <ieee1284>MFG:Brother;CMD:PT-CBP;MDL:QL-500;CLS:PRINTER;</ieee1284>
373+ <commandset>PT-CBP</commandset>
374+ <description>Brother QL-500</description>
375+ <manufacturer>Brother</manufacturer>
376+ <model>QL-500</model>
377+ </general>
378+ </autodetect>
379+ <functionality>B</functionality>
380+ <driver>ptouch</driver>
381+ <unverified />
382+ <!--no "contrib_url"-->
383+ <comments>
384+ <en>
385+ Prints 3 inches per second.
386+ </en>
387+ </comments>
388+</printer>
389
390=== added file '.pc/philpem-ptouch-fixes/printer/Brother-QL-550.xml'
391--- .pc/philpem-ptouch-fixes/printer/Brother-QL-550.xml 1970-01-01 00:00:00 +0000
392+++ .pc/philpem-ptouch-fixes/printer/Brother-QL-550.xml 2015-04-10 21:18:54 +0000
393@@ -0,0 +1,97 @@
394+<!--
395+Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
396+
397+This file is part of ptouch-driver.
398+
399+ptouch-driver is free software; you can redistribute it and/or modify
400+it under the terms of the GNU General Public License as published by
401+the Free Software Foundation; either version 2 of the License, or (at
402+your option) any later version.
403+
404+ptouch-driver is distributed in the hope that it will be useful, but
405+WITHOUT ANY WARRANTY; without even the implied warranty of
406+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
407+General Public License for more details.
408+
409+You should have received a copy of the GNU General Public License
410+along with ptouch-driver; if not, write to the Free Software
411+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
412+USA
413+-->
414+<printer id="printer/Brother-QL-550">
415+ <make>Brother</make>
416+ <model>QL-550</model>
417+ <pcmodel>BRQ550</pcmodel>
418+ <mechanism>
419+ <thermal/>
420+ <!--not "color"-->
421+ <resolution>
422+ <dpi>
423+ <x>300</x>
424+ <y>300</y>
425+ </dpi>
426+ </resolution>
427+ <consumables>
428+ <comments>
429+ <en>
430+ Special &quot;DK&quot; adhesive labels or adhesive tape thermal paper.
431+ No ink or ribbons needed.
432+ Die Cut Standard Address Labels 29mm x 90mm, 400 Labels - $7.99
433+ Die Cut Shipping Labels 62mm x 100mm, 300 Labels - $13.99
434+ Die Cut File Folder Labels 17mm x 87mm, 300 labels - $6.99
435+ Multipurpose Die Cut Labels 17mm x 54mm, 400 Labels - $7.99
436+ CD/DVD Film Labels 58mm x 58mm, 100 Labels - $14.99
437+ Large Die Cut Address Labels 38mm x 90mm, 400 Labels/Roll - $10.99
438+ Small Address Label 29mm x 62mm, 800 Labels - $13.99
439+ Clear Continuous Film Roll 62mm x 15.24m, Clear - $44.99
440+ White Continuous Film Roll 62mm x 30.48m, White - $13.99
441+ White Continuous Film Roll 29mm x 30.48m, White - $8.99
442+ White Continuous Film Roll 29mm x 15.24m, White - $15.99
443+ White Continuous Film Roll 62mm x 15.24m, White - $30.99
444+ White Continuous Film Roll 12mm x 30.48m, White - $7.99
445+ Yellow Continuous Film Roll 62mm x 15.24m, Yellow - $44.99
446+ Cutter Unit, 2 pcs
447+ Cleaning Sheets, 10 sheets
448+ </en>
449+ </comments>
450+ <partno>DK-11201</partno>
451+ <partno>DK-11202</partno>
452+ <partno>DK-11203</partno>
453+ <partno>DK-11204</partno>
454+ <partno>DK-11207</partno>
455+ <partno>DK-11208</partno>
456+ <partno>DK-11209</partno>
457+ <partno>DK-22113</partno>
458+ <partno>DK-22205</partno>
459+ <partno>DK-22210</partno>
460+ <partno>DK-22211</partno>
461+ <partno>DK-22212</partno>
462+ <partno>DK-22214</partno>
463+ <partno>DK-22606</partno>
464+ <partno>DKBU99</partno>
465+ <partno>DKCL99</partno>
466+ </consumables>
467+ </mechanism>
468+ <url>http://www.brother.co.uk/cms.cfm/s_page/55570/s_level/17510/s_product/QL550</url>
469+ <lang>
470+ <proprietary />
471+ </lang>
472+ <autodetect>
473+ <general>
474+ <ieee1284>MFG:Brother;CMD:PT-CBP;MDL:QL-550;CLS:PRINTER;</ieee1284>
475+ <commandset>PT-CBP</commandset>
476+ <description>Brother QL-550</description>
477+ <manufacturer>Brother</manufacturer>
478+ <model>QL-550</model>
479+ </general>
480+ </autodetect>
481+ <functionality>B</functionality>
482+ <driver>ptouch</driver>
483+ <unverified />
484+ <!--no "contrib_url"-->
485+ <comments>
486+ <en>
487+ Prints 3 inches per second.
488+ </en>
489+ </comments>
490+</printer>
491
492=== added file '.pc/philpem-ptouch-fixes/printer/Brother-QL-650TD.xml'
493--- .pc/philpem-ptouch-fixes/printer/Brother-QL-650TD.xml 1970-01-01 00:00:00 +0000
494+++ .pc/philpem-ptouch-fixes/printer/Brother-QL-650TD.xml 2015-04-10 21:18:54 +0000
495@@ -0,0 +1,97 @@
496+<!--
497+Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
498+
499+This file is part of ptouch-driver.
500+
501+ptouch-driver is free software; you can redistribute it and/or modify
502+it under the terms of the GNU General Public License as published by
503+the Free Software Foundation; either version 2 of the License, or (at
504+your option) any later version.
505+
506+ptouch-driver is distributed in the hope that it will be useful, but
507+WITHOUT ANY WARRANTY; without even the implied warranty of
508+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
509+General Public License for more details.
510+
511+You should have received a copy of the GNU General Public License
512+along with ptouch-driver; if not, write to the Free Software
513+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
514+USA
515+-->
516+<printer id="printer/Brother-QL-650TD">
517+ <make>Brother</make>
518+ <model>QL-650TD</model>
519+ <pcmodel>BRQ650</pcmodel>
520+ <mechanism>
521+ <thermal/>
522+ <!--not "color"-->
523+ <resolution>
524+ <dpi>
525+ <x>300</x>
526+ <y>300</y>
527+ </dpi>
528+ </resolution>
529+ <consumables>
530+ <comments>
531+ <en>
532+ Special &quot;DK&quot; adhesive labels or adhesive tape thermal paper.
533+ No ink or ribbons needed.
534+ Die Cut Standard Address Labels 29mm x 90mm, 400 Labels - $7.99
535+ Die Cut Shipping Labels 62mm x 100mm, 300 Labels - $13.99
536+ Die Cut File Folder Labels 17mm x 87mm, 300 labels - $6.99
537+ Multipurpose Die Cut Labels 17mm x 54mm, 400 Labels - $7.99
538+ CD/DVD Film Labels 58mm x 58mm, 100 Labels - $14.99
539+ Large Die Cut Address Labels 38mm x 90mm, 400 Labels/Roll - $10.99
540+ Small Address Label 29mm x 62mm, 800 Labels - $13.99
541+ Clear Continuous Film Roll 62mm x 15.24m, Clear - $44.99
542+ White Continuous Film Roll 62mm x 30.48m, White - $13.99
543+ White Continuous Film Roll 29mm x 30.48m, White - $8.99
544+ White Continuous Film Roll 29mm x 15.24m, White - $15.99
545+ White Continuous Film Roll 62mm x 15.24m, White - $30.99
546+ White Continuous Film Roll 12mm x 30.48m, White - $7.99
547+ Yellow Continuous Film Roll 62mm x 15.24m, Yellow - $44.99
548+ Cutter Unit, 2 pcs
549+ Cleaning Sheets, 10 sheets
550+ </en>
551+ </comments>
552+ <partno>DK-11201</partno>
553+ <partno>DK-11202</partno>
554+ <partno>DK-11203</partno>
555+ <partno>DK-11204</partno>
556+ <partno>DK-11207</partno>
557+ <partno>DK-11208</partno>
558+ <partno>DK-11209</partno>
559+ <partno>DK-22113</partno>
560+ <partno>DK-22205</partno>
561+ <partno>DK-22210</partno>
562+ <partno>DK-22211</partno>
563+ <partno>DK-22212</partno>
564+ <partno>DK-22214</partno>
565+ <partno>DK-22606</partno>
566+ <partno>DKBU99</partno>
567+ <partno>DKCL99</partno>
568+ </consumables>
569+ </mechanism>
570+ <url>http://www.advizia.com/brother/modelDetail.asp?PkgID=386702&amp;User=ptouch&amp;Rnd=785</url>
571+ <lang>
572+ <proprietary />
573+ </lang>
574+ <autodetect>
575+ <general>
576+ <ieee1284>MFG:Brother;CMD:PT-CBP;MDL:QL-650TD;CLS:PRINTER;</ieee1284>
577+ <commandset>PT-CBP</commandset>
578+ <description>Brother QL-650TD</description>
579+ <manufacturer>Brother</manufacturer>
580+ <model>QL-650TD</model>
581+ </general>
582+ </autodetect>
583+ <functionality>B</functionality>
584+ <driver>ptouch</driver>
585+ <unverified />
586+ <!--no "contrib_url"-->
587+ <comments>
588+ <en>
589+ Prints 3 inches per second.
590+ </en>
591+ </comments>
592+</printer>
593
594=== added file '.pc/philpem-ptouch-fixes/ptouch-driver-foomatic.spec.in'
595--- .pc/philpem-ptouch-fixes/ptouch-driver-foomatic.spec.in 1970-01-01 00:00:00 +0000
596+++ .pc/philpem-ptouch-fixes/ptouch-driver-foomatic.spec.in 2015-04-10 21:18:54 +0000
597@@ -0,0 +1,102 @@
598+## -*- RPM-spec -*- file for the ptouch-driver package
599+## Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
600+##
601+## This file is part of ptouch-driver.
602+##
603+## ptouch-driver is free software; you can redistribute it and/or modify
604+## it under the terms of the GNU General Public License as published by
605+## the Free Software Foundation; either version 2 of the License, or (at
606+## your option) any later version.
607+##
608+## ptouch-driver is distributed in the hope that it will be useful, but
609+## WITHOUT ANY WARRANTY; without even the implied warranty of
610+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
611+## General Public License for more details.
612+##
613+## You should have received a copy of the GNU General Public License
614+## along with ptouch-driver; if not, write to the Free Software
615+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
616+## USA
617+Name: ptouch-driver-foomatic
618+Version: @VERSION@
619+Release: 1
620+Summary: Foomatic database data for Brother P-touch label printers
621+
622+Group: System Environment/Libraries
623+License: GPL
624+URL: http://ptouch-driver.sourceforge.net/
625+Source0: ptouch-driver-%{version}.tar.gz
626+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
627+
628+Requires: foomatic ptouch-driver
629+
630+%description
631+The ptouch-driver consists of a CUPS raster filter and foomatic
632+database XML documents for driving the family of Brother P-touch label
633+printers.
634+
635+%prep
636+%setup -q -n ptouch-driver-%{version}
637+
638+%build
639+%configure
640+
641+%install
642+rm -rf $RPM_BUILD_ROOT
643+make install-data DESTDIR=$RPM_BUILD_ROOT
644+
645+%clean
646+rm -rf $RPM_BUILD_ROOT
647+
648+
649+%files
650+%defattr(-,root,root,-)
651+%doc AUTHORS ChangeLog COPYING NEWS README
652+/usr/share/foomatic/db/source/driver/ptouch.xml
653+/usr/share/foomatic/db/source/printer/Brother-PT-1500PC.xml
654+/usr/share/foomatic/db/source/printer/Brother-PT-18R.xml
655+/usr/share/foomatic/db/source/printer/Brother-PT-1950VP.xml
656+/usr/share/foomatic/db/source/printer/Brother-PT-1950.xml
657+/usr/share/foomatic/db/source/printer/Brother-PT-1960.xml
658+/usr/share/foomatic/db/source/printer/Brother-PT-2300.xml
659+/usr/share/foomatic/db/source/printer/Brother-PT-2420PC.xml
660+/usr/share/foomatic/db/source/printer/Brother-PT-2450DX.xml
661+/usr/share/foomatic/db/source/printer/Brother-PT-2500PC.xml
662+/usr/share/foomatic/db/source/printer/Brother-PT-2600.xml
663+/usr/share/foomatic/db/source/printer/Brother-PT-2610.xml
664+/usr/share/foomatic/db/source/printer/Brother-PT-3600.xml
665+/usr/share/foomatic/db/source/printer/Brother-PT-550A.xml
666+/usr/share/foomatic/db/source/printer/Brother-PT-9200DX.xml
667+/usr/share/foomatic/db/source/printer/Brother-PT-9200PC.xml
668+/usr/share/foomatic/db/source/printer/Brother-PT-9400.xml
669+/usr/share/foomatic/db/source/printer/Brother-PT-9500PC.xml
670+/usr/share/foomatic/db/source/printer/Brother-PT-9600.xml
671+/usr/share/foomatic/db/source/printer/Brother-PT-PC.xml
672+/usr/share/foomatic/db/source/printer/Brother-QL-500.xml
673+/usr/share/foomatic/db/source/printer/Brother-QL-550.xml
674+/usr/share/foomatic/db/source/printer/Brother-QL-650TD.xml
675+/usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceDistance.xml
676+/usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceMedia.xml
677+/usr/share/foomatic/db/source/opt/Brother-Ptouch-Align.xml
678+/usr/share/foomatic/db/source/opt/Brother-Ptouch-BytesPerLine.xml
679+/usr/share/foomatic/db/source/opt/Brother-Ptouch-ConcatPages.xml
680+/usr/share/foomatic/db/source/opt/Brother-Ptouch-CutMark.xml
681+/usr/share/foomatic/db/source/opt/Brother-Ptouch-CutMedia.xml
682+/usr/share/foomatic/db/source/opt/Brother-Ptouch-HalfCut.xml
683+/usr/share/foomatic/db/source/opt/Brother-Ptouch-LabelPreamble.xml
684+/usr/share/foomatic/db/source/opt/Brother-Ptouch-MirrorPrint.xml
685+/usr/share/foomatic/db/source/opt/Brother-Ptouch-NegativePrint.xml
686+/usr/share/foomatic/db/source/opt/Brother-Ptouch-PageSize.xml
687+/usr/share/foomatic/db/source/opt/Brother-Ptouch-PixelTransfer.xml
688+/usr/share/foomatic/db/source/opt/Brother-Ptouch-PrintDensity.xml
689+/usr/share/foomatic/db/source/opt/Brother-Ptouch-PrintQuality.xml
690+/usr/share/foomatic/db/source/opt/Brother-Ptouch-Resolution.xml
691+/usr/share/foomatic/db/source/opt/Brother-Ptouch-RollFedMedia.xml
692+/usr/share/foomatic/db/source/opt/Brother-Ptouch-SoftwareMirror.xml
693+/usr/share/foomatic/db/source/opt/Brother-Ptouch-TransferMode.xml
694+
695+
696+%changelog
697+* Mon Jan 30 2006 Arne John Glenstrup <panic@itu.dk> - 0.9-1
698+- Initial build.
699+
700
701=== added file '.pc/philpem-ptouch-fixes/rastertoptch.c'
702--- .pc/philpem-ptouch-fixes/rastertoptch.c 1970-01-01 00:00:00 +0000
703+++ .pc/philpem-ptouch-fixes/rastertoptch.c 2015-04-10 21:18:54 +0000
704@@ -0,0 +1,1590 @@
705+/* rastertoptch is a filter to convert CUPS raster data into a Brother
706+ * P-touch label printer command byte stream.
707+ *
708+ * Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
709+ *
710+ * This file is part of ptouch-driver
711+ *
712+ * ptouch-driver is free software; you can redistribute it and/or modify
713+ * it under the terms of the GNU General Public License as published by
714+ * the Free Software Foundation; either version 2 of the License, or
715+ * (at your option) any later version.
716+ *
717+ * ptouch-driver is distributed in the hope that it will be useful,
718+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
719+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
720+ * GNU General Public License for more details.
721+ *
722+ * You should have received a copy of the GNU General Public License
723+ * along with ptouch-driver; if not, write to the Free Software
724+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
725+ *
726+ *
727+ * Please note: This software is not in any way related to Brother
728+ * Industries, Ltd., except that it is intended for use with their
729+ * products. Any comments to this software should NOT be directed to
730+ * Brother Industries, Ltd.
731+ */
732+
733+/** @file
734+ * This filter processes CUPS raster data, converting it into a byte
735+ * stream on stdout suitable for sending directly to a label printer
736+ * of the Brother P-touch family.
737+ *
738+ * @version 1.2
739+ * @author Arne John Glenstrup <panic@itu.dk>
740+ * @date 2006
741+
742+ * <h2>Invocation</h2>
743+ * The filter is invoked thus:
744+ *
745+ * rastertoptch job user title copies options [filename]
746+ *
747+ * @param printer The name of the printer queue (ignored)
748+ * @param job The numeric job ID (ignored)
749+ * @param user The string from the originating-user-name (ignored)
750+ * @param title The string from the job-name attribute (ignored)
751+ * @param copies The number of copies to be printed (ignored)
752+ * @param options String representations of the job template
753+ * parameters, separated by spaces. Boolean attributes
754+ * are provided as "name" for true values and "noname"
755+ * for false values. All other attributes are provided
756+ * as "name=value" for single-valued attributes and
757+ * "name=value1,value2,...,valueN" for set attributes
758+ * @param filename The request file (if omitted, read from stdin)
759+ *
760+ * Available options (default values in [brackets]):
761+ *
762+ * @param PixelXfer=ULP|RLE|BIP Use uncompressed line printing (ULP),
763+ * run-length encoding (RLE) or bit
764+ * image printing (BIP) when emitting
765+ * pixel data [ULP]
766+ * @param PrintQuality=High|Fast Use high quality or fast printing [High]
767+ * @param HalfCut Perform half-cut (crack & peel) when
768+ * cutting [noHalfCut]
769+ * @param BytesPerLine=N Emit N bytes per line [90]
770+ * @param Align=Right|Center Pixel data alignment on tape [Right]
771+ * @param PrintDensity=1|...|5 Print density level: 1=light, 5=dark
772+ * @param ConcatPages Output all pages in one page [noConcatPages]
773+ * @param RLEMemMax Maximum memory used for RLE buffer [1000000]
774+ * @param SoftwareMirror Make the filter mirror pixel data
775+ * if MirrorPrint is requested [noSoftwareMirror]
776+ * @param LabelPreamble Emit preamble containing print quality,
777+ * roll/label type, tape width, label height,
778+ * and pixel lines [noLabelPreamble]
779+ * @param Debug Emit diagnostic output to stderr [noDebug]
780+ * (only if compiled with DEBUG set)
781+ *
782+ * Information about media type, resolution, mirror print, negative
783+ * print, cut media, advance distance (feed) is extracted from the
784+ * CUPS raster page headers given in the input stream. The MediaType
785+ * page header field can be either "roll" or "labels" for continuous
786+ * tape or pre-cut labels, respectively.
787+ *
788+ * LabelPreamble should usually not be used for the PT series printers.
789+ *
790+ * <h2>Output</h2>
791+ * Each invocation of this filter is one job, containing a number of
792+ * pages, each page containing a number of lines, each line consisting
793+ * of a number of pixel bytes.
794+ *
795+ * Output consists of job-related printer initialisation commands,
796+ * followed by a number of pages, each page consisting of page-related
797+ * commands, followed by raster line data. Each page is followed by a
798+ * finish page or (after the final page) finish job command.
799+ *
800+ * The following printer command language, printer, and tape
801+ * information has been deduced from many sources, but is not official
802+ * Brother documentation and may thus contain errors. Please send any
803+ * corrections based on actual experience with these printers to the
804+ * maintainer.
805+ *
806+ * <h3>Job-related commands</h3>
807+ * <table>
808+ * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
809+ * <tr><td>ESC @ (1b 40)</td>
810+ <td>Initialise</td><td>Clear print buffer</td></tr>
811+ * <tr><td>ESC i D # (1b 69 44 ##)
812+ * <td>Set print density</td>
813+ * <td>bit 0-3: 0=no change, 1-5=density level</td></tr>
814+ * <tr><td>ESC i K # (1b 69 4b ##)
815+ * <td>Set half cut</td>
816+ * <td>bit 2: 0=full cut, 1=half cut</td></tr>
817+ * <tr><td>ESC i R ## (1b 69 52 ##)</td>
818+ * <td>Set transfer mode</td>
819+ * <td>##: ?: 1=?</td></tr>
820+ * <tr><td>M ## (4d ##)</td>
821+ * <td>Set compression</td>
822+ * <td>##: Compression type: 2=RLE</td></tr>
823+ * </table>
824+ *
825+ * <h3>Page-related commands</h3>
826+ * <table>
827+ * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
828+ * <tr><td>ESC i c #1 #2 #3 NUL #4 <br>(1b 63 #1 #2 #3 00 #4)
829+ * <td>Set width & resolution</td>
830+ * <td>360x360DPI: #1 #2 #4 = 0x84 0x00 0x00<br>
831+ * 360x720DPI: #1 #2 #4 = 0x86 0x09 0x01<br>
832+ * #3: Tape width in mm</td></tr>
833+ * <tr><td>ESC i M # <br>(1b 69 4d ##)</td>
834+ * <td>Set mode</td>
835+ * <td>bit 0-4: Feed amount (default=large): 0-7=none, 8-11=small,
836+ * 12-25=medium, 26-31=large<br>
837+ * bit 6: Auto cut/cut mark (default=on): 0=off, 1=on<br>
838+ * bit 7: Mirror print (default=off): 0=off, 1=on.
839+ * (note that it seems that QL devices do not reverse the
840+ * data stream themselves, but rely on the driver doing
841+ * it!)</td></tr>
842+ * <tr><td>ESC i z #1 #2 #3 #4 #5 #6 NUL NUL NUL NUL<br>
843+ * (1b 69 7a #1 #2 #3 #4 #5 #6 00 00 00 00)</td>
844+ * <td>Set media & quality</td>
845+ * <td>#1, bit 6: Print quality: 0=fast, 1=high<br>
846+ * #2, bit 0: Media type: 0=continuous roll,
847+ * 1=pre-cut labels<br>
848+ * #3: Tape width in mm<br>
849+ * #4: Label height in mm (0 for continuous roll)<br>
850+ * #5 #6: Page consists of N=#5+256*#6 pixel lines</td></tr>
851+ * <tr><td>ESC i d #1 #2 <br>(1b 69 64 #1 #2)</td>
852+ * <td>Set margin</td>
853+ * <td>Set size of right(?) margin to N=#1+256*#2 pixels</td></tr>
854+ * <tr><td>FF (0c)</td>
855+ * <td>Form feed</td>
856+ * <td>Print buffer data without ejecting.</td></tr>
857+ * <tr><td>SUB (1a)</td>
858+ * <td>Eject</td>
859+ * <td>Print buffer data and ejects.</td></tr>
860+ * </table>
861+ *
862+ * <h3>Line-related commands</h3>
863+ * <table>
864+ * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
865+ * <tr><td>G #1 #2 ...data... <br>(47 #1 #2 ...data...)</td>
866+ * <td>Send raster line</td>
867+ * <td>data consists of
868+ * N=#1+256*#2 bytes of RLE compressed raster data.
869+ * </td></tr>
870+ * <tr><td>Z (5a)</td>
871+ * <td>Advance tape</td><td>Print 1 empty line</td></tr>
872+ * <tr><td>g #1 #2 ...data... <br>(67 #1 #2 ...data...)</td>
873+ * <td>Send raster line</td>
874+ * <td>data consists of
875+ * N=#2 bytes of uncompressed raster data.</td></tr>
876+ * <tr><td>ESC * ' #1 #2 ...data... <br>(1b 2a 27 #1 #2 ...data...)</td>
877+ * <td>Bit image printing (BIP)</td>
878+ * <td>Print N=#1+256*#2 lines of 24 pixels; data consists of 3*N
879+ * bytes</td></tr>
880+ * </table>
881+ *
882+ * <h3>Compressed-data-related commands (RLE)</h3>
883+ * <table>
884+ * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
885+ * <tr><td>#1 ...data...</td>
886+ * <td>#1 >= 0: Print uncompressed</td>
887+ * <td>data consists of 1+#1 uncompressed bytes</td></tr>
888+ * <tr><td>#1 #2</td>
889+ * <td>#1 < 0: Print compressed</td>
890+ * <td>#2 should be printed 1-#1 times</td></tr>
891+ * </table>
892+ * #1 is represented as a 2-complement signed integer.
893+ *
894+ * <h2>Printer model characteristics</h2>
895+ * The following table lists for each model what kind of cutter it has
896+ * (manual, auto, half cut), what kind of pixel data transfer mode it
897+ * requires, its resolution, number of print head pixels, number of
898+ * bytes of pixel data that must be transmitted per line (regardless
899+ * of actual tape width!), and what kinds of tape it can take.
900+ *
901+ * For PC models, pixel data must be centered, so narrow tapes require
902+ * padding raster data with zero bits on each side. For QL models,
903+ * labels are left-aligned, so pixel data must be right aligned, so
904+ * narrow tapes require padding raster data with zero bits at the end.
905+ *
906+ * For PC-PT, only the central 24 pixels (= 3,4mm!) can be used for
907+ * pixel-based graphics. It might be possible to print several strips
908+ * of 24 pixels side-by side by issuing CR and line-positioning
909+ * commands. That is currently not supported, let alone attempted,
910+ * with this driver.
911+ *
912+ * <table>
913+ * <tr><th>Model <th>Cutter <th>Xfer<th>DPI<th>Pixels<th>Bytes<th>Tape
914+ * <tr><td>QL-500 <td>manual <td>ULP<td>300<td>720<td>90<td>DK12-62mm
915+ * <tr><td>QL-550 <td>auto <td>ULP<td>300<td>720<td>90<td>DK12-62mm
916+ * <tr><td>QL-650TD <td>auto <td>ULP<td>300<td>720<td>90<td>DK12-62mm
917+ * <tr><td>PT-PC <td>auto <td>BIP<td>180<td>128<td> 3<td>TZ6-24mm
918+ * <tr><td>PT-18R <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-18mm
919+ * <tr><td>PT-550A <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-36mm
920+ * <tr><td>PT-1500PC<td>manual <td>RLE<td>180<td>112<td>14<td>TZ6-24mm
921+ * <tr><td>PT-1950 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-18mm
922+ * <tr><td>PT-1950VP<td>auto <td>RLE<td>180<td>112<td>14<td>TZ6-18mm
923+ * <tr><td>PT-1960 <td>auto <td>RLE<td>180<td> 96<td>12<td>TZ6-18mm
924+ * <tr><td>PT-2300 <td>auto <td>RLE<td>180<td>112<td>14<td>TZ6-18mm
925+ * <tr><td>PT-2420PC<td>manual <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
926+ * <tr><td>PT-2450DX<td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
927+ * <tr><td>PT-2500PC<td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
928+ * <tr><td>PT-2600 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ,AV6-24mm
929+ * <tr><td>PT-2610 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ,AV6-24mm
930+ * <tr><td>PT-3600 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ,AV6-36mm
931+ * <tr><td>PT-9200DX<td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
932+ * <tr><td>PT-9200PC<td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
933+ * <tr><td>PT-9400 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
934+ * <tr><td>PT-9500PC<td>auto/half<td>RLE<td>360<br>
935+ 360x720<td>384<td>48<td>TZ,AV6-36mm
936+ * <tr><td>PT-9600 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ,AV6-36mm
937+ * </table>
938+ *
939+ * <h2>Tape characteristics</h2>
940+ * <table>
941+ * <tr><th>Tape width
942+ * <th colspan=2>Print area <th>Margins</th><th>DPI</th></tr>
943+ * <tr><td>62mm<td>61.0mm<td>720pixels</td><td>0.5mm</td><td>300</td></tr>
944+ * <tr><td>36mm<td>27.1mm<td>384pixels</td><td>4.5mm</td><td>360</td></tr>
945+ * <tr><td>24mm<td>18.0mm<td>128pixels</td><td>3mm</td><td>180</td></tr>
946+ * <tr><td>18mm<td>12.0mm<td> 85pixels</td><td>3mm</td><td>180</td></tr>
947+ * <tr><td>12mm<td> 8.0mm<td> 57pixels</td><td>2mm</td><td>180</td></tr>
948+ * <tr><td> 9mm<td> 6.9mm<td> 49pixels</td><td>1mm</td><td>180</td></tr>
949+ * <tr><td> 6mm<td> 3.9mm<td> 28pixels</td><td>1mm</td><td>180</td></tr>
950+ * </table>
951+ *
952+ * <h2>Notes</h2>
953+ * - Pixels bytes sent are printed from right to left, with bit 7
954+ * rightmost!
955+ * - Bit image printing (BIP) using "ESC * ' #1 #2 ...data..."
956+ * probably only works for the PT-PC model.
957+ * - QL Printer documentation might state that the print area is less
958+ * than 61mm, which is probably to ensure that printed pixels stay
959+ * within the tape even if it is not precisely positioned. The
960+ * print head really IS 720 pixels.
961+ */
962+/** Default pixel transfer method */
963+#define PIXEL_XFER_DEFAULT RLE
964+/** Default print quality */
965+#define PRINT_QUALITY_HIGH_DEFAULT true
966+/** Default half cut mode */
967+#define HALF_CUT_DEFAULT false
968+/** Maximum number of bytes per line */
969+#define BYTES_PER_LINE_MAX 255 /* cf. ULP_emit_line */
970+/** Default number of bytes per line */
971+#define BYTES_PER_LINE_DEFAULT 90
972+/** Default pixel data alignment on narrow tapes */
973+#define ALIGN_DEFAULT RIGHT
974+/** Maximum print density value */
975+#define PRINT_DENSITY_MAX 5
976+/** Default print density value (1: light, ..., 5:dark, 0: no change) */
977+#define PRINT_DENSITY_DEFAULT 0
978+/** Transfer mode default ??? (-1 = don't set) */
979+#define TRANSFER_MODE_DEFAULT -1
980+/** Driver pixel data mirroring default */
981+#define SOFTWARE_MIRROR_DEFAULT false
982+/** Label preamble emitting default */
983+#define LABEL_PREAMBLE_DEFAULT false
984+/** Interlabel margin removal default */
985+#define CONCAT_PAGES_DEFAULT false
986+/** RLE buffer maximum memory usage */
987+#define RLE_ALLOC_MAX_DEFAULT 1000000
988+/** Mirror printing default */
989+#define MIRROR_DEFAULT false
990+/** Negative printing default */
991+#define NEGATIVE_DEFAULT false
992+/** Cut media mode default */
993+#define CUT_MEDIA_DEFAULT CUPS_CUT_NONE
994+/** Roll fed media default */
995+#define ROLL_FED_MEDIA_DEFAULT true
996+/** Device resolution default in DPI */
997+#define RESOLUTION_DEFAULT { 300, 300 }
998+/** Page size default in PostScript points */
999+#define PAGE_SIZE_DEFAULT { 176, 142 } /* 62x50mm */
1000+/** Image size default in pixels */
1001+#define IMAGE_HEIGHT_DEFAULT 0
1002+/** Feed amount default */
1003+#define FEED_DEFAULT 0
1004+/** When to perform feed default */
1005+#define PERFORM_FEED_DEFAULT CUPS_ADVANCE_NONE
1006+
1007+#include <config.h>
1008+#include <stdio.h>
1009+#include <unistd.h>
1010+#include <limits.h>
1011+#include <stdlib.h>
1012+#include <string.h>
1013+#include <errno.h>
1014+#include <fcntl.h>
1015+#include <signal.h>
1016+#include <math.h>
1017+#include <cups/raster.h>
1018+#include <cups/cups.h>
1019+
1020+#if STDC_HEADERS
1021+# include <string.h>
1022+#else
1023+# if !HAVE_MEMCPY
1024+# define memcpy(d, s, n) bcopy ((s), (d), (n))
1025+# endif
1026+#endif
1027+#if HAVE_STDBOOL_H
1028+# include <stdbool.h>
1029+#else
1030+# if ! HAVE__BOOL
1031+# ifdef __cplusplus
1032+typedef bool _Bool;
1033+# else
1034+typedef unsigned char _Bool;
1035+# endif
1036+# endif
1037+# define bool _Bool
1038+# define false 0
1039+# define true 1
1040+# define __bool_true_false_are_defined 1
1041+#endif
1042+
1043+
1044+
1045+#ifdef DEBUG
1046+#include <sys/times.h>
1047+/** Debug flag */
1048+int debug = 0;
1049+/** Number of emitted lines */
1050+unsigned emitted_lines = 0;
1051+#endif
1052+
1053+/** Length of a PostScript point in mm */
1054+#define MM_PER_PT (25.4 / 72.0)
1055+/** Printer code: Eject */
1056+#define PTC_EJECT 0x1a
1057+/** Printer code: Form feed */
1058+#define PTC_FORMFEED 0x0c
1059+
1060+/** ASCII escape value */
1061+#define ESC 0x1b
1062+
1063+/**
1064+ * Pixel transfer mode type.
1065+ */
1066+typedef enum {
1067+ ULP, /**< Uncompressed line printing */
1068+ RLE, /**< Run-length encoding */
1069+ BIP, /**< Bit image printing */
1070+} xfer_t;
1071+
1072+/**
1073+ * Pixel data alignment type.
1074+ */
1075+typedef enum {RIGHT, CENTER} align_t;
1076+
1077+/** Flag signalling whether any errors were encountered. */
1078+int error_occurred;
1079+
1080+/** CUPS Raster line buffer. */
1081+unsigned char* buffer;
1082+/** Buffer holding line data to emit to the printer. */
1083+unsigned char* emit_line_buffer;
1084+/** Buffer holding RLE line data to emit to the printer. */
1085+unsigned char* rle_buffer = NULL;
1086+/** Pointer to first free pos in rle_buffer. */
1087+unsigned char* rle_buffer_next = NULL;
1088+/** Size of rle_buffer. */
1089+unsigned long rle_alloced = 0;
1090+/** Number of empty lines (input data only zeros) waiting to be stored */
1091+int empty_lines = 0;
1092+/** Number of pixel lines waiting to be emitted. */
1093+unsigned lines_waiting = 0;
1094+/** Threshold for flushing waiting lines to printer. */
1095+unsigned max_lines_waiting = INT_MAX;
1096+
1097+/** Macro for obtaining integer option values. */
1098+#define OBTAIN_INT_OPTION(name, var, min, max) \
1099+ cups_option \
1100+ = cupsGetOption (name, num_options, cups_options); \
1101+ if (cups_option) { \
1102+ errno = 0; \
1103+ char* rest; \
1104+ long int var = strtol (cups_option, &rest, 0); \
1105+ if (errno || *rest != '\0' || rest == cups_option \
1106+ || var < min || var > max) { \
1107+ fprintf (stderr, "ERROR: " name " '%s', " \
1108+ "must be an integer N, where %ld <= N <= %ld\n", \
1109+ cups_option, (long) min, (long) max); \
1110+ error_occurred = 1; \
1111+ } else \
1112+ options.var = var; \
1113+ }
1114+
1115+/** Macro for obtaining boolean option values. */
1116+#define OBTAIN_BOOL_OPTION(name, var) \
1117+ cups_option \
1118+ = cupsGetOption (name, num_options, cups_options); \
1119+ if (cups_option) options.var = true; \
1120+ cups_option \
1121+ = cupsGetOption ("no"name, num_options, cups_options); \
1122+ if (cups_option) options.var = false; \
1123+
1124+/**
1125+ * Struct type for holding all the job options.
1126+ */
1127+typedef struct {
1128+ xfer_t pixel_xfer; /**< pixel transfer mode */
1129+ cups_bool_t print_quality_high; /**< print quality is high */
1130+ bool half_cut; /**< half cut */
1131+ int bytes_per_line; /**< bytes per line (print head width) */
1132+ align_t align; /**< pixel data alignment */
1133+ int software_mirror; /**< mirror pixel data if mirror printing */
1134+ int print_density; /**< printing density (0=don't change) */
1135+ int xfer_mode; /**< transfer mode ??? */
1136+ int label_preamble; /**< emit ESC i z ... */
1137+ bool concat_pages; /**< remove interlabel margins */
1138+ unsigned long rle_alloc_max; /**< max bytes used for rle_buffer */
1139+} job_options_t;
1140+
1141+/**
1142+ * Struct type for holding current page options.
1143+ */
1144+typedef struct {
1145+ cups_cut_t cut_media; /**< cut media mode */
1146+ cups_bool_t mirror; /**< mirror printing */
1147+ bool roll_fed_media; /**< continuous (not labels) roll media */
1148+ unsigned resolution [2]; /**< horiz & vertical resolution in DPI */
1149+ unsigned page_size [2]; /**< width & height of page in points */
1150+ unsigned image_height; /**< height of page image in pixels */
1151+ unsigned feed; /**< feed size in points */
1152+ cups_adv_t perform_feed; /**< When to feed */
1153+} page_options_t;
1154+
1155+/**
1156+ * Parse options given in command line argument 5.
1157+ * @param argc number of command line arguments plus one
1158+ * @param argv command line arguments
1159+ * @return options, where each option set to its default value if
1160+ * not specified in argv [5]
1161+ */
1162+job_options_t
1163+parse_options (int argc, const char* argv []) {
1164+ job_options_t options = {
1165+ PIXEL_XFER_DEFAULT,
1166+ PRINT_QUALITY_HIGH_DEFAULT,
1167+ HALF_CUT_DEFAULT,
1168+ BYTES_PER_LINE_DEFAULT,
1169+ ALIGN_DEFAULT,
1170+ SOFTWARE_MIRROR_DEFAULT,
1171+ PRINT_DENSITY_DEFAULT,
1172+ TRANSFER_MODE_DEFAULT,
1173+ LABEL_PREAMBLE_DEFAULT,
1174+ CONCAT_PAGES_DEFAULT,
1175+ RLE_ALLOC_MAX_DEFAULT,
1176+ };
1177+ if (argc < 6) return options;
1178+ int num_options = 0;
1179+ cups_option_t* cups_options = NULL;
1180+ num_options
1181+ = cupsParseOptions (argv [5], num_options, &cups_options);
1182+ const char* cups_option
1183+ = cupsGetOption ("PixelXfer", num_options, cups_options);
1184+ if (cups_option) {
1185+ if (strcasecmp (cups_option, "ULP") == 0)
1186+ options.pixel_xfer = ULP;
1187+ else if (strcasecmp (cups_option, "RLE") == 0)
1188+ options.pixel_xfer = RLE;
1189+ else if (strcasecmp (cups_option, "BIP") == 0)
1190+ options.pixel_xfer = BIP;
1191+ else {
1192+ fprintf (stderr, "ERROR: Unknown PicelXfer '%s', "
1193+ "must be RLE, BIP or ULP\n", cups_option);
1194+ error_occurred = 1;
1195+ }
1196+ }
1197+ cups_option
1198+ = cupsGetOption ("PrintQuality", num_options, cups_options);
1199+ if (cups_option) {
1200+ if (strcasecmp (cups_option, "High") == 0)
1201+ options.print_quality_high = true;
1202+ else if (strcasecmp (cups_option, "Fast") == 0)
1203+ options.print_quality_high = false;
1204+ else {
1205+ fprintf (stderr, "ERROR: Unknown PrintQuality '%s', "
1206+ "must be High or Fast\n", cups_option);
1207+ error_occurred = 1;
1208+ }
1209+ }
1210+ OBTAIN_BOOL_OPTION ("HalfCut", half_cut);
1211+ OBTAIN_INT_OPTION ("BytesPerLine", bytes_per_line,
1212+ 1, BYTES_PER_LINE_MAX);
1213+ cups_option
1214+ = cupsGetOption ("Align", num_options, cups_options);
1215+ if (cups_option) {
1216+ if (strcasecmp (cups_option, "Right") == 0)
1217+ options.align = RIGHT;
1218+ else if (strcasecmp (cups_option, "Center") == 0)
1219+ options.align = CENTER;
1220+ else {
1221+ fprintf (stderr, "ERROR: Unknown Align '%s', "
1222+ "must be Right or Center\n", cups_option);
1223+ error_occurred = 1;
1224+ }
1225+ }
1226+ OBTAIN_INT_OPTION ("PrintDensity", print_density,
1227+ 0, PRINT_DENSITY_MAX);
1228+ OBTAIN_BOOL_OPTION ("ConcatPages", concat_pages);
1229+ OBTAIN_INT_OPTION ("RLEMemMax", rle_alloc_max, 0, LONG_MAX);
1230+ OBTAIN_INT_OPTION ("TransferMode", xfer_mode, 0, 255);
1231+ OBTAIN_BOOL_OPTION ("SoftwareMirror", software_mirror);
1232+ OBTAIN_BOOL_OPTION ("LabelPreamble", label_preamble);
1233+ /* Release memory allocated for CUPS options struct */
1234+ cupsFreeOptions (num_options, cups_options);
1235+ return options;
1236+}
1237+
1238+/**
1239+ * Determine input stream and open it. If there are 6 command line
1240+ * arguments, argv[6] is taken to be the input file name
1241+ * otherwise stdin is used. This funtion exits the program on error.
1242+ * @param argc number of command line arguments plus one
1243+ * @param argv command line arguments
1244+ * @return file descriptor for the opened input stream
1245+ */
1246+int
1247+open_input_file (int argc, const char* argv []) {
1248+ int fd;
1249+ if (argc == 7) {
1250+ if ((fd = open (argv[6], O_RDONLY)) < 0) {
1251+ perror ("ERROR: Unable to open raster file - ");
1252+ sleep (1);
1253+ exit (1);
1254+ }
1255+ } else
1256+ fd = 0;
1257+ return fd;
1258+}
1259+
1260+/**
1261+ * Update page_options with information found in header.
1262+ * @param header CUPS page header
1263+ * @param page_options page options to be updated
1264+ */
1265+void
1266+update_page_options (cups_page_header_t* header,
1267+ page_options_t* page_options) {
1268+ page_options->cut_media = header->CutMedia;
1269+ page_options->mirror = header->MirrorPrint;
1270+ const char* media_type = header->MediaType;
1271+ page_options->roll_fed_media /* Default is continuous roll */
1272+ = (strcasecmp ("Labels", media_type) != 0);
1273+ page_options->resolution [0] = header->HWResolution [0];
1274+ page_options->resolution [1] = header->HWResolution [1];
1275+ page_options->page_size [0] = header->PageSize [0];
1276+ page_options->page_size [1] = header->PageSize [1];
1277+ page_options->image_height = header->cupsHeight;
1278+ page_options->feed = header->AdvanceDistance;
1279+ page_options->perform_feed = header->AdvanceMedia;
1280+}
1281+
1282+void cancel_job (int signal);
1283+/**
1284+ * Prepare for a new page by setting up signalling infrastructure and
1285+ * memory allocation.
1286+ * @param cups_buffer_size Required size of CUPS raster line buffer
1287+ * @param device_buffer_size Required size of device pixel line buffer
1288+ */
1289+void
1290+page_prepare (unsigned cups_buffer_size, unsigned device_buffer_size) {
1291+ /* Set up signalling to handle print job cancelling */
1292+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1293+ struct sigaction action;
1294+#endif
1295+
1296+#ifdef HAVE_SIGSET
1297+ sigset (SIGTERM, cancel_job);
1298+#elif defined(HAVE_SIGACTION)
1299+ memset (&action, 0, sizeof (action));
1300+ sigemptyset (&action.sa_mask);
1301+ action.sa_handler = cancel_job;
1302+ sigaction (SIGTERM, &action, NULL);
1303+#else
1304+ signal (SIGTERM, cancel_job);
1305+#endif
1306+
1307+ /* Allocate line buffer */
1308+ buffer = malloc (cups_buffer_size);
1309+ emit_line_buffer = malloc (device_buffer_size);
1310+ if (!buffer || !emit_line_buffer) {
1311+ fprintf
1312+ (stderr,
1313+ "ERROR: Cannot allocate memory for raster line buffer\n");
1314+ exit (1);
1315+ }
1316+}
1317+
1318+/**
1319+ * Clean up signalling and memory after emitting a page
1320+*/
1321+void
1322+page_end () {
1323+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1324+ struct sigaction action;
1325+#endif
1326+
1327+#ifdef HAVE_SIGSET
1328+ sigset (SIGTERM, SIG_IGN);
1329+#elif defined(HAVE_SIGACTION)
1330+ memset (&action, 0, sizeof (action));
1331+ sigemptyset (&action.sa_mask);
1332+ action.sa_handler = SIG_IGN;
1333+ sigaction (SIGTERM, &action, NULL);
1334+#else
1335+ signal (SIGTERM, SIG_IGN);
1336+#endif
1337+ /* Release line buffer memory */
1338+ free (buffer);
1339+ free (emit_line_buffer);
1340+}
1341+
1342+/**
1343+ * Cancel print job.
1344+ */
1345+void
1346+cancel_job (int signal) {
1347+ /* Emit page end & eject marker */
1348+ putchar (PTC_EJECT);
1349+ page_end ();
1350+ if (rle_buffer) free (rle_buffer);
1351+ exit (0);
1352+}
1353+
1354+/**
1355+ * Emit printer command codes at start of print job.
1356+ * This function does not emit P-touch page specific codes.
1357+ * @param job_options Job options
1358+ */
1359+void
1360+emit_job_cmds (job_options_t* job_options) {
1361+ /* Initialise printer */
1362+ putchar (ESC); putchar ('@');
1363+ /* Emit print density selection command if required */
1364+ int density = job_options->print_density;
1365+ switch (density) {
1366+ case 1: case 2: case 3: case 4: case 5:
1367+ putchar (ESC); putchar ('i'); putchar ('D'); putchar (density);
1368+ break;
1369+ default: break;
1370+ }
1371+ /* Emit transfer mode selection command if required */
1372+ int xfer_mode = job_options->xfer_mode;
1373+ if (xfer_mode >= 0 && xfer_mode < 0x100) {
1374+ putchar (ESC); putchar ('i'); putchar ('R'); putchar (xfer_mode);
1375+ }
1376+ /* Emit half cut selection command if required */
1377+ if (job_options->half_cut) {
1378+ putchar (ESC); putchar ('i'); putchar ('K'); putchar (0x04);
1379+ }
1380+}
1381+
1382+/**
1383+ * Emit feed, cut and mirror command codes.
1384+ * @param do_feed Emit codes to actually feed
1385+ * @param feed Feed size
1386+ * @param do_cut Emit codes to actually cut
1387+ * @param do_mirror Emit codes to mirror print
1388+ */
1389+inline void
1390+emit_feed_cut_mirror (bool do_feed, unsigned feed,
1391+ bool do_cut,
1392+ bool do_mirror) {
1393+ /* Determine feed nibble */
1394+ unsigned feed_nibble;
1395+ if (do_feed) {
1396+ feed_nibble = lrint (feed / 2.6 + 2.4); /* one suggested conversion */
1397+ if (feed_nibble > 31) feed_nibble = 31;
1398+ } else
1399+ feed_nibble = 0;
1400+ /* Determine auto cut bit - we only handle after each page */
1401+ unsigned char auto_cut_bit = do_cut ? 0x40 : 0x00;
1402+ /* Determine mirror print bit*/
1403+ unsigned char mirror_bit = do_mirror ? 0x80 : 0x00;
1404+ /* Combine & emit printer command code */
1405+ putchar (ESC); putchar ('i'); putchar ('M');
1406+ putchar ((char) (feed & 0x1f) | auto_cut_bit | mirror_bit);
1407+}
1408+
1409+/**
1410+ * Emit quality, roll fed media, and label size command codes.
1411+ * @param job_options Current job options
1412+ * @param page_options Current page options
1413+ * @param page_size_y Page size (height) in pt
1414+ * @param image_height_px Number of pixel lines in current page
1415+ */
1416+void
1417+emit_quality_rollfed_size (job_options_t* job_options,
1418+ page_options_t* page_options,
1419+ unsigned page_size_y,
1420+ unsigned image_height_px) {
1421+ bool roll_fed_media = page_options->roll_fed_media;
1422+ /* Determine print quality bit */
1423+ unsigned char print_quality_bit
1424+ = (job_options->print_quality_high == CUPS_TRUE) ? 0x40 : 0x00;
1425+ unsigned char roll_fed_media_bit = roll_fed_media ? 0x00 : 0x01;
1426+ /* Get tape width in mm */
1427+ int tape_width_mm = lrint (page_options->page_size [0] * MM_PER_PT);
1428+ if (tape_width_mm > 0xff) {
1429+ fprintf (stderr,
1430+ "ERROR: Page width (%umm) exceeds 255mm\n",
1431+ tape_width_mm);
1432+ tape_width_mm = 0xff;
1433+ }
1434+ /* Get tape height in mm */
1435+ unsigned tape_height_mm;
1436+ if (roll_fed_media)
1437+ tape_height_mm = 0;
1438+ else
1439+ tape_height_mm = lrint (page_size_y * MM_PER_PT);
1440+ if (tape_height_mm > 0xff) {
1441+ fprintf (stderr,
1442+ "ERROR: Page height (%umm) exceeds 255mm; use continuous tape (MediaType=roll)\n",
1443+ tape_height_mm);
1444+ tape_height_mm = 0xff;
1445+ }
1446+ /* Combine & emit printer command code */
1447+ putchar (ESC); putchar ('i'); putchar ('z');
1448+ putchar (print_quality_bit); putchar (roll_fed_media_bit);
1449+ putchar (tape_width_mm & 0xff); putchar (tape_height_mm & 0xff);
1450+ putchar (image_height_px & 0xff);
1451+ putchar ((image_height_px >> 8) & 0xff);
1452+ putchar (0x00); putchar (0x00); putchar (0x00); putchar (0x00);
1453+}
1454+/**
1455+ * Emit printer command codes at start of page for options that have
1456+ * changed.
1457+ * @param job_options Job options
1458+ * @param old_page_options Page options for preceding page
1459+ * @param new_page_options Page options for page to be printed
1460+ * @param force Ignore old_page_options and emit commands
1461+ * for selecting all options in new_page_options
1462+ */
1463+void
1464+emit_page_cmds (job_options_t* job_options,
1465+ page_options_t* old_page_options,
1466+ page_options_t* new_page_options,
1467+ bool force) {
1468+ int tape_width_mm = -1;
1469+
1470+ /* Set width and resolution */
1471+ unsigned hres = new_page_options->resolution [0];
1472+ unsigned vres = new_page_options->resolution [1];
1473+ unsigned old_page_size_x = old_page_options->page_size [0];
1474+ unsigned new_page_size_x = new_page_options->page_size [0];
1475+ if (force
1476+ || hres != old_page_options->resolution [0]
1477+ || vres != old_page_options->resolution [1]
1478+ || new_page_size_x != old_page_size_x)
1479+ /* We only know how to select 360x360DPI or 360x720DPI */
1480+ if (hres == 360 && (vres == 360 || vres == 720)) {
1481+ /* Get tape width in mm */
1482+ tape_width_mm = lrint (new_page_size_x * MM_PER_PT);
1483+ if (tape_width_mm > 0xff) {
1484+ fprintf (stderr,
1485+ "ERROR: Page width (%umm) exceeds 255mm\n",
1486+ tape_width_mm);
1487+ tape_width_mm = 0xff;
1488+ }
1489+ /* Emit printer commands */
1490+ putchar (ESC); putchar ('i'); putchar ('c');
1491+ if (vres == 360) {
1492+ putchar (0x84); putchar (0x00); putchar (tape_width_mm & 0xff);
1493+ putchar (0x00); putchar (0x00);
1494+ } else {
1495+ putchar (0x86); putchar (0x09); putchar (tape_width_mm & 0xff);
1496+ putchar (0x00); putchar (0x01);
1497+ }
1498+ }
1499+
1500+ /* Set feed, auto cut and mirror print */
1501+ unsigned feed = new_page_options->feed;
1502+ cups_adv_t perform_feed = new_page_options->perform_feed;
1503+ cups_cut_t cut_media = new_page_options->cut_media;
1504+ cups_bool_t mirror = new_page_options->mirror;
1505+ if (force
1506+ || feed != old_page_options->feed
1507+ || perform_feed != old_page_options->perform_feed
1508+ || cut_media != old_page_options->cut_media
1509+ || mirror != old_page_options->mirror)
1510+ /* We only know how to feed after each page */
1511+ emit_feed_cut_mirror (perform_feed == CUPS_ADVANCE_PAGE, feed,
1512+ cut_media == CUPS_CUT_PAGE,
1513+ mirror == CUPS_TRUE);
1514+ /* Set media and quality if label preamble is requested */
1515+ unsigned page_size_y = new_page_options->page_size [1];
1516+ unsigned image_height_px = lrint (page_size_y * vres / 72.0);
1517+ if (job_options->label_preamble && !job_options->concat_pages
1518+ && (force
1519+ || (new_page_options->roll_fed_media
1520+ != old_page_options->roll_fed_media)
1521+ || new_page_size_x != old_page_size_x
1522+ || page_size_y != old_page_options->page_size [1]))
1523+ emit_quality_rollfed_size (job_options, new_page_options,
1524+ page_size_y, image_height_px);
1525+
1526+ /* WHY DON'T WE SET MARGIN (ESC i d ...)? */
1527+
1528+ /* Set pixel data transfer compression */
1529+ if (force) {
1530+ if (job_options->pixel_xfer == RLE) {
1531+ putchar ('M'); putchar (0x02);
1532+ }
1533+ }
1534+ /* Emit number of raster lines to follow if using BIP */
1535+ if (job_options->pixel_xfer == BIP) {
1536+ unsigned image_height_px = lrint (page_size_y * vres / 72.0);
1537+ putchar (ESC); putchar (0x2a); putchar (0x27);
1538+ putchar (image_height_px & 0xff);
1539+ putchar ((image_height_px >> 8) & 0xff);
1540+ }
1541+}
1542+
1543+/** mirror [i] = bit mirror image of i.
1544+ * I.e., (mirror [i] >> j) & 1 == (i >> (7 - j)) & 1 for 0 <= j <= 7
1545+ */
1546+const unsigned char mirror [0x100] = {
1547+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
1548+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
1549+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
1550+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
1551+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
1552+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
1553+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
1554+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
1555+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
1556+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
1557+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
1558+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
1559+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
1560+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
1561+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
1562+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
1563+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
1564+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
1565+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
1566+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
1567+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
1568+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
1569+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
1570+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
1571+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
1572+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
1573+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
1574+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
1575+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
1576+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
1577+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
1578+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
1579+};
1580+
1581+/**
1582+ * Generate a buffer of pixel data ready to emit.
1583+ * Requirement: buflen + right_padding_bytes
1584+ * + (shift > 0 ? 1 : 0) <= bytes_per_line
1585+ * @param in_buffer Buffer containing raster data in
1586+ * left-to-right order
1587+ * @param out_buffer Buffer for returning generated line in
1588+ * right-to-left order; must be
1589+ * bytes_per_line long
1590+ * @param buflen in_buffer length
1591+ * @param bytes_per_line Number of pixel bytes to generate
1592+ * @param right_padding_bytes Number of zero bytes to pad
1593+ * with to the right of pixels
1594+ * @param shift Number of bits to shift left
1595+ * If do_mirror is false and shift < 0
1596+ * Then shift right -shift bits
1597+ * @param do_mirror Mirror in_buffer pixel data
1598+ * @param xormask The XOR mask for negative printing
1599+ * @return 0 if entire line is empty (zeros)
1600+ * nonzero if line contains nonzero pixels
1601+ */
1602+inline int
1603+generate_emit_line (unsigned char* in_buffer,
1604+ unsigned char* out_buffer,
1605+ int buflen,
1606+ unsigned char bytes_per_line,
1607+ int right_padding_bytes,
1608+ int shift,
1609+ int do_mirror,
1610+ unsigned char xormask) {
1611+#ifdef DEBUG
1612+ if (debug)
1613+ fprintf (stderr, "DEBUG: generate_emit_line "
1614+ "(in_buffer=%0x, out_buffer=%0x, "
1615+ "buflen=%d, bytes_per_line=%d, right_padding_bytes=%d, "
1616+ "shift=%d, do_mirror=%d, xormask=%0x)\n",
1617+ in_buffer, out_buffer, buflen, bytes_per_line,
1618+ right_padding_bytes, shift, do_mirror, xormask);
1619+#endif
1620+ /* Generate right padding zero bytes */
1621+ memset (out_buffer, xormask, right_padding_bytes);
1622+ unsigned int nonzero = 0;
1623+ int j = right_padding_bytes;
1624+ /* Copy pixel data from in_buffer to out_buffer, */
1625+ /* shifted and mirrored if required */
1626+ unsigned int box = 0; /* Box for shifting pixel data left */
1627+ int i;
1628+ if (do_mirror)
1629+ if (shift) {
1630+ for (i = 0; i < buflen; i++) {
1631+ unsigned int data = in_buffer [i]; nonzero |= data;
1632+ box |= data << shift;
1633+ out_buffer [j++] = (box & 0xff) ^ xormask;
1634+ box >>= 8;
1635+ }
1636+ out_buffer [j++] = box & 0xff;
1637+ } else
1638+ for (i = 0; i < buflen; i++) {
1639+ unsigned char data = in_buffer [i]; nonzero |= data;
1640+ out_buffer [j++] = data ^ xormask;
1641+ }
1642+ else
1643+ if (shift) {
1644+ if (buflen > 0) {
1645+ if (shift < 0) {
1646+ box = in_buffer [buflen - 1] >> -shift; nonzero |= box;
1647+ shift += 8;
1648+ } else {
1649+ box = in_buffer [buflen - 1] << shift; nonzero |= box;
1650+ out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
1651+ box >>= 8;
1652+ }
1653+ for (i = buflen - 2; i >= 0; i--) {
1654+ unsigned data = in_buffer [i]; nonzero |= data;
1655+ box |= data << shift;
1656+ out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
1657+ box >>= 8;
1658+ }
1659+ out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
1660+ }
1661+ } else
1662+ for (i = buflen - 1; i >= 0; i--) {
1663+ unsigned char data = in_buffer [i]; nonzero |= data;
1664+ out_buffer [j++] = (mirror [data]) ^ xormask;
1665+ }
1666+ /* Generate left padding bytes */
1667+ memset (out_buffer + j, xormask, bytes_per_line - j);
1668+ return nonzero != 0;
1669+}
1670+
1671+/**
1672+ * Emit lines waiting in RLE buffer.
1673+ * Resets global variable rle_buffer_next to rle_buffer,
1674+ * and lines_waiting to zero.
1675+ * @param job_options Job options
1676+ * @param page_options Page options
1677+ */
1678+inline void
1679+flush_rle_buffer (job_options_t* job_options,
1680+ page_options_t* page_options) {
1681+#ifdef DEBUG
1682+ if (debug)
1683+ fprintf (stderr, "DEBUG: flush_rle_buffer (): "
1684+ "lines_waiting = %d\n",
1685+ lines_waiting);
1686+#endif
1687+ if (lines_waiting > 0) {
1688+ if (job_options->label_preamble)
1689+ emit_quality_rollfed_size (job_options, page_options,
1690+ page_options->page_size [1],
1691+ lines_waiting);
1692+ xfer_t pixel_xfer = job_options->pixel_xfer;
1693+ int bytes_per_line = job_options->bytes_per_line;
1694+ switch (pixel_xfer) {
1695+ case RLE: {
1696+ size_t dummy
1697+ = fwrite (rle_buffer, sizeof (char), rle_buffer_next - rle_buffer, stdout);
1698+ break;
1699+ }
1700+ case ULP:
1701+ case BIP: {
1702+ unsigned char* p = rle_buffer;
1703+ unsigned emitted_lines = 0;
1704+ while (rle_buffer_next - p > 0) {
1705+ if (pixel_xfer == ULP) {
1706+ putchar ('g'); putchar (0x00); putchar (bytes_per_line);
1707+ }
1708+ int emitted = 0;
1709+ int linelen;
1710+ switch (*p++) {
1711+ case 'G':
1712+ linelen = *p++;
1713+ linelen += ((int)(*p++)) << 8;
1714+ while (linelen > 0) {
1715+ signed char l = *p++; linelen--;
1716+ if (l < 0) { /* emit repeated data */
1717+ char data = *p++; linelen--;
1718+ emitted -= l; emitted++;
1719+ for (; l <= 0; l++) putchar (data);
1720+ } else { /* emit the l + 1 following bytes of data */
1721+ size_t dummy = fwrite (p, sizeof (char), l + 1, stdout);
1722+ p += l; p++;
1723+ linelen -= l; linelen--;
1724+ emitted += l; emitted++;
1725+ }
1726+ }
1727+ if (emitted > bytes_per_line)
1728+ fprintf (stderr,
1729+ "ERROR: Emitted %d > %d bytes for one pixel line!\n",
1730+ emitted, bytes_per_line);
1731+ /* No break; fall through to next case: */
1732+ case 'Z':
1733+ for (; emitted < bytes_per_line; emitted++) putchar (0x00);
1734+ break;
1735+ default:
1736+ fprintf (stderr, "ERROR: Unknown RLE flag at %p: '0x%02x'\n",
1737+ p - 1, (int)*(p - 1));
1738+ }
1739+ emitted_lines++;
1740+ }
1741+#ifdef DEBUG
1742+ if (debug)
1743+ fprintf (stderr, "DEBUG: emitted %d lines\n", emitted_lines);
1744+#endif
1745+ break;
1746+ }
1747+ default:
1748+ fprintf (stderr, "ERROR: Unknown pixel transfer mode: '%d'\n",
1749+ pixel_xfer);
1750+ }
1751+ rle_buffer_next = rle_buffer;
1752+ lines_waiting = 0;
1753+ }
1754+}
1755+
1756+/**
1757+ * Ensure sufficient memory available in rle buffer.
1758+ * If rle buffer needs to be extended, global variables rle_buffer and
1759+ * rle_buffer_next might be altered.
1760+ * @param job_options Job options
1761+ * @param page_options Page options
1762+ * @param bytes Number of bytes required.
1763+ */
1764+inline void
1765+ensure_rle_buf_space (job_options_t* job_options,
1766+ page_options_t* page_options,
1767+ unsigned bytes) {
1768+ unsigned long nextpos = rle_buffer_next - rle_buffer;
1769+ if (nextpos + bytes > rle_alloced) {
1770+ /* Exponential size increase avoids too frequent reallocation */
1771+ unsigned long new_alloced = rle_alloced * 2 + 0x4000;
1772+#ifdef DEBUG
1773+ if (debug)
1774+ fprintf (stderr, "DEBUG: ensure_rle_buf_space (bytes=%d): "
1775+ "increasing rle_buffer from %d to %d\n",
1776+ bytes,
1777+ rle_alloced * sizeof (char),
1778+ new_alloced * sizeof (char));
1779+#endif
1780+ void* p = NULL;
1781+ if (new_alloced <= job_options->rle_alloc_max) {
1782+ if (rle_buffer)
1783+ p = (unsigned char*) realloc (rle_buffer, new_alloced * sizeof (char));
1784+ else
1785+ p = (unsigned char*) malloc (new_alloced * sizeof (char));
1786+ }
1787+ if (p) {
1788+ rle_buffer = p;
1789+ rle_buffer_next = rle_buffer + nextpos;
1790+ rle_alloced = new_alloced;
1791+ } else { /* Gain memory by flushing buffer to printer */
1792+ flush_rle_buffer (job_options, page_options);
1793+ if (rle_buffer_next - rle_buffer + bytes > rle_alloced) {
1794+ fprintf (stderr,
1795+ "ERROR: Out of memory when attempting to increase RLE "
1796+ "buffer from %ld to %ld bytes\n",
1797+ rle_alloced * sizeof (char),
1798+ new_alloced * sizeof (char));
1799+ exit (-1);
1800+ }
1801+ }
1802+ }
1803+}
1804+
1805+/** @def APPEND_MIXED_BYTES
1806+ * Macro for appending mixed-bytes run to rle_buffer */
1807+/** @def APPEND_REPEATED_BYTE
1808+ * Macro for appending repeated-byte run to rle_buffer */
1809+/**
1810+ * Store buffer data in rle buffer using run-length encoding.
1811+ * @param job_options Job options
1812+ * @param page_options Page options
1813+ * @param buf Buffer containing data to store
1814+ * @param buf_len Length of buffer
1815+ *
1816+ * Global variable rle_buffer_next is a pointer into buffer for holding RLE data.
1817+ * Must have room for at least 3 + buf_len + buf_len/128 + 1
1818+ * bytes (ensured by reallocation).
1819+ * On return, rle_buffer_next points to first unused buffer byte.
1820+ *
1821+ * This implementation enjoys the property that
1822+ * the resulting RLE is at most buf_len + buf_len/128 + 1 bytes
1823+ * long, because:
1824+ * # a repeated-byte run has a repeat factor of at least 3
1825+ * # two mixed-bytes runs never follow directly after each other,
1826+ * unless the first one is 128 bytes long
1827+ * The first property ensures that a repeated-run output sequence is
1828+ * always at least 1 byte shorter than the input sequence it
1829+ * represents. This combined with the second property means that only
1830+ * - a terminating mixed-bytes run, and
1831+ * - a mixed-bytes run of 128 bytes
1832+ * can cause the RLE representation to be longer (by 1 byte) than the
1833+ * corresponding input sequence in buf.
1834+ */
1835+inline void
1836+RLE_store_line (job_options_t* job_options,
1837+ page_options_t* page_options,
1838+ const unsigned char* buf, unsigned buf_len) {
1839+ ensure_rle_buf_space (job_options, page_options,
1840+ 4 + buf_len + buf_len / 128);
1841+ unsigned char* rle_next = rle_buffer_next + 3;
1842+ /* Make room for 3 initial meta data bytes, */
1843+ /* written when actual length is known */
1844+ const unsigned char* buf_end = buf + buf_len; /* Buffer end */
1845+ const unsigned char* mix_start; /* Start of mixed bytes run */
1846+
1847+ const unsigned char* rep_start; /* End + 1 of mixed bytes run,
1848+ and start of repeated byte run */
1849+ const unsigned char* next; /* Next byte pointer,
1850+ and end + 1 of repeated byte run */
1851+ unsigned char next_val; /* Next byte value to consider */
1852+ unsigned char rep_val; /* Repeated byte value */
1853+ unsigned char nonzero = 0; /* OR of all buffer bytes */
1854+
1855+#define APPEND_MIXED_BYTES \
1856+ if (mix_len > 128) mix_len = 128; \
1857+ *rle_next++ = mix_len - 1; \
1858+ memcpy (rle_next, mix_start, mix_len); \
1859+ rle_next += mix_len;
1860+#define APPEND_REPEATED_BYTE \
1861+ unsigned rep_len = next - rep_start; \
1862+ *rle_next++ = (signed char)(1 - rep_len); \
1863+ *rle_next++ = rep_val;
1864+
1865+ for (mix_start = rep_start = next = buf, rep_val = next_val = *next;
1866+ next != buf_end;
1867+ next++, next_val = *next) {
1868+ /* Loop invariants at this point:
1869+ * 1) [mix_start..rep_start - 1] contains mixed bytes waiting
1870+ * to be appended to rle_buffer,
1871+ * 2) [rep_start..next - 1] contains repeats of rep_val
1872+ * waiting to be appended to rle_buffer
1873+ * 3) If next - rep_start > 2 then mix_start == rep_start
1874+ * 4) next - rep_start <= 129
1875+ * 5) rep_start - mix_start < 128
1876+ * 6) [rle_buffer_next..rle_next - 1] = RLE ([buf..mix_start - 1])
1877+ * 7) rep_val = *rep_start
1878+ * 8) next_val = *next
1879+ */
1880+ nonzero |= next_val;
1881+ if (next - rep_start >= 129) {
1882+ /* RLE cannot represent repeated runs longer than 129 bytes */
1883+ APPEND_REPEATED_BYTE;
1884+ rep_start += rep_len;
1885+ rep_val = *rep_start;
1886+ mix_start = rep_start;
1887+ }
1888+ if (next_val == rep_val) { /* Run of repeated byte values */
1889+ if (next - rep_start == 2) {
1890+ unsigned mix_len = rep_start - mix_start;
1891+ if (mix_len > 0) {
1892+ APPEND_MIXED_BYTES;
1893+ mix_start = rep_start;
1894+ }
1895+ }
1896+ } else {
1897+ if (next - rep_start > 2) { /* End of repeated run found */
1898+ APPEND_REPEATED_BYTE;
1899+ mix_start = next;
1900+ }
1901+ rep_start = next;
1902+ rep_val = next_val;
1903+ unsigned mix_len = rep_start - mix_start;
1904+ if (mix_len >= 128) {
1905+ /* RLE cannot represent mixed runs longer than 128 bytes */
1906+ APPEND_MIXED_BYTES;
1907+ mix_start += mix_len;
1908+ }
1909+ }
1910+ }
1911+ /* Handle final bytes */
1912+ if (next - rep_start > 2) { /* Handle final repeated byte run */
1913+ APPEND_REPEATED_BYTE;
1914+ mix_start = next;
1915+ }
1916+ rep_start = next;
1917+ unsigned mix_len = rep_start - mix_start;
1918+ if (mix_len > 0) { /* Handle any remaining final mixed run */
1919+ APPEND_MIXED_BYTES;
1920+ mix_start += mix_len;
1921+ }
1922+ mix_len = rep_start - mix_start;
1923+ if (mix_len > 0) { /* Case where final mixed run is 129 bytes */
1924+ APPEND_MIXED_BYTES;
1925+ }
1926+ unsigned rle_len = rle_next - rle_buffer_next - 3;
1927+ /* Store rle line meta data (length and (non)zero status) */
1928+ if (nonzero) { /* Check for nonempty (no black pixels) line */
1929+ rle_buffer_next [0] = 'G';
1930+ rle_buffer_next [1] = rle_len & 0xff;
1931+ rle_buffer_next [2] = (rle_len >> 8) & 0xff;
1932+ rle_buffer_next = rle_next;
1933+ } else {
1934+ rle_buffer_next [0] = 'Z';
1935+ rle_buffer_next++;
1936+ }
1937+ lines_waiting++;
1938+ if (lines_waiting >= max_lines_waiting)
1939+ flush_rle_buffer (job_options, page_options);
1940+}
1941+
1942+/**
1943+ * Store a number of empty lines in rle_buffer using RLE.
1944+ * @param job_options Job options
1945+ * @param page_options Page options
1946+ * @param empty_lines Number of empty lines to store
1947+ * @param xormask The XOR mask for negative printing
1948+ */
1949+inline void
1950+RLE_store_empty_lines (job_options_t* job_options,
1951+ page_options_t* page_options,
1952+ int empty_lines,
1953+ unsigned char xormask) {
1954+ int bytes_per_line = job_options->bytes_per_line;
1955+#ifdef DEBUG
1956+ if (debug)
1957+ fprintf (stderr, "DEBUG: RLE_store_empty_lines (empty_lines=%d, "
1958+ "bytes_per_line=%d): lines_waiting = %d\n",
1959+ empty_lines, bytes_per_line, lines_waiting);
1960+#endif
1961+ lines_waiting += empty_lines;
1962+ if (xormask) {
1963+ int blocks = (bytes_per_line + 127) / 128;
1964+ ensure_rle_buf_space (job_options, page_options,
1965+ empty_lines * blocks);
1966+ for (; empty_lines--; ) {
1967+ *(rle_buffer_next++) = 'G';
1968+ *(rle_buffer_next++) = 0x02;
1969+ *(rle_buffer_next++) = 0x00;
1970+ int rep_len;
1971+ for (; bytes_per_line > 0; bytes_per_line -= rep_len) {
1972+ rep_len = bytes_per_line;
1973+ if (rep_len > 128) rep_len = 128;
1974+ *(rle_buffer_next++) = (signed char) (1 - rep_len);
1975+ *(rle_buffer_next++) = xormask;
1976+ }
1977+ }
1978+ } else {
1979+ ensure_rle_buf_space (job_options, page_options, empty_lines);
1980+ for (; empty_lines--; ) *(rle_buffer_next++) = 'Z';
1981+ }
1982+}
1983+
1984+/**
1985+ * Emit raster lines for current page.
1986+ * @param page Page number of page to be emitted
1987+ * @param job_options Job options
1988+ * @param page_options Page options
1989+ * @param ras Raster data stream
1990+ * @param header Current page header
1991+ * @return 0 on success, nonzero otherwise
1992+ */
1993+int
1994+emit_raster_lines (int page,
1995+ job_options_t* job_options,
1996+ page_options_t* page_options,
1997+ cups_raster_t* ras,
1998+ cups_page_header_t* header) {
1999+ unsigned char xormask = (header->NegativePrint ? ~0 : 0);
2000+ /* Determine whether we need to mirror the pixel data */
2001+ int do_mirror = job_options->software_mirror && page_options->mirror;
2002+
2003+ unsigned cupsBytesPerLine = header->cupsBytesPerLine;
2004+ unsigned cupsHeight = header->cupsHeight;
2005+ unsigned cupsWidth = header->cupsWidth;
2006+ int bytes_per_line = job_options->bytes_per_line;
2007+ unsigned buflen = cupsBytesPerLine;
2008+ /* Make sure buflen can be written as a byte */
2009+ if (buflen > 0xff) buflen = 0xff;
2010+ /* Truncate buflen if greater than bytes_per_line */
2011+ if (buflen >= bytes_per_line) buflen = bytes_per_line;
2012+ /* Calculate extra horizontal spacing pixels if the right side of */
2013+ /* ImagingBoundingBox doesn't touch the PageSize box */
2014+ double scale_pt2xpixels = header->HWResolution [0] / 72.0;
2015+ unsigned right_spacing_px = 0;
2016+ if (header->ImagingBoundingBox [2] != 0) {
2017+ unsigned right_distance_pt
2018+ = header->PageSize [0] - header->ImagingBoundingBox [2];
2019+ if (right_distance_pt != 0)
2020+ right_spacing_px = right_distance_pt * scale_pt2xpixels;
2021+ }
2022+ /* Calculate right_padding_bytes and shift */
2023+ int right_padding_bits;
2024+ if (job_options->align == CENTER) {
2025+ unsigned left_spacing_px = 0;
2026+ if (header->ImagingBoundingBox [0] != 0)
2027+ left_spacing_px
2028+ = header->ImagingBoundingBox [0] * scale_pt2xpixels;
2029+ right_padding_bits
2030+ = (bytes_per_line * 8
2031+ - (left_spacing_px + cupsWidth + right_spacing_px)) / 2
2032+ + right_spacing_px;
2033+ if (right_padding_bits < 0) right_padding_bits = 0;
2034+ } else
2035+ right_padding_bits = right_spacing_px;
2036+ int right_padding_bytes = right_padding_bits / 8;
2037+ int shift = right_padding_bits % 8;
2038+ /* If width is not an integral number of bytes, we must shift */
2039+ /* right if we don't mirror, to ensure printing starts leftmost */
2040+ if (!do_mirror) shift -= (8 - cupsWidth % 8) % 8;
2041+ int shift_positive = (shift > 0 ? 1 : 0);
2042+ /* We cannot allow buffer+padding to exceed device width */
2043+ if (buflen + right_padding_bytes + shift_positive > bytes_per_line) {
2044+#ifdef DEBUG
2045+ if (debug) {
2046+ fprintf (stderr, "DEBUG: Warning: buflen = %d, right_padding_bytes = %d, "
2047+ "shift = %d, bytes_per_line = %d\n",
2048+ buflen, right_padding_bytes, shift, bytes_per_line);
2049+ }
2050+#endif
2051+ /* We cannot allow padding to exceed device width */
2052+ if (right_padding_bytes + shift_positive > bytes_per_line)
2053+ right_padding_bytes = bytes_per_line - shift_positive;
2054+ /* Truncate buffer to fit device width */
2055+ buflen = bytes_per_line - right_padding_bytes - shift_positive;
2056+ }
2057+ /* Percentage of page emitted */
2058+ int completed = -1;
2059+ /* Generate and store empty lines if the top of ImagingBoundingBox */
2060+ /* doesn't touch the PageSize box */
2061+ double scale_pt2ypixels = header->HWResolution [1] / 72.0;
2062+ unsigned top_empty_lines = 0;
2063+ unsigned page_size_y = header->PageSize [1];
2064+ if (header->ImagingBoundingBox [3] != 0
2065+ && (!job_options->concat_pages || page == 1)) {
2066+ unsigned top_distance_pt
2067+ = page_size_y - header->ImagingBoundingBox [3];
2068+ if (top_distance_pt != 0) {
2069+ top_empty_lines = lrint (top_distance_pt * scale_pt2ypixels);
2070+ empty_lines += top_empty_lines;
2071+ }
2072+ }
2073+ /* Generate and store actual page data */
2074+ int y;
2075+ for (y = 0; y < cupsHeight; y++) {
2076+ /* Feedback to the user */
2077+ if ((y & 0x1f) == 0) {
2078+ int now_completed = 100 * y / cupsHeight;
2079+ if (now_completed > completed) {
2080+ completed = now_completed;
2081+ fprintf (stderr,
2082+ "INFO: Printing page %d, %d%% complete...\n",
2083+ page, completed);
2084+ fflush (stderr);
2085+ }
2086+ }
2087+ /* Read one line of pixels */
2088+ if (cupsRasterReadPixels (ras, buffer, cupsBytesPerLine) < 1)
2089+ break; /* Escape if no pixels read */
2090+ bool nonempty_line =
2091+ generate_emit_line (buffer, emit_line_buffer, buflen, bytes_per_line,
2092+ right_padding_bytes, shift, do_mirror, xormask);
2093+ if (nonempty_line) {
2094+ if (empty_lines) {
2095+ RLE_store_empty_lines
2096+ (job_options, page_options, empty_lines, xormask);
2097+ empty_lines = 0;
2098+ }
2099+ RLE_store_line (job_options, page_options,
2100+ emit_line_buffer, bytes_per_line);
2101+ } else
2102+ empty_lines++;
2103+ }
2104+
2105+ unsigned image_height_px = lrint (page_size_y * scale_pt2ypixels);
2106+ unsigned bot_empty_lines;
2107+ if (image_height_px >= top_empty_lines + y)
2108+ bot_empty_lines = image_height_px - top_empty_lines - y;
2109+ else
2110+ bot_empty_lines = 0;
2111+ if (bot_empty_lines != 0 && !job_options->concat_pages)
2112+ empty_lines += bot_empty_lines;
2113+ fprintf (stderr,
2114+ "INFO: Printing page %d, 100%% complete.\n",
2115+ page);
2116+ fflush (stderr);
2117+ return 0;
2118+}
2119+/**
2120+ * Process CUPS raster data from input file, emitting printer data on
2121+ * stdout.
2122+ * @param fd File descriptor for input file
2123+ * @param job_options Pointer to print options
2124+ * @return 0 on success, nonzero otherwise
2125+ */
2126+int
2127+process_rasterdata (int fd, job_options_t* job_options) {
2128+ int page = 1; /* Page number */
2129+ cups_raster_t* ras; /* Raster stream for printing */
2130+ cups_page_header_t header; /* Current page header */
2131+ int first_page = true; /* Is this the first page? */
2132+ int more_pages; /* Are there more pages left? */
2133+ int bytes_per_line = job_options->bytes_per_line;
2134+ page_options_t page_options [2] = {{
2135+ CUT_MEDIA_DEFAULT,
2136+ MIRROR_DEFAULT,
2137+ ROLL_FED_MEDIA_DEFAULT,
2138+ RESOLUTION_DEFAULT,
2139+ PAGE_SIZE_DEFAULT,
2140+ IMAGE_HEIGHT_DEFAULT,
2141+ FEED_DEFAULT,
2142+ PERFORM_FEED_DEFAULT,}
2143+ }; /* Current & preceding page opts */
2144+ page_options_t* new_page_options
2145+ = page_options + 0; /* Options for current page */
2146+ page_options_t* old_page_options
2147+ = page_options + 1; /* Options for preceding page */
2148+ page_options_t* tmp_page_options;/* Temp variable for swapping */
2149+ ras = cupsRasterOpen (fd, CUPS_RASTER_READ);
2150+ for (more_pages = cupsRasterReadHeader (ras, &header);
2151+ more_pages;
2152+ tmp_page_options = old_page_options,
2153+ old_page_options = new_page_options,
2154+ new_page_options = tmp_page_options,
2155+ first_page = false) {
2156+ update_page_options (&header, new_page_options);
2157+#ifdef DEBUG
2158+ if (debug) {
2159+ fprintf (stderr, "DEBUG: pixel_xfer = %d\n", job_options->pixel_xfer);
2160+ fprintf (stderr, "DEBUG: print_quality_high = %d\n", job_options->print_quality_high);
2161+ fprintf (stderr, "DEBUG: half_cut = %d\n", job_options->half_cut);
2162+ fprintf (stderr, "DEBUG: bytes_per_line = %d\n", job_options->bytes_per_line);
2163+ fprintf (stderr, "DEBUG: align = %d\n", job_options->align);
2164+ fprintf (stderr, "DEBUG: software_mirror = %d\n", job_options->software_mirror);
2165+ fprintf (stderr, "DEBUG: label_preamble = %d\n", job_options->label_preamble);
2166+ fprintf (stderr, "DEBUG: print_density = %d\n", job_options->print_density);
2167+ fprintf (stderr, "DEBUG: xfer_mode = %d\n", job_options->xfer_mode);
2168+ fprintf (stderr, "DEBUG: concat_pages = %d\n", job_options->concat_pages);
2169+ fprintf (stderr, "DEBUG: cut_media = %d\n", new_page_options->cut_media);
2170+ fprintf (stderr, "DEBUG: mirror = %d\n", new_page_options->mirror);
2171+ fprintf (stderr, "DEBUG: roll_fed_media = %d\n", new_page_options->roll_fed_media);
2172+ fprintf (stderr, "DEBUG: resolution = %d x %d\n", new_page_options->resolution [0], new_page_options->resolution [1]);
2173+ fprintf (stderr, "DEBUG: page_size = %d x %d\n", new_page_options->page_size [0], new_page_options->page_size [1]);
2174+ fprintf (stderr, "DEBUG: image_height = %d\n", new_page_options->image_height);
2175+ fprintf (stderr, "DEBUG: feed = %d\n", new_page_options->feed);
2176+ fprintf (stderr, "DEBUG: perform_feed = %d\n", new_page_options->perform_feed);
2177+ fprintf (stderr, "DEBUG: header->ImagingBoundingBox = [%u, %u, %u, %u]\n",
2178+ header.ImagingBoundingBox [0], header.ImagingBoundingBox [1],
2179+ header.ImagingBoundingBox [2], header.ImagingBoundingBox [3]);
2180+ fprintf (stderr, "DEBUG: header.Margins = [%u, %u]\n",
2181+ header.Margins [0], header.Margins [1]);
2182+ }
2183+#endif
2184+ page_prepare (header.cupsBytesPerLine, bytes_per_line);
2185+ if (first_page) {
2186+ emit_job_cmds (job_options);
2187+ emit_page_cmds (job_options, old_page_options,
2188+ new_page_options, first_page);
2189+ }
2190+ emit_raster_lines (page, job_options, new_page_options, ras, &header);
2191+ unsigned char xormask = (header.NegativePrint ? ~0 : 0);
2192+ /* Determine whether this is the last page (fetch next) */
2193+ more_pages = cupsRasterReadHeader (ras, &header);
2194+ /* Do feeding or ejecting at the end of each page. */
2195+ cups_adv_t perform_feed = new_page_options->perform_feed;
2196+ if (more_pages) {
2197+ if (!job_options->concat_pages) {
2198+ RLE_store_empty_lines
2199+ (job_options, page_options, empty_lines, xormask);
2200+ empty_lines = 0;
2201+ flush_rle_buffer (job_options, page_options);
2202+ if (perform_feed == CUPS_ADVANCE_PAGE)
2203+ putchar (PTC_EJECT); /* Emit eject marker to force feed */
2204+ else
2205+ putchar (PTC_FORMFEED); /* Emit page end marker without feed */
2206+ }
2207+ } else {
2208+ if (!job_options->concat_pages) {
2209+ RLE_store_empty_lines
2210+ (job_options, page_options, empty_lines, xormask);
2211+ empty_lines = 0;
2212+ flush_rle_buffer (job_options, page_options);
2213+ putchar (PTC_FORMFEED);
2214+ } else {
2215+ double scale_pt2ypixels = header.HWResolution [1] / 72.0;
2216+ unsigned bot_empty_lines
2217+ = lrint (header.ImagingBoundingBox [1] * scale_pt2ypixels);
2218+ empty_lines = bot_empty_lines;
2219+ RLE_store_empty_lines
2220+ (job_options, page_options, empty_lines, xormask);
2221+ empty_lines = 0;
2222+ flush_rle_buffer (job_options, page_options);
2223+ }
2224+
2225+ /* If special feed or cut at job end, emit commands to that effect */
2226+ cups_cut_t cut_media = new_page_options->cut_media;
2227+ if (perform_feed == CUPS_ADVANCE_JOB || cut_media == CUPS_CUT_JOB) {
2228+ emit_feed_cut_mirror
2229+ (perform_feed == CUPS_ADVANCE_PAGE ||
2230+ perform_feed == CUPS_ADVANCE_JOB,
2231+ new_page_options->feed,
2232+ cut_media == CUPS_CUT_PAGE || cut_media == CUPS_CUT_JOB,
2233+ new_page_options->mirror == CUPS_TRUE);
2234+ /* Emit eject marker */
2235+ putchar (PTC_EJECT);
2236+ }
2237+ }
2238+ page_end ();
2239+ /* Emit page count according to CUPS requirements */
2240+ fprintf (stderr, "PAGE: %d 1\n", page);
2241+ page++;
2242+ }
2243+ return 0;
2244+}
2245+/**
2246+ * Main entry function.
2247+ * @param argc number of command line arguments plus one
2248+ * @param argv command line arguments
2249+ * @return 0 if success, nonzero otherwise
2250+ */
2251+int
2252+main (int argc, const char* argv []) {
2253+ error_occurred = 0;
2254+#ifdef DEBUG
2255+ int i;
2256+ if (argc > 5)
2257+ if (strcasestr (argv [5], "debug") == argv [5]
2258+ || strcasestr (argv [5], " debug") != NULL)
2259+ debug = true;
2260+ struct tms time_start, time_end;
2261+ if (debug) {
2262+ fprintf (stderr, "DEBUG: args = ");
2263+ for (i = 0; i < argc; i++) fprintf (stderr, "%d:'%s' ", i, argv [i]);
2264+ fprintf (stderr, "\nDEBUG: environment =\n");
2265+ char** envvarbind;
2266+ for (envvarbind = environ; *envvarbind; envvarbind++)
2267+ fprintf (stderr, "DEBUG: %s\n", *envvarbind);
2268+ times (&time_start);
2269+ }
2270+#endif
2271+
2272+ job_options_t job_options = parse_options (argc, argv);
2273+
2274+ int fd = open_input_file (argc, argv);
2275+
2276+ int rv = process_rasterdata (fd, &job_options);
2277+
2278+#ifdef DEBUG
2279+ if (debug) {
2280+ times (&time_end);
2281+ fprintf (stderr, "DEBUG: User time System time (usec)\n");
2282+ fprintf (stderr, "DEBUG: %9.3g %9.3g\n",
2283+ (time_end.tms_utime - time_start.tms_utime)
2284+ * 1000000.0 / CLOCKS_PER_SEC,
2285+ (time_end.tms_stime - time_start.tms_stime)
2286+ * 1000000.0 / CLOCKS_PER_SEC);
2287+ fprintf (stderr, "DEBUG: Emitted lines: %u\n", emitted_lines);
2288+ }
2289+#endif
2290+
2291+ if (fd != 0) close (fd);
2292+
2293+ if (error_occurred) return error_occurred; else return rv;
2294+}
2295
2296=== removed directory '.pc/send-esc-i-A-for-QL-only.patch'
2297=== removed file '.pc/send-esc-i-A-for-QL-only.patch/rastertoptch.c'
2298--- .pc/send-esc-i-A-for-QL-only.patch/rastertoptch.c 2014-03-06 16:23:54 +0000
2299+++ .pc/send-esc-i-A-for-QL-only.patch/rastertoptch.c 1970-01-01 00:00:00 +0000
2300@@ -1,1590 +0,0 @@
2301-/* rastertoptch is a filter to convert CUPS raster data into a Brother
2302- * P-touch label printer command byte stream.
2303- *
2304- * Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
2305- *
2306- * This file is part of ptouch-driver
2307- *
2308- * ptouch-driver is free software; you can redistribute it and/or modify
2309- * it under the terms of the GNU General Public License as published by
2310- * the Free Software Foundation; either version 2 of the License, or
2311- * (at your option) any later version.
2312- *
2313- * ptouch-driver is distributed in the hope that it will be useful,
2314- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2315- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2316- * GNU General Public License for more details.
2317- *
2318- * You should have received a copy of the GNU General Public License
2319- * along with ptouch-driver; if not, write to the Free Software
2320- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2321- *
2322- *
2323- * Please note: This software is not in any way related to Brother
2324- * Industries, Ltd., except that it is intended for use with their
2325- * products. Any comments to this software should NOT be directed to
2326- * Brother Industries, Ltd.
2327- */
2328-
2329-/** @file
2330- * This filter processes CUPS raster data, converting it into a byte
2331- * stream on stdout suitable for sending directly to a label printer
2332- * of the Brother P-touch family.
2333- *
2334- * @version 1.2
2335- * @author Arne John Glenstrup <panic@itu.dk>
2336- * @date 2006
2337-
2338- * <h2>Invocation</h2>
2339- * The filter is invoked thus:
2340- *
2341- * rastertoptch job user title copies options [filename]
2342- *
2343- * @param printer The name of the printer queue (ignored)
2344- * @param job The numeric job ID (ignored)
2345- * @param user The string from the originating-user-name (ignored)
2346- * @param title The string from the job-name attribute (ignored)
2347- * @param copies The number of copies to be printed (ignored)
2348- * @param options String representations of the job template
2349- * parameters, separated by spaces. Boolean attributes
2350- * are provided as "name" for true values and "noname"
2351- * for false values. All other attributes are provided
2352- * as "name=value" for single-valued attributes and
2353- * "name=value1,value2,...,valueN" for set attributes
2354- * @param filename The request file (if omitted, read from stdin)
2355- *
2356- * Available options (default values in [brackets]):
2357- *
2358- * @param PixelXfer=ULP|RLE|BIP Use uncompressed line printing (ULP),
2359- * run-length encoding (RLE) or bit
2360- * image printing (BIP) when emitting
2361- * pixel data [ULP]
2362- * @param PrintQuality=High|Fast Use high quality or fast printing [High]
2363- * @param HalfCut Perform half-cut (crack & peel) when
2364- * cutting [noHalfCut]
2365- * @param BytesPerLine=N Emit N bytes per line [90]
2366- * @param Align=Right|Center Pixel data alignment on tape [Right]
2367- * @param PrintDensity=1|...|5 Print density level: 1=light, 5=dark
2368- * @param ConcatPages Output all pages in one page [noConcatPages]
2369- * @param RLEMemMax Maximum memory used for RLE buffer [1000000]
2370- * @param SoftwareMirror Make the filter mirror pixel data
2371- * if MirrorPrint is requested [noSoftwareMirror]
2372- * @param LabelPreamble Emit preamble containing print quality,
2373- * roll/label type, tape width, label height,
2374- * and pixel lines [noLabelPreamble]
2375- * @param Debug Emit diagnostic output to stderr [noDebug]
2376- * (only if compiled with DEBUG set)
2377- *
2378- * Information about media type, resolution, mirror print, negative
2379- * print, cut media, advance distance (feed) is extracted from the
2380- * CUPS raster page headers given in the input stream. The MediaType
2381- * page header field can be either "roll" or "labels" for continuous
2382- * tape or pre-cut labels, respectively.
2383- *
2384- * LabelPreamble should usually not be used for the PT series printers.
2385- *
2386- * <h2>Output</h2>
2387- * Each invocation of this filter is one job, containing a number of
2388- * pages, each page containing a number of lines, each line consisting
2389- * of a number of pixel bytes.
2390- *
2391- * Output consists of job-related printer initialisation commands,
2392- * followed by a number of pages, each page consisting of page-related
2393- * commands, followed by raster line data. Each page is followed by a
2394- * finish page or (after the final page) finish job command.
2395- *
2396- * The following printer command language, printer, and tape
2397- * information has been deduced from many sources, but is not official
2398- * Brother documentation and may thus contain errors. Please send any
2399- * corrections based on actual experience with these printers to the
2400- * maintainer.
2401- *
2402- * <h3>Job-related commands</h3>
2403- * <table>
2404- * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
2405- * <tr><td>ESC @ (1b 40)</td>
2406- <td>Initialise</td><td>Clear print buffer</td></tr>
2407- * <tr><td>ESC i D # (1b 69 44 ##)
2408- * <td>Set print density</td>
2409- * <td>bit 0-3: 0=no change, 1-5=density level</td></tr>
2410- * <tr><td>ESC i K # (1b 69 4b ##)
2411- * <td>Set half cut</td>
2412- * <td>bit 2: 0=full cut, 1=half cut</td></tr>
2413- * <tr><td>ESC i R ## (1b 69 52 ##)</td>
2414- * <td>Set transfer mode</td>
2415- * <td>##: ?: 1=?</td></tr>
2416- * <tr><td>M ## (4d ##)</td>
2417- * <td>Set compression</td>
2418- * <td>##: Compression type: 2=RLE</td></tr>
2419- * </table>
2420- *
2421- * <h3>Page-related commands</h3>
2422- * <table>
2423- * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
2424- * <tr><td>ESC i c #1 #2 #3 NUL #4 <br>(1b 63 #1 #2 #3 00 #4)
2425- * <td>Set width & resolution</td>
2426- * <td>360x360DPI: #1 #2 #4 = 0x84 0x00 0x00<br>
2427- * 360x720DPI: #1 #2 #4 = 0x86 0x09 0x01<br>
2428- * #3: Tape width in mm</td></tr>
2429- * <tr><td>ESC i M # <br>(1b 69 4d ##)</td>
2430- * <td>Set mode</td>
2431- * <td>bit 0-4: Feed amount (default=large): 0-7=none, 8-11=small,
2432- * 12-25=medium, 26-31=large<br>
2433- * bit 6: Auto cut/cut mark (default=on): 0=off, 1=on<br>
2434- * bit 7: Mirror print (default=off): 0=off, 1=on.
2435- * (note that it seems that QL devices do not reverse the
2436- * data stream themselves, but rely on the driver doing
2437- * it!)</td></tr>
2438- * <tr><td>ESC i z #1 #2 #3 #4 #5 #6 NUL NUL NUL NUL<br>
2439- * (1b 69 7a #1 #2 #3 #4 #5 #6 00 00 00 00)</td>
2440- * <td>Set media & quality</td>
2441- * <td>#1, bit 6: Print quality: 0=fast, 1=high<br>
2442- * #2, bit 0: Media type: 0=continuous roll,
2443- * 1=pre-cut labels<br>
2444- * #3: Tape width in mm<br>
2445- * #4: Label height in mm (0 for continuous roll)<br>
2446- * #5 #6: Page consists of N=#5+256*#6 pixel lines</td></tr>
2447- * <tr><td>ESC i d #1 #2 <br>(1b 69 64 #1 #2)</td>
2448- * <td>Set margin</td>
2449- * <td>Set size of right(?) margin to N=#1+256*#2 pixels</td></tr>
2450- * <tr><td>FF (0c)</td>
2451- * <td>Form feed</td>
2452- * <td>Print buffer data without ejecting.</td></tr>
2453- * <tr><td>SUB (1a)</td>
2454- * <td>Eject</td>
2455- * <td>Print buffer data and ejects.</td></tr>
2456- * </table>
2457- *
2458- * <h3>Line-related commands</h3>
2459- * <table>
2460- * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
2461- * <tr><td>G #1 #2 ...data... <br>(47 #1 #2 ...data...)</td>
2462- * <td>Send raster line</td>
2463- * <td>data consists of
2464- * N=#1+256*#2 bytes of RLE compressed raster data.
2465- * </td></tr>
2466- * <tr><td>Z (5a)</td>
2467- * <td>Advance tape</td><td>Print 1 empty line</td></tr>
2468- * <tr><td>g #1 #2 ...data... <br>(67 #1 #2 ...data...)</td>
2469- * <td>Send raster line</td>
2470- * <td>data consists of
2471- * N=#2 bytes of uncompressed raster data.</td></tr>
2472- * <tr><td>ESC * ' #1 #2 ...data... <br>(1b 2a 27 #1 #2 ...data...)</td>
2473- * <td>Bit image printing (BIP)</td>
2474- * <td>Print N=#1+256*#2 lines of 24 pixels; data consists of 3*N
2475- * bytes</td></tr>
2476- * </table>
2477- *
2478- * <h3>Compressed-data-related commands (RLE)</h3>
2479- * <table>
2480- * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
2481- * <tr><td>#1 ...data...</td>
2482- * <td>#1 >= 0: Print uncompressed</td>
2483- * <td>data consists of 1+#1 uncompressed bytes</td></tr>
2484- * <tr><td>#1 #2</td>
2485- * <td>#1 < 0: Print compressed</td>
2486- * <td>#2 should be printed 1-#1 times</td></tr>
2487- * </table>
2488- * #1 is represented as a 2-complement signed integer.
2489- *
2490- * <h2>Printer model characteristics</h2>
2491- * The following table lists for each model what kind of cutter it has
2492- * (manual, auto, half cut), what kind of pixel data transfer mode it
2493- * requires, its resolution, number of print head pixels, number of
2494- * bytes of pixel data that must be transmitted per line (regardless
2495- * of actual tape width!), and what kinds of tape it can take.
2496- *
2497- * For PC models, pixel data must be centered, so narrow tapes require
2498- * padding raster data with zero bits on each side. For QL models,
2499- * labels are left-aligned, so pixel data must be right aligned, so
2500- * narrow tapes require padding raster data with zero bits at the end.
2501- *
2502- * For PC-PT, only the central 24 pixels (= 3,4mm!) can be used for
2503- * pixel-based graphics. It might be possible to print several strips
2504- * of 24 pixels side-by side by issuing CR and line-positioning
2505- * commands. That is currently not supported, let alone attempted,
2506- * with this driver.
2507- *
2508- * <table>
2509- * <tr><th>Model <th>Cutter <th>Xfer<th>DPI<th>Pixels<th>Bytes<th>Tape
2510- * <tr><td>QL-500 <td>manual <td>ULP<td>300<td>720<td>90<td>DK12-62mm
2511- * <tr><td>QL-550 <td>auto <td>ULP<td>300<td>720<td>90<td>DK12-62mm
2512- * <tr><td>QL-650TD <td>auto <td>ULP<td>300<td>720<td>90<td>DK12-62mm
2513- * <tr><td>PT-PC <td>auto <td>BIP<td>180<td>128<td> 3<td>TZ6-24mm
2514- * <tr><td>PT-18R <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-18mm
2515- * <tr><td>PT-550A <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-36mm
2516- * <tr><td>PT-1500PC<td>manual <td>RLE<td>180<td>112<td>14<td>TZ6-24mm
2517- * <tr><td>PT-1950 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-18mm
2518- * <tr><td>PT-1950VP<td>auto <td>RLE<td>180<td>112<td>14<td>TZ6-18mm
2519- * <tr><td>PT-1960 <td>auto <td>RLE<td>180<td> 96<td>12<td>TZ6-18mm
2520- * <tr><td>PT-2300 <td>auto <td>RLE<td>180<td>112<td>14<td>TZ6-18mm
2521- * <tr><td>PT-2420PC<td>manual <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
2522- * <tr><td>PT-2450DX<td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
2523- * <tr><td>PT-2500PC<td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
2524- * <tr><td>PT-2600 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ,AV6-24mm
2525- * <tr><td>PT-2610 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ,AV6-24mm
2526- * <tr><td>PT-3600 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ,AV6-36mm
2527- * <tr><td>PT-9200DX<td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
2528- * <tr><td>PT-9200PC<td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
2529- * <tr><td>PT-9400 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
2530- * <tr><td>PT-9500PC<td>auto/half<td>RLE<td>360<br>
2531- 360x720<td>384<td>48<td>TZ,AV6-36mm
2532- * <tr><td>PT-9600 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ,AV6-36mm
2533- * </table>
2534- *
2535- * <h2>Tape characteristics</h2>
2536- * <table>
2537- * <tr><th>Tape width
2538- * <th colspan=2>Print area <th>Margins</th><th>DPI</th></tr>
2539- * <tr><td>62mm<td>61.0mm<td>720pixels</td><td>0.5mm</td><td>300</td></tr>
2540- * <tr><td>36mm<td>27.1mm<td>384pixels</td><td>4.5mm</td><td>360</td></tr>
2541- * <tr><td>24mm<td>18.0mm<td>128pixels</td><td>3mm</td><td>180</td></tr>
2542- * <tr><td>18mm<td>12.0mm<td> 85pixels</td><td>3mm</td><td>180</td></tr>
2543- * <tr><td>12mm<td> 8.0mm<td> 57pixels</td><td>2mm</td><td>180</td></tr>
2544- * <tr><td> 9mm<td> 6.9mm<td> 49pixels</td><td>1mm</td><td>180</td></tr>
2545- * <tr><td> 6mm<td> 3.9mm<td> 28pixels</td><td>1mm</td><td>180</td></tr>
2546- * </table>
2547- *
2548- * <h2>Notes</h2>
2549- * - Pixels bytes sent are printed from right to left, with bit 7
2550- * rightmost!
2551- * - Bit image printing (BIP) using "ESC * ' #1 #2 ...data..."
2552- * probably only works for the PT-PC model.
2553- * - QL Printer documentation might state that the print area is less
2554- * than 61mm, which is probably to ensure that printed pixels stay
2555- * within the tape even if it is not precisely positioned. The
2556- * print head really IS 720 pixels.
2557- */
2558-/** Default pixel transfer method */
2559-#define PIXEL_XFER_DEFAULT RLE
2560-/** Default print quality */
2561-#define PRINT_QUALITY_HIGH_DEFAULT true
2562-/** Default half cut mode */
2563-#define HALF_CUT_DEFAULT false
2564-/** Maximum number of bytes per line */
2565-#define BYTES_PER_LINE_MAX 255 /* cf. ULP_emit_line */
2566-/** Default number of bytes per line */
2567-#define BYTES_PER_LINE_DEFAULT 90
2568-/** Default pixel data alignment on narrow tapes */
2569-#define ALIGN_DEFAULT RIGHT
2570-/** Maximum print density value */
2571-#define PRINT_DENSITY_MAX 5
2572-/** Default print density value (1: light, ..., 5:dark, 0: no change) */
2573-#define PRINT_DENSITY_DEFAULT 0
2574-/** Transfer mode default ??? (-1 = don't set) */
2575-#define TRANSFER_MODE_DEFAULT -1
2576-/** Driver pixel data mirroring default */
2577-#define SOFTWARE_MIRROR_DEFAULT false
2578-/** Label preamble emitting default */
2579-#define LABEL_PREAMBLE_DEFAULT false
2580-/** Interlabel margin removal default */
2581-#define CONCAT_PAGES_DEFAULT false
2582-/** RLE buffer maximum memory usage */
2583-#define RLE_ALLOC_MAX_DEFAULT 1000000
2584-/** Mirror printing default */
2585-#define MIRROR_DEFAULT false
2586-/** Negative printing default */
2587-#define NEGATIVE_DEFAULT false
2588-/** Cut media mode default */
2589-#define CUT_MEDIA_DEFAULT CUPS_CUT_NONE
2590-/** Roll fed media default */
2591-#define ROLL_FED_MEDIA_DEFAULT true
2592-/** Device resolution default in DPI */
2593-#define RESOLUTION_DEFAULT { 300, 300 }
2594-/** Page size default in PostScript points */
2595-#define PAGE_SIZE_DEFAULT { 176, 142 } /* 62x50mm */
2596-/** Image size default in pixels */
2597-#define IMAGE_HEIGHT_DEFAULT 0
2598-/** Feed amount default */
2599-#define FEED_DEFAULT 0
2600-/** When to perform feed default */
2601-#define PERFORM_FEED_DEFAULT CUPS_ADVANCE_NONE
2602-
2603-#include <config.h>
2604-#include <stdio.h>
2605-#include <unistd.h>
2606-#include <limits.h>
2607-#include <stdlib.h>
2608-#include <string.h>
2609-#include <errno.h>
2610-#include <fcntl.h>
2611-#include <signal.h>
2612-#include <math.h>
2613-#include <cups/raster.h>
2614-#include <cups/cups.h>
2615-
2616-#if STDC_HEADERS
2617-# include <string.h>
2618-#else
2619-# if !HAVE_MEMCPY
2620-# define memcpy(d, s, n) bcopy ((s), (d), (n))
2621-# endif
2622-#endif
2623-#if HAVE_STDBOOL_H
2624-# include <stdbool.h>
2625-#else
2626-# if ! HAVE__BOOL
2627-# ifdef __cplusplus
2628-typedef bool _Bool;
2629-# else
2630-typedef unsigned char _Bool;
2631-# endif
2632-# endif
2633-# define bool _Bool
2634-# define false 0
2635-# define true 1
2636-# define __bool_true_false_are_defined 1
2637-#endif
2638-
2639-
2640-
2641-#ifdef DEBUG
2642-#include <sys/times.h>
2643-/** Debug flag */
2644-int debug = 0;
2645-/** Number of emitted lines */
2646-unsigned emitted_lines = 0;
2647-#endif
2648-
2649-/** Length of a PostScript point in mm */
2650-#define MM_PER_PT (25.4 / 72.0)
2651-/** Printer code: Eject */
2652-#define PTC_EJECT 0x1a
2653-/** Printer code: Form feed */
2654-#define PTC_FORMFEED 0x0c
2655-
2656-/** ASCII escape value */
2657-#define ESC 0x1b
2658-
2659-/**
2660- * Pixel transfer mode type.
2661- */
2662-typedef enum {
2663- ULP, /**< Uncompressed line printing */
2664- RLE, /**< Run-length encoding */
2665- BIP, /**< Bit image printing */
2666-} xfer_t;
2667-
2668-/**
2669- * Pixel data alignment type.
2670- */
2671-typedef enum {RIGHT, CENTER} align_t;
2672-
2673-/** Flag signalling whether any errors were encountered. */
2674-int error_occurred;
2675-
2676-/** CUPS Raster line buffer. */
2677-unsigned char* buffer;
2678-/** Buffer holding line data to emit to the printer. */
2679-unsigned char* emit_line_buffer;
2680-/** Buffer holding RLE line data to emit to the printer. */
2681-unsigned char* rle_buffer = NULL;
2682-/** Pointer to first free pos in rle_buffer. */
2683-unsigned char* rle_buffer_next = NULL;
2684-/** Size of rle_buffer. */
2685-unsigned long rle_alloced = 0;
2686-/** Number of empty lines (input data only zeros) waiting to be stored */
2687-int empty_lines = 0;
2688-/** Number of pixel lines waiting to be emitted. */
2689-unsigned lines_waiting = 0;
2690-/** Threshold for flushing waiting lines to printer. */
2691-unsigned max_lines_waiting = INT_MAX;
2692-
2693-/** Macro for obtaining integer option values. */
2694-#define OBTAIN_INT_OPTION(name, var, min, max) \
2695- cups_option \
2696- = cupsGetOption (name, num_options, cups_options); \
2697- if (cups_option) { \
2698- errno = 0; \
2699- char* rest; \
2700- long int var = strtol (cups_option, &rest, 0); \
2701- if (errno || *rest != '\0' || rest == cups_option \
2702- || var < min || var > max) { \
2703- fprintf (stderr, "ERROR: " name " '%s', " \
2704- "must be an integer N, where %ld <= N <= %ld\n", \
2705- cups_option, (long) min, (long) max); \
2706- error_occurred = 1; \
2707- } else \
2708- options.var = var; \
2709- }
2710-
2711-/** Macro for obtaining boolean option values. */
2712-#define OBTAIN_BOOL_OPTION(name, var) \
2713- cups_option \
2714- = cupsGetOption (name, num_options, cups_options); \
2715- if (cups_option) options.var = true; \
2716- cups_option \
2717- = cupsGetOption ("no"name, num_options, cups_options); \
2718- if (cups_option) options.var = false; \
2719-
2720-/**
2721- * Struct type for holding all the job options.
2722- */
2723-typedef struct {
2724- xfer_t pixel_xfer; /**< pixel transfer mode */
2725- cups_bool_t print_quality_high; /**< print quality is high */
2726- bool half_cut; /**< half cut */
2727- int bytes_per_line; /**< bytes per line (print head width) */
2728- align_t align; /**< pixel data alignment */
2729- int software_mirror; /**< mirror pixel data if mirror printing */
2730- int print_density; /**< printing density (0=don't change) */
2731- int xfer_mode; /**< transfer mode ??? */
2732- int label_preamble; /**< emit ESC i z ... */
2733- bool concat_pages; /**< remove interlabel margins */
2734- unsigned long rle_alloc_max; /**< max bytes used for rle_buffer */
2735-} job_options_t;
2736-
2737-/**
2738- * Struct type for holding current page options.
2739- */
2740-typedef struct {
2741- cups_cut_t cut_media; /**< cut media mode */
2742- cups_bool_t mirror; /**< mirror printing */
2743- bool roll_fed_media; /**< continuous (not labels) roll media */
2744- unsigned resolution [2]; /**< horiz & vertical resolution in DPI */
2745- unsigned page_size [2]; /**< width & height of page in points */
2746- unsigned image_height; /**< height of page image in pixels */
2747- unsigned feed; /**< feed size in points */
2748- cups_adv_t perform_feed; /**< When to feed */
2749-} page_options_t;
2750-
2751-/**
2752- * Parse options given in command line argument 5.
2753- * @param argc number of command line arguments plus one
2754- * @param argv command line arguments
2755- * @return options, where each option set to its default value if
2756- * not specified in argv [5]
2757- */
2758-job_options_t
2759-parse_options (int argc, const char* argv []) {
2760- job_options_t options = {
2761- PIXEL_XFER_DEFAULT,
2762- PRINT_QUALITY_HIGH_DEFAULT,
2763- HALF_CUT_DEFAULT,
2764- BYTES_PER_LINE_DEFAULT,
2765- ALIGN_DEFAULT,
2766- SOFTWARE_MIRROR_DEFAULT,
2767- PRINT_DENSITY_DEFAULT,
2768- TRANSFER_MODE_DEFAULT,
2769- LABEL_PREAMBLE_DEFAULT,
2770- CONCAT_PAGES_DEFAULT,
2771- RLE_ALLOC_MAX_DEFAULT,
2772- };
2773- if (argc < 6) return options;
2774- int num_options = 0;
2775- cups_option_t* cups_options = NULL;
2776- num_options
2777- = cupsParseOptions (argv [5], num_options, &cups_options);
2778- const char* cups_option
2779- = cupsGetOption ("PixelXfer", num_options, cups_options);
2780- if (cups_option) {
2781- if (strcasecmp (cups_option, "ULP") == 0)
2782- options.pixel_xfer = ULP;
2783- else if (strcasecmp (cups_option, "RLE") == 0)
2784- options.pixel_xfer = RLE;
2785- else if (strcasecmp (cups_option, "BIP") == 0)
2786- options.pixel_xfer = BIP;
2787- else {
2788- fprintf (stderr, "ERROR: Unknown PicelXfer '%s', "
2789- "must be RLE, BIP or ULP\n", cups_option);
2790- error_occurred = 1;
2791- }
2792- }
2793- cups_option
2794- = cupsGetOption ("PrintQuality", num_options, cups_options);
2795- if (cups_option) {
2796- if (strcasecmp (cups_option, "High") == 0)
2797- options.print_quality_high = true;
2798- else if (strcasecmp (cups_option, "Fast") == 0)
2799- options.print_quality_high = false;
2800- else {
2801- fprintf (stderr, "ERROR: Unknown PrintQuality '%s', "
2802- "must be High or Fast\n", cups_option);
2803- error_occurred = 1;
2804- }
2805- }
2806- OBTAIN_BOOL_OPTION ("HalfCut", half_cut);
2807- OBTAIN_INT_OPTION ("BytesPerLine", bytes_per_line,
2808- 1, BYTES_PER_LINE_MAX);
2809- cups_option
2810- = cupsGetOption ("Align", num_options, cups_options);
2811- if (cups_option) {
2812- if (strcasecmp (cups_option, "Right") == 0)
2813- options.align = RIGHT;
2814- else if (strcasecmp (cups_option, "Center") == 0)
2815- options.align = CENTER;
2816- else {
2817- fprintf (stderr, "ERROR: Unknown Align '%s', "
2818- "must be Right or Center\n", cups_option);
2819- error_occurred = 1;
2820- }
2821- }
2822- OBTAIN_INT_OPTION ("PrintDensity", print_density,
2823- 0, PRINT_DENSITY_MAX);
2824- OBTAIN_BOOL_OPTION ("ConcatPages", concat_pages);
2825- OBTAIN_INT_OPTION ("RLEMemMax", rle_alloc_max, 0, LONG_MAX);
2826- OBTAIN_INT_OPTION ("TransferMode", xfer_mode, 0, 255);
2827- OBTAIN_BOOL_OPTION ("SoftwareMirror", software_mirror);
2828- OBTAIN_BOOL_OPTION ("LabelPreamble", label_preamble);
2829- /* Release memory allocated for CUPS options struct */
2830- cupsFreeOptions (num_options, cups_options);
2831- return options;
2832-}
2833-
2834-/**
2835- * Determine input stream and open it. If there are 6 command line
2836- * arguments, argv[6] is taken to be the input file name
2837- * otherwise stdin is used. This funtion exits the program on error.
2838- * @param argc number of command line arguments plus one
2839- * @param argv command line arguments
2840- * @return file descriptor for the opened input stream
2841- */
2842-int
2843-open_input_file (int argc, const char* argv []) {
2844- int fd;
2845- if (argc == 7) {
2846- if ((fd = open (argv[6], O_RDONLY)) < 0) {
2847- perror ("ERROR: Unable to open raster file - ");
2848- sleep (1);
2849- exit (1);
2850- }
2851- } else
2852- fd = 0;
2853- return fd;
2854-}
2855-
2856-/**
2857- * Update page_options with information found in header.
2858- * @param header CUPS page header
2859- * @param page_options page options to be updated
2860- */
2861-void
2862-update_page_options (cups_page_header_t* header,
2863- page_options_t* page_options) {
2864- page_options->cut_media = header->CutMedia;
2865- page_options->mirror = header->MirrorPrint;
2866- const char* media_type = header->MediaType;
2867- page_options->roll_fed_media /* Default is continuous roll */
2868- = (strcasecmp ("Labels", media_type) != 0);
2869- page_options->resolution [0] = header->HWResolution [0];
2870- page_options->resolution [1] = header->HWResolution [1];
2871- page_options->page_size [0] = header->PageSize [0];
2872- page_options->page_size [1] = header->PageSize [1];
2873- page_options->image_height = header->cupsHeight;
2874- page_options->feed = header->AdvanceDistance;
2875- page_options->perform_feed = header->AdvanceMedia;
2876-}
2877-
2878-void cancel_job (int signal);
2879-/**
2880- * Prepare for a new page by setting up signalling infrastructure and
2881- * memory allocation.
2882- * @param cups_buffer_size Required size of CUPS raster line buffer
2883- * @param device_buffer_size Required size of device pixel line buffer
2884- */
2885-void
2886-page_prepare (unsigned cups_buffer_size, unsigned device_buffer_size) {
2887- /* Set up signalling to handle print job cancelling */
2888-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
2889- struct sigaction action;
2890-#endif
2891-
2892-#ifdef HAVE_SIGSET
2893- sigset (SIGTERM, cancel_job);
2894-#elif defined(HAVE_SIGACTION)
2895- memset (&action, 0, sizeof (action));
2896- sigemptyset (&action.sa_mask);
2897- action.sa_handler = cancel_job;
2898- sigaction (SIGTERM, &action, NULL);
2899-#else
2900- signal (SIGTERM, cancel_job);
2901-#endif
2902-
2903- /* Allocate line buffer */
2904- buffer = malloc (cups_buffer_size);
2905- emit_line_buffer = malloc (device_buffer_size);
2906- if (!buffer || !emit_line_buffer) {
2907- fprintf
2908- (stderr,
2909- "ERROR: Cannot allocate memory for raster line buffer\n");
2910- exit (1);
2911- }
2912-}
2913-
2914-/**
2915- * Clean up signalling and memory after emitting a page
2916-*/
2917-void
2918-page_end () {
2919-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
2920- struct sigaction action;
2921-#endif
2922-
2923-#ifdef HAVE_SIGSET
2924- sigset (SIGTERM, SIG_IGN);
2925-#elif defined(HAVE_SIGACTION)
2926- memset (&action, 0, sizeof (action));
2927- sigemptyset (&action.sa_mask);
2928- action.sa_handler = SIG_IGN;
2929- sigaction (SIGTERM, &action, NULL);
2930-#else
2931- signal (SIGTERM, SIG_IGN);
2932-#endif
2933- /* Release line buffer memory */
2934- free (buffer);
2935- free (emit_line_buffer);
2936-}
2937-
2938-/**
2939- * Cancel print job.
2940- */
2941-void
2942-cancel_job (int signal) {
2943- /* Emit page end & eject marker */
2944- putchar (PTC_EJECT);
2945- page_end ();
2946- if (rle_buffer) free (rle_buffer);
2947- exit (0);
2948-}
2949-
2950-/**
2951- * Emit printer command codes at start of print job.
2952- * This function does not emit P-touch page specific codes.
2953- * @param job_options Job options
2954- */
2955-void
2956-emit_job_cmds (job_options_t* job_options) {
2957- /* Initialise printer */
2958- putchar (ESC); putchar ('@');
2959- /* Emit print density selection command if required */
2960- int density = job_options->print_density;
2961- switch (density) {
2962- case 1: case 2: case 3: case 4: case 5:
2963- putchar (ESC); putchar ('i'); putchar ('D'); putchar (density);
2964- break;
2965- default: break;
2966- }
2967- /* Emit transfer mode selection command if required */
2968- int xfer_mode = job_options->xfer_mode;
2969- if (xfer_mode >= 0 && xfer_mode < 0x100) {
2970- putchar (ESC); putchar ('i'); putchar ('R'); putchar (xfer_mode);
2971- }
2972- /* Emit half cut selection command if required */
2973- if (job_options->half_cut) {
2974- putchar (ESC); putchar ('i'); putchar ('K'); putchar (0x04);
2975- }
2976-}
2977-
2978-/**
2979- * Emit feed, cut and mirror command codes.
2980- * @param do_feed Emit codes to actually feed
2981- * @param feed Feed size
2982- * @param do_cut Emit codes to actually cut
2983- * @param do_mirror Emit codes to mirror print
2984- */
2985-inline void
2986-emit_feed_cut_mirror (bool do_feed, unsigned feed,
2987- bool do_cut,
2988- bool do_mirror) {
2989- /* Determine feed nibble */
2990- unsigned feed_nibble;
2991- if (do_feed) {
2992- feed_nibble = lrint (feed / 2.6 + 2.4); /* one suggested conversion */
2993- if (feed_nibble > 31) feed_nibble = 31;
2994- } else
2995- feed_nibble = 0;
2996- /* Determine auto cut bit - we only handle after each page */
2997- unsigned char auto_cut_bit = do_cut ? 0x40 : 0x00;
2998- /* Determine mirror print bit*/
2999- unsigned char mirror_bit = do_mirror ? 0x80 : 0x00;
3000- /* Combine & emit printer command code */
3001- putchar (ESC); putchar ('i'); putchar ('M');
3002- putchar ((char) (feed & 0x1f) | auto_cut_bit | mirror_bit);
3003-}
3004-
3005-/**
3006- * Emit quality, roll fed media, and label size command codes.
3007- * @param job_options Current job options
3008- * @param page_options Current page options
3009- * @param page_size_y Page size (height) in pt
3010- * @param image_height_px Number of pixel lines in current page
3011- */
3012-void
3013-emit_quality_rollfed_size (job_options_t* job_options,
3014- page_options_t* page_options,
3015- unsigned page_size_y,
3016- unsigned image_height_px) {
3017- bool roll_fed_media = page_options->roll_fed_media;
3018- /* Determine print quality bit */
3019- unsigned char print_quality_bit
3020- = (job_options->print_quality_high == CUPS_TRUE) ? 0x40 : 0x00;
3021- unsigned char roll_fed_media_bit = roll_fed_media ? 0x00 : 0x01;
3022- /* Get tape width in mm */
3023- int tape_width_mm = lrint (page_options->page_size [0] * MM_PER_PT);
3024- if (tape_width_mm > 0xff) {
3025- fprintf (stderr,
3026- "ERROR: Page width (%umm) exceeds 255mm\n",
3027- tape_width_mm);
3028- tape_width_mm = 0xff;
3029- }
3030- /* Get tape height in mm */
3031- unsigned tape_height_mm;
3032- if (roll_fed_media)
3033- tape_height_mm = 0;
3034- else
3035- tape_height_mm = lrint (page_size_y * MM_PER_PT);
3036- if (tape_height_mm > 0xff) {
3037- fprintf (stderr,
3038- "ERROR: Page height (%umm) exceeds 255mm; use continuous tape (MediaType=roll)\n",
3039- tape_height_mm);
3040- tape_height_mm = 0xff;
3041- }
3042- /* Combine & emit printer command code */
3043- putchar (ESC); putchar ('i'); putchar ('z');
3044- putchar (print_quality_bit); putchar (roll_fed_media_bit);
3045- putchar (tape_width_mm & 0xff); putchar (tape_height_mm & 0xff);
3046- putchar (image_height_px & 0xff);
3047- putchar ((image_height_px >> 8) & 0xff);
3048- putchar (0x00); putchar (0x00); putchar (0x00); putchar (0x00);
3049-}
3050-/**
3051- * Emit printer command codes at start of page for options that have
3052- * changed.
3053- * @param job_options Job options
3054- * @param old_page_options Page options for preceding page
3055- * @param new_page_options Page options for page to be printed
3056- * @param force Ignore old_page_options and emit commands
3057- * for selecting all options in new_page_options
3058- */
3059-void
3060-emit_page_cmds (job_options_t* job_options,
3061- page_options_t* old_page_options,
3062- page_options_t* new_page_options,
3063- bool force) {
3064- int tape_width_mm = -1;
3065-
3066- /* Set width and resolution */
3067- unsigned hres = new_page_options->resolution [0];
3068- unsigned vres = new_page_options->resolution [1];
3069- unsigned old_page_size_x = old_page_options->page_size [0];
3070- unsigned new_page_size_x = new_page_options->page_size [0];
3071- if (force
3072- || hres != old_page_options->resolution [0]
3073- || vres != old_page_options->resolution [1]
3074- || new_page_size_x != old_page_size_x)
3075- /* We only know how to select 360x360DPI or 360x720DPI */
3076- if (hres == 360 && (vres == 360 || vres == 720)) {
3077- /* Get tape width in mm */
3078- tape_width_mm = lrint (new_page_size_x * MM_PER_PT);
3079- if (tape_width_mm > 0xff) {
3080- fprintf (stderr,
3081- "ERROR: Page width (%umm) exceeds 255mm\n",
3082- tape_width_mm);
3083- tape_width_mm = 0xff;
3084- }
3085- /* Emit printer commands */
3086- putchar (ESC); putchar ('i'); putchar ('c');
3087- if (vres == 360) {
3088- putchar (0x84); putchar (0x00); putchar (tape_width_mm & 0xff);
3089- putchar (0x00); putchar (0x00);
3090- } else {
3091- putchar (0x86); putchar (0x09); putchar (tape_width_mm & 0xff);
3092- putchar (0x00); putchar (0x01);
3093- }
3094- }
3095-
3096- /* Set feed, auto cut and mirror print */
3097- unsigned feed = new_page_options->feed;
3098- cups_adv_t perform_feed = new_page_options->perform_feed;
3099- cups_cut_t cut_media = new_page_options->cut_media;
3100- cups_bool_t mirror = new_page_options->mirror;
3101- if (force
3102- || feed != old_page_options->feed
3103- || perform_feed != old_page_options->perform_feed
3104- || cut_media != old_page_options->cut_media
3105- || mirror != old_page_options->mirror)
3106- /* We only know how to feed after each page */
3107- emit_feed_cut_mirror (perform_feed == CUPS_ADVANCE_PAGE, feed,
3108- cut_media == CUPS_CUT_PAGE,
3109- mirror == CUPS_TRUE);
3110- /* Set media and quality if label preamble is requested */
3111- unsigned page_size_y = new_page_options->page_size [1];
3112- unsigned image_height_px = lrint (page_size_y * vres / 72.0);
3113- if (job_options->label_preamble && !job_options->concat_pages
3114- && (force
3115- || (new_page_options->roll_fed_media
3116- != old_page_options->roll_fed_media)
3117- || new_page_size_x != old_page_size_x
3118- || page_size_y != old_page_options->page_size [1]))
3119- emit_quality_rollfed_size (job_options, new_page_options,
3120- page_size_y, image_height_px);
3121-
3122- /* WHY DON'T WE SET MARGIN (ESC i d ...)? */
3123-
3124- /* Set pixel data transfer compression */
3125- if (force) {
3126- if (job_options->pixel_xfer == RLE) {
3127- putchar ('M'); putchar (0x02);
3128- }
3129- }
3130- /* Emit number of raster lines to follow if using BIP */
3131- if (job_options->pixel_xfer == BIP) {
3132- unsigned image_height_px = lrint (page_size_y * vres / 72.0);
3133- putchar (ESC); putchar (0x2a); putchar (0x27);
3134- putchar (image_height_px & 0xff);
3135- putchar ((image_height_px >> 8) & 0xff);
3136- }
3137-}
3138-
3139-/** mirror [i] = bit mirror image of i.
3140- * I.e., (mirror [i] >> j) & 1 == (i >> (7 - j)) & 1 for 0 <= j <= 7
3141- */
3142-const unsigned char mirror [0x100] = {
3143- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
3144- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
3145- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
3146- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
3147- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
3148- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
3149- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
3150- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
3151- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
3152- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
3153- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
3154- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
3155- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
3156- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
3157- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
3158- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
3159- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
3160- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
3161- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
3162- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
3163- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
3164- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
3165- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
3166- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
3167- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
3168- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
3169- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
3170- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
3171- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
3172- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
3173- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
3174- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
3175-};
3176-
3177-/**
3178- * Generate a buffer of pixel data ready to emit.
3179- * Requirement: buflen + right_padding_bytes
3180- * + (shift > 0 ? 1 : 0) <= bytes_per_line
3181- * @param in_buffer Buffer containing raster data in
3182- * left-to-right order
3183- * @param out_buffer Buffer for returning generated line in
3184- * right-to-left order; must be
3185- * bytes_per_line long
3186- * @param buflen in_buffer length
3187- * @param bytes_per_line Number of pixel bytes to generate
3188- * @param right_padding_bytes Number of zero bytes to pad
3189- * with to the right of pixels
3190- * @param shift Number of bits to shift left
3191- * If do_mirror is false and shift < 0
3192- * Then shift right -shift bits
3193- * @param do_mirror Mirror in_buffer pixel data
3194- * @param xormask The XOR mask for negative printing
3195- * @return 0 if entire line is empty (zeros)
3196- * nonzero if line contains nonzero pixels
3197- */
3198-inline int
3199-generate_emit_line (unsigned char* in_buffer,
3200- unsigned char* out_buffer,
3201- int buflen,
3202- unsigned char bytes_per_line,
3203- int right_padding_bytes,
3204- int shift,
3205- int do_mirror,
3206- unsigned char xormask) {
3207-#ifdef DEBUG
3208- if (debug)
3209- fprintf (stderr, "DEBUG: generate_emit_line "
3210- "(in_buffer=%0x, out_buffer=%0x, "
3211- "buflen=%d, bytes_per_line=%d, right_padding_bytes=%d, "
3212- "shift=%d, do_mirror=%d, xormask=%0x)\n",
3213- in_buffer, out_buffer, buflen, bytes_per_line,
3214- right_padding_bytes, shift, do_mirror, xormask);
3215-#endif
3216- /* Generate right padding zero bytes */
3217- memset (out_buffer, xormask, right_padding_bytes);
3218- unsigned int nonzero = 0;
3219- int j = right_padding_bytes;
3220- /* Copy pixel data from in_buffer to out_buffer, */
3221- /* shifted and mirrored if required */
3222- unsigned int box = 0; /* Box for shifting pixel data left */
3223- int i;
3224- if (do_mirror)
3225- if (shift) {
3226- for (i = 0; i < buflen; i++) {
3227- unsigned int data = in_buffer [i]; nonzero |= data;
3228- box |= data << shift;
3229- out_buffer [j++] = (box & 0xff) ^ xormask;
3230- box >>= 8;
3231- }
3232- out_buffer [j++] = box & 0xff;
3233- } else
3234- for (i = 0; i < buflen; i++) {
3235- unsigned char data = in_buffer [i]; nonzero |= data;
3236- out_buffer [j++] = data ^ xormask;
3237- }
3238- else
3239- if (shift) {
3240- if (buflen > 0) {
3241- if (shift < 0) {
3242- box = in_buffer [buflen - 1] >> -shift; nonzero |= box;
3243- shift += 8;
3244- } else {
3245- box = in_buffer [buflen - 1] << shift; nonzero |= box;
3246- out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
3247- box >>= 8;
3248- }
3249- for (i = buflen - 2; i >= 0; i--) {
3250- unsigned data = in_buffer [i]; nonzero |= data;
3251- box |= data << shift;
3252- out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
3253- box >>= 8;
3254- }
3255- out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
3256- }
3257- } else
3258- for (i = buflen - 1; i >= 0; i--) {
3259- unsigned char data = in_buffer [i]; nonzero |= data;
3260- out_buffer [j++] = (mirror [data]) ^ xormask;
3261- }
3262- /* Generate left padding bytes */
3263- memset (out_buffer + j, xormask, bytes_per_line - j);
3264- return nonzero != 0;
3265-}
3266-
3267-/**
3268- * Emit lines waiting in RLE buffer.
3269- * Resets global variable rle_buffer_next to rle_buffer,
3270- * and lines_waiting to zero.
3271- * @param job_options Job options
3272- * @param page_options Page options
3273- */
3274-inline void
3275-flush_rle_buffer (job_options_t* job_options,
3276- page_options_t* page_options) {
3277-#ifdef DEBUG
3278- if (debug)
3279- fprintf (stderr, "DEBUG: flush_rle_buffer (): "
3280- "lines_waiting = %d\n",
3281- lines_waiting);
3282-#endif
3283- if (lines_waiting > 0) {
3284- if (job_options->label_preamble)
3285- emit_quality_rollfed_size (job_options, page_options,
3286- page_options->page_size [1],
3287- lines_waiting);
3288- xfer_t pixel_xfer = job_options->pixel_xfer;
3289- int bytes_per_line = job_options->bytes_per_line;
3290- switch (pixel_xfer) {
3291- case RLE: {
3292- size_t dummy
3293- = fwrite (rle_buffer, sizeof (char), rle_buffer_next - rle_buffer, stdout);
3294- break;
3295- }
3296- case ULP:
3297- case BIP: {
3298- unsigned char* p = rle_buffer;
3299- unsigned emitted_lines = 0;
3300- while (rle_buffer_next - p > 0) {
3301- if (pixel_xfer == ULP) {
3302- putchar ('g'); putchar (0x00); putchar (bytes_per_line);
3303- }
3304- int emitted = 0;
3305- int linelen;
3306- switch (*p++) {
3307- case 'G':
3308- linelen = *p++;
3309- linelen += ((int)(*p++)) << 8;
3310- while (linelen > 0) {
3311- signed char l = *p++; linelen--;
3312- if (l < 0) { /* emit repeated data */
3313- char data = *p++; linelen--;
3314- emitted -= l; emitted++;
3315- for (; l <= 0; l++) putchar (data);
3316- } else { /* emit the l + 1 following bytes of data */
3317- size_t dummy = fwrite (p, sizeof (char), l + 1, stdout);
3318- p += l; p++;
3319- linelen -= l; linelen--;
3320- emitted += l; emitted++;
3321- }
3322- }
3323- if (emitted > bytes_per_line)
3324- fprintf (stderr,
3325- "ERROR: Emitted %d > %d bytes for one pixel line!\n",
3326- emitted, bytes_per_line);
3327- /* No break; fall through to next case: */
3328- case 'Z':
3329- for (; emitted < bytes_per_line; emitted++) putchar (0x00);
3330- break;
3331- default:
3332- fprintf (stderr, "ERROR: Unknown RLE flag at %p: '0x%02x'\n",
3333- p - 1, (int)*(p - 1));
3334- }
3335- emitted_lines++;
3336- }
3337-#ifdef DEBUG
3338- if (debug)
3339- fprintf (stderr, "DEBUG: emitted %d lines\n", emitted_lines);
3340-#endif
3341- break;
3342- }
3343- default:
3344- fprintf (stderr, "ERROR: Unknown pixel transfer mode: '%d'\n",
3345- pixel_xfer);
3346- }
3347- rle_buffer_next = rle_buffer;
3348- lines_waiting = 0;
3349- }
3350-}
3351-
3352-/**
3353- * Ensure sufficient memory available in rle buffer.
3354- * If rle buffer needs to be extended, global variables rle_buffer and
3355- * rle_buffer_next might be altered.
3356- * @param job_options Job options
3357- * @param page_options Page options
3358- * @param bytes Number of bytes required.
3359- */
3360-inline void
3361-ensure_rle_buf_space (job_options_t* job_options,
3362- page_options_t* page_options,
3363- unsigned bytes) {
3364- unsigned long nextpos = rle_buffer_next - rle_buffer;
3365- if (nextpos + bytes > rle_alloced) {
3366- /* Exponential size increase avoids too frequent reallocation */
3367- unsigned long new_alloced = rle_alloced * 2 + 0x4000;
3368-#ifdef DEBUG
3369- if (debug)
3370- fprintf (stderr, "DEBUG: ensure_rle_buf_space (bytes=%d): "
3371- "increasing rle_buffer from %d to %d\n",
3372- bytes,
3373- rle_alloced * sizeof (char),
3374- new_alloced * sizeof (char));
3375-#endif
3376- void* p = NULL;
3377- if (new_alloced <= job_options->rle_alloc_max) {
3378- if (rle_buffer)
3379- p = (unsigned char*) realloc (rle_buffer, new_alloced * sizeof (char));
3380- else
3381- p = (unsigned char*) malloc (new_alloced * sizeof (char));
3382- }
3383- if (p) {
3384- rle_buffer = p;
3385- rle_buffer_next = rle_buffer + nextpos;
3386- rle_alloced = new_alloced;
3387- } else { /* Gain memory by flushing buffer to printer */
3388- flush_rle_buffer (job_options, page_options);
3389- if (rle_buffer_next - rle_buffer + bytes > rle_alloced) {
3390- fprintf (stderr,
3391- "ERROR: Out of memory when attempting to increase RLE "
3392- "buffer from %ld to %ld bytes\n",
3393- rle_alloced * sizeof (char),
3394- new_alloced * sizeof (char));
3395- exit (-1);
3396- }
3397- }
3398- }
3399-}
3400-
3401-/** @def APPEND_MIXED_BYTES
3402- * Macro for appending mixed-bytes run to rle_buffer */
3403-/** @def APPEND_REPEATED_BYTE
3404- * Macro for appending repeated-byte run to rle_buffer */
3405-/**
3406- * Store buffer data in rle buffer using run-length encoding.
3407- * @param job_options Job options
3408- * @param page_options Page options
3409- * @param buf Buffer containing data to store
3410- * @param buf_len Length of buffer
3411- *
3412- * Global variable rle_buffer_next is a pointer into buffer for holding RLE data.
3413- * Must have room for at least 3 + buf_len + buf_len/128 + 1
3414- * bytes (ensured by reallocation).
3415- * On return, rle_buffer_next points to first unused buffer byte.
3416- *
3417- * This implementation enjoys the property that
3418- * the resulting RLE is at most buf_len + buf_len/128 + 1 bytes
3419- * long, because:
3420- * # a repeated-byte run has a repeat factor of at least 3
3421- * # two mixed-bytes runs never follow directly after each other,
3422- * unless the first one is 128 bytes long
3423- * The first property ensures that a repeated-run output sequence is
3424- * always at least 1 byte shorter than the input sequence it
3425- * represents. This combined with the second property means that only
3426- * - a terminating mixed-bytes run, and
3427- * - a mixed-bytes run of 128 bytes
3428- * can cause the RLE representation to be longer (by 1 byte) than the
3429- * corresponding input sequence in buf.
3430- */
3431-inline void
3432-RLE_store_line (job_options_t* job_options,
3433- page_options_t* page_options,
3434- const unsigned char* buf, unsigned buf_len) {
3435- ensure_rle_buf_space (job_options, page_options,
3436- 4 + buf_len + buf_len / 128);
3437- unsigned char* rle_next = rle_buffer_next + 3;
3438- /* Make room for 3 initial meta data bytes, */
3439- /* written when actual length is known */
3440- const unsigned char* buf_end = buf + buf_len; /* Buffer end */
3441- const unsigned char* mix_start; /* Start of mixed bytes run */
3442-
3443- const unsigned char* rep_start; /* End + 1 of mixed bytes run,
3444- and start of repeated byte run */
3445- const unsigned char* next; /* Next byte pointer,
3446- and end + 1 of repeated byte run */
3447- unsigned char next_val; /* Next byte value to consider */
3448- unsigned char rep_val; /* Repeated byte value */
3449- unsigned char nonzero = 0; /* OR of all buffer bytes */
3450-
3451-#define APPEND_MIXED_BYTES \
3452- if (mix_len > 128) mix_len = 128; \
3453- *rle_next++ = mix_len - 1; \
3454- memcpy (rle_next, mix_start, mix_len); \
3455- rle_next += mix_len;
3456-#define APPEND_REPEATED_BYTE \
3457- unsigned rep_len = next - rep_start; \
3458- *rle_next++ = (signed char)(1 - rep_len); \
3459- *rle_next++ = rep_val;
3460-
3461- for (mix_start = rep_start = next = buf, rep_val = next_val = *next;
3462- next != buf_end;
3463- next++, next_val = *next) {
3464- /* Loop invariants at this point:
3465- * 1) [mix_start..rep_start - 1] contains mixed bytes waiting
3466- * to be appended to rle_buffer,
3467- * 2) [rep_start..next - 1] contains repeats of rep_val
3468- * waiting to be appended to rle_buffer
3469- * 3) If next - rep_start > 2 then mix_start == rep_start
3470- * 4) next - rep_start <= 129
3471- * 5) rep_start - mix_start < 128
3472- * 6) [rle_buffer_next..rle_next - 1] = RLE ([buf..mix_start - 1])
3473- * 7) rep_val = *rep_start
3474- * 8) next_val = *next
3475- */
3476- nonzero |= next_val;
3477- if (next - rep_start >= 129) {
3478- /* RLE cannot represent repeated runs longer than 129 bytes */
3479- APPEND_REPEATED_BYTE;
3480- rep_start += rep_len;
3481- rep_val = *rep_start;
3482- mix_start = rep_start;
3483- }
3484- if (next_val == rep_val) { /* Run of repeated byte values */
3485- if (next - rep_start == 2) {
3486- unsigned mix_len = rep_start - mix_start;
3487- if (mix_len > 0) {
3488- APPEND_MIXED_BYTES;
3489- mix_start = rep_start;
3490- }
3491- }
3492- } else {
3493- if (next - rep_start > 2) { /* End of repeated run found */
3494- APPEND_REPEATED_BYTE;
3495- mix_start = next;
3496- }
3497- rep_start = next;
3498- rep_val = next_val;
3499- unsigned mix_len = rep_start - mix_start;
3500- if (mix_len >= 128) {
3501- /* RLE cannot represent mixed runs longer than 128 bytes */
3502- APPEND_MIXED_BYTES;
3503- mix_start += mix_len;
3504- }
3505- }
3506- }
3507- /* Handle final bytes */
3508- if (next - rep_start > 2) { /* Handle final repeated byte run */
3509- APPEND_REPEATED_BYTE;
3510- mix_start = next;
3511- }
3512- rep_start = next;
3513- unsigned mix_len = rep_start - mix_start;
3514- if (mix_len > 0) { /* Handle any remaining final mixed run */
3515- APPEND_MIXED_BYTES;
3516- mix_start += mix_len;
3517- }
3518- mix_len = rep_start - mix_start;
3519- if (mix_len > 0) { /* Case where final mixed run is 129 bytes */
3520- APPEND_MIXED_BYTES;
3521- }
3522- unsigned rle_len = rle_next - rle_buffer_next - 3;
3523- /* Store rle line meta data (length and (non)zero status) */
3524- if (nonzero) { /* Check for nonempty (no black pixels) line */
3525- rle_buffer_next [0] = 'G';
3526- rle_buffer_next [1] = rle_len & 0xff;
3527- rle_buffer_next [2] = (rle_len >> 8) & 0xff;
3528- rle_buffer_next = rle_next;
3529- } else {
3530- rle_buffer_next [0] = 'Z';
3531- rle_buffer_next++;
3532- }
3533- lines_waiting++;
3534- if (lines_waiting >= max_lines_waiting)
3535- flush_rle_buffer (job_options, page_options);
3536-}
3537-
3538-/**
3539- * Store a number of empty lines in rle_buffer using RLE.
3540- * @param job_options Job options
3541- * @param page_options Page options
3542- * @param empty_lines Number of empty lines to store
3543- * @param xormask The XOR mask for negative printing
3544- */
3545-inline void
3546-RLE_store_empty_lines (job_options_t* job_options,
3547- page_options_t* page_options,
3548- int empty_lines,
3549- unsigned char xormask) {
3550- int bytes_per_line = job_options->bytes_per_line;
3551-#ifdef DEBUG
3552- if (debug)
3553- fprintf (stderr, "DEBUG: RLE_store_empty_lines (empty_lines=%d, "
3554- "bytes_per_line=%d): lines_waiting = %d\n",
3555- empty_lines, bytes_per_line, lines_waiting);
3556-#endif
3557- lines_waiting += empty_lines;
3558- if (xormask) {
3559- int blocks = (bytes_per_line + 127) / 128;
3560- ensure_rle_buf_space (job_options, page_options,
3561- empty_lines * blocks);
3562- for (; empty_lines--; ) {
3563- *(rle_buffer_next++) = 'G';
3564- *(rle_buffer_next++) = 0x02;
3565- *(rle_buffer_next++) = 0x00;
3566- int rep_len;
3567- for (; bytes_per_line > 0; bytes_per_line -= rep_len) {
3568- rep_len = bytes_per_line;
3569- if (rep_len > 128) rep_len = 128;
3570- *(rle_buffer_next++) = (signed char) (1 - rep_len);
3571- *(rle_buffer_next++) = xormask;
3572- }
3573- }
3574- } else {
3575- ensure_rle_buf_space (job_options, page_options, empty_lines);
3576- for (; empty_lines--; ) *(rle_buffer_next++) = 'Z';
3577- }
3578-}
3579-
3580-/**
3581- * Emit raster lines for current page.
3582- * @param page Page number of page to be emitted
3583- * @param job_options Job options
3584- * @param page_options Page options
3585- * @param ras Raster data stream
3586- * @param header Current page header
3587- * @return 0 on success, nonzero otherwise
3588- */
3589-int
3590-emit_raster_lines (int page,
3591- job_options_t* job_options,
3592- page_options_t* page_options,
3593- cups_raster_t* ras,
3594- cups_page_header_t* header) {
3595- unsigned char xormask = (header->NegativePrint ? ~0 : 0);
3596- /* Determine whether we need to mirror the pixel data */
3597- int do_mirror = job_options->software_mirror && page_options->mirror;
3598-
3599- unsigned cupsBytesPerLine = header->cupsBytesPerLine;
3600- unsigned cupsHeight = header->cupsHeight;
3601- unsigned cupsWidth = header->cupsWidth;
3602- int bytes_per_line = job_options->bytes_per_line;
3603- unsigned buflen = cupsBytesPerLine;
3604- /* Make sure buflen can be written as a byte */
3605- if (buflen > 0xff) buflen = 0xff;
3606- /* Truncate buflen if greater than bytes_per_line */
3607- if (buflen >= bytes_per_line) buflen = bytes_per_line;
3608- /* Calculate extra horizontal spacing pixels if the right side of */
3609- /* ImagingBoundingBox doesn't touch the PageSize box */
3610- double scale_pt2xpixels = header->HWResolution [0] / 72.0;
3611- unsigned right_spacing_px = 0;
3612- if (header->ImagingBoundingBox [2] != 0) {
3613- unsigned right_distance_pt
3614- = header->PageSize [0] - header->ImagingBoundingBox [2];
3615- if (right_distance_pt != 0)
3616- right_spacing_px = right_distance_pt * scale_pt2xpixels;
3617- }
3618- /* Calculate right_padding_bytes and shift */
3619- int right_padding_bits;
3620- if (job_options->align == CENTER) {
3621- unsigned left_spacing_px = 0;
3622- if (header->ImagingBoundingBox [0] != 0)
3623- left_spacing_px
3624- = header->ImagingBoundingBox [0] * scale_pt2xpixels;
3625- right_padding_bits
3626- = (bytes_per_line * 8
3627- - (left_spacing_px + cupsWidth + right_spacing_px)) / 2
3628- + right_spacing_px;
3629- if (right_padding_bits < 0) right_padding_bits = 0;
3630- } else
3631- right_padding_bits = right_spacing_px;
3632- int right_padding_bytes = right_padding_bits / 8;
3633- int shift = right_padding_bits % 8;
3634- /* If width is not an integral number of bytes, we must shift */
3635- /* right if we don't mirror, to ensure printing starts leftmost */
3636- if (!do_mirror) shift -= (8 - cupsWidth % 8) % 8;
3637- int shift_positive = (shift > 0 ? 1 : 0);
3638- /* We cannot allow buffer+padding to exceed device width */
3639- if (buflen + right_padding_bytes + shift_positive > bytes_per_line) {
3640-#ifdef DEBUG
3641- if (debug) {
3642- fprintf (stderr, "DEBUG: Warning: buflen = %d, right_padding_bytes = %d, "
3643- "shift = %d, bytes_per_line = %d\n",
3644- buflen, right_padding_bytes, shift, bytes_per_line);
3645- }
3646-#endif
3647- /* We cannot allow padding to exceed device width */
3648- if (right_padding_bytes + shift_positive > bytes_per_line)
3649- right_padding_bytes = bytes_per_line - shift_positive;
3650- /* Truncate buffer to fit device width */
3651- buflen = bytes_per_line - right_padding_bytes - shift_positive;
3652- }
3653- /* Percentage of page emitted */
3654- int completed = -1;
3655- /* Generate and store empty lines if the top of ImagingBoundingBox */
3656- /* doesn't touch the PageSize box */
3657- double scale_pt2ypixels = header->HWResolution [1] / 72.0;
3658- unsigned top_empty_lines = 0;
3659- unsigned page_size_y = header->PageSize [1];
3660- if (header->ImagingBoundingBox [3] != 0
3661- && (!job_options->concat_pages || page == 1)) {
3662- unsigned top_distance_pt
3663- = page_size_y - header->ImagingBoundingBox [3];
3664- if (top_distance_pt != 0) {
3665- top_empty_lines = lrint (top_distance_pt * scale_pt2ypixels);
3666- empty_lines += top_empty_lines;
3667- }
3668- }
3669- /* Generate and store actual page data */
3670- int y;
3671- for (y = 0; y < cupsHeight; y++) {
3672- /* Feedback to the user */
3673- if ((y & 0x1f) == 0) {
3674- int now_completed = 100 * y / cupsHeight;
3675- if (now_completed > completed) {
3676- completed = now_completed;
3677- fprintf (stderr,
3678- "INFO: Printing page %d, %d%% complete...\n",
3679- page, completed);
3680- fflush (stderr);
3681- }
3682- }
3683- /* Read one line of pixels */
3684- if (cupsRasterReadPixels (ras, buffer, cupsBytesPerLine) < 1)
3685- break; /* Escape if no pixels read */
3686- bool nonempty_line =
3687- generate_emit_line (buffer, emit_line_buffer, buflen, bytes_per_line,
3688- right_padding_bytes, shift, do_mirror, xormask);
3689- if (nonempty_line) {
3690- if (empty_lines) {
3691- RLE_store_empty_lines
3692- (job_options, page_options, empty_lines, xormask);
3693- empty_lines = 0;
3694- }
3695- RLE_store_line (job_options, page_options,
3696- emit_line_buffer, bytes_per_line);
3697- } else
3698- empty_lines++;
3699- }
3700-
3701- unsigned image_height_px = lrint (page_size_y * scale_pt2ypixels);
3702- unsigned bot_empty_lines;
3703- if (image_height_px >= top_empty_lines + y)
3704- bot_empty_lines = image_height_px - top_empty_lines - y;
3705- else
3706- bot_empty_lines = 0;
3707- if (bot_empty_lines != 0 && !job_options->concat_pages)
3708- empty_lines += bot_empty_lines;
3709- fprintf (stderr,
3710- "INFO: Printing page %d, 100%% complete.\n",
3711- page);
3712- fflush (stderr);
3713- return 0;
3714-}
3715-/**
3716- * Process CUPS raster data from input file, emitting printer data on
3717- * stdout.
3718- * @param fd File descriptor for input file
3719- * @param job_options Pointer to print options
3720- * @return 0 on success, nonzero otherwise
3721- */
3722-int
3723-process_rasterdata (int fd, job_options_t* job_options) {
3724- int page = 1; /* Page number */
3725- cups_raster_t* ras; /* Raster stream for printing */
3726- cups_page_header_t header; /* Current page header */
3727- int first_page = true; /* Is this the first page? */
3728- int more_pages; /* Are there more pages left? */
3729- int bytes_per_line = job_options->bytes_per_line;
3730- page_options_t page_options [2] = {{
3731- CUT_MEDIA_DEFAULT,
3732- MIRROR_DEFAULT,
3733- ROLL_FED_MEDIA_DEFAULT,
3734- RESOLUTION_DEFAULT,
3735- PAGE_SIZE_DEFAULT,
3736- IMAGE_HEIGHT_DEFAULT,
3737- FEED_DEFAULT,
3738- PERFORM_FEED_DEFAULT,}
3739- }; /* Current & preceding page opts */
3740- page_options_t* new_page_options
3741- = page_options + 0; /* Options for current page */
3742- page_options_t* old_page_options
3743- = page_options + 1; /* Options for preceding page */
3744- page_options_t* tmp_page_options;/* Temp variable for swapping */
3745- ras = cupsRasterOpen (fd, CUPS_RASTER_READ);
3746- for (more_pages = cupsRasterReadHeader (ras, &header);
3747- more_pages;
3748- tmp_page_options = old_page_options,
3749- old_page_options = new_page_options,
3750- new_page_options = tmp_page_options,
3751- first_page = false) {
3752- update_page_options (&header, new_page_options);
3753-#ifdef DEBUG
3754- if (debug) {
3755- fprintf (stderr, "DEBUG: pixel_xfer = %d\n", job_options->pixel_xfer);
3756- fprintf (stderr, "DEBUG: print_quality_high = %d\n", job_options->print_quality_high);
3757- fprintf (stderr, "DEBUG: half_cut = %d\n", job_options->half_cut);
3758- fprintf (stderr, "DEBUG: bytes_per_line = %d\n", job_options->bytes_per_line);
3759- fprintf (stderr, "DEBUG: align = %d\n", job_options->align);
3760- fprintf (stderr, "DEBUG: software_mirror = %d\n", job_options->software_mirror);
3761- fprintf (stderr, "DEBUG: label_preamble = %d\n", job_options->label_preamble);
3762- fprintf (stderr, "DEBUG: print_density = %d\n", job_options->print_density);
3763- fprintf (stderr, "DEBUG: xfer_mode = %d\n", job_options->xfer_mode);
3764- fprintf (stderr, "DEBUG: concat_pages = %d\n", job_options->concat_pages);
3765- fprintf (stderr, "DEBUG: cut_media = %d\n", new_page_options->cut_media);
3766- fprintf (stderr, "DEBUG: mirror = %d\n", new_page_options->mirror);
3767- fprintf (stderr, "DEBUG: roll_fed_media = %d\n", new_page_options->roll_fed_media);
3768- fprintf (stderr, "DEBUG: resolution = %d x %d\n", new_page_options->resolution [0], new_page_options->resolution [1]);
3769- fprintf (stderr, "DEBUG: page_size = %d x %d\n", new_page_options->page_size [0], new_page_options->page_size [1]);
3770- fprintf (stderr, "DEBUG: image_height = %d\n", new_page_options->image_height);
3771- fprintf (stderr, "DEBUG: feed = %d\n", new_page_options->feed);
3772- fprintf (stderr, "DEBUG: perform_feed = %d\n", new_page_options->perform_feed);
3773- fprintf (stderr, "DEBUG: header->ImagingBoundingBox = [%u, %u, %u, %u]\n",
3774- header.ImagingBoundingBox [0], header.ImagingBoundingBox [1],
3775- header.ImagingBoundingBox [2], header.ImagingBoundingBox [3]);
3776- fprintf (stderr, "DEBUG: header.Margins = [%u, %u]\n",
3777- header.Margins [0], header.Margins [1]);
3778- }
3779-#endif
3780- page_prepare (header.cupsBytesPerLine, bytes_per_line);
3781- if (first_page) {
3782- emit_job_cmds (job_options);
3783- emit_page_cmds (job_options, old_page_options,
3784- new_page_options, first_page);
3785- }
3786- emit_raster_lines (page, job_options, new_page_options, ras, &header);
3787- unsigned char xormask = (header.NegativePrint ? ~0 : 0);
3788- /* Determine whether this is the last page (fetch next) */
3789- more_pages = cupsRasterReadHeader (ras, &header);
3790- /* Do feeding or ejecting at the end of each page. */
3791- cups_adv_t perform_feed = new_page_options->perform_feed;
3792- if (more_pages) {
3793- if (!job_options->concat_pages) {
3794- RLE_store_empty_lines
3795- (job_options, page_options, empty_lines, xormask);
3796- empty_lines = 0;
3797- flush_rle_buffer (job_options, page_options);
3798- if (perform_feed == CUPS_ADVANCE_PAGE)
3799- putchar (PTC_EJECT); /* Emit eject marker to force feed */
3800- else
3801- putchar (PTC_FORMFEED); /* Emit page end marker without feed */
3802- }
3803- } else {
3804- if (!job_options->concat_pages) {
3805- RLE_store_empty_lines
3806- (job_options, page_options, empty_lines, xormask);
3807- empty_lines = 0;
3808- flush_rle_buffer (job_options, page_options);
3809- putchar (PTC_FORMFEED);
3810- } else {
3811- double scale_pt2ypixels = header.HWResolution [1] / 72.0;
3812- unsigned bot_empty_lines
3813- = lrint (header.ImagingBoundingBox [1] * scale_pt2ypixels);
3814- empty_lines = bot_empty_lines;
3815- RLE_store_empty_lines
3816- (job_options, page_options, empty_lines, xormask);
3817- empty_lines = 0;
3818- flush_rle_buffer (job_options, page_options);
3819- }
3820-
3821- /* If special feed or cut at job end, emit commands to that effect */
3822- cups_cut_t cut_media = new_page_options->cut_media;
3823- if (perform_feed == CUPS_ADVANCE_JOB || cut_media == CUPS_CUT_JOB) {
3824- emit_feed_cut_mirror
3825- (perform_feed == CUPS_ADVANCE_PAGE ||
3826- perform_feed == CUPS_ADVANCE_JOB,
3827- new_page_options->feed,
3828- cut_media == CUPS_CUT_PAGE || cut_media == CUPS_CUT_JOB,
3829- new_page_options->mirror == CUPS_TRUE);
3830- /* Emit eject marker */
3831- putchar (PTC_EJECT);
3832- }
3833- }
3834- page_end ();
3835- /* Emit page count according to CUPS requirements */
3836- fprintf (stderr, "PAGE: %d 1\n", page);
3837- page++;
3838- }
3839- return 0;
3840-}
3841-/**
3842- * Main entry function.
3843- * @param argc number of command line arguments plus one
3844- * @param argv command line arguments
3845- * @return 0 if success, nonzero otherwise
3846- */
3847-int
3848-main (int argc, const char* argv []) {
3849- error_occurred = 0;
3850-#ifdef DEBUG
3851- int i;
3852- if (argc > 5)
3853- if (strcasestr (argv [5], "debug") == argv [5]
3854- || strcasestr (argv [5], " debug") != NULL)
3855- debug = true;
3856- struct tms time_start, time_end;
3857- if (debug) {
3858- fprintf (stderr, "DEBUG: args = ");
3859- for (i = 0; i < argc; i++) fprintf (stderr, "%d:'%s' ", i, argv [i]);
3860- fprintf (stderr, "\nDEBUG: environment =\n");
3861- char** envvarbind;
3862- for (envvarbind = environ; *envvarbind; envvarbind++)
3863- fprintf (stderr, "DEBUG: %s\n", *envvarbind);
3864- times (&time_start);
3865- }
3866-#endif
3867-
3868- job_options_t job_options = parse_options (argc, argv);
3869-
3870- int fd = open_input_file (argc, argv);
3871-
3872- int rv = process_rasterdata (fd, &job_options);
3873-
3874-#ifdef DEBUG
3875- if (debug) {
3876- times (&time_end);
3877- fprintf (stderr, "DEBUG: User time System time (usec)\n");
3878- fprintf (stderr, "DEBUG: %9.3g %9.3g\n",
3879- (time_end.tms_utime - time_start.tms_utime)
3880- * 1000000.0 / CLOCKS_PER_SEC,
3881- (time_end.tms_stime - time_start.tms_stime)
3882- * 1000000.0 / CLOCKS_PER_SEC);
3883- fprintf (stderr, "DEBUG: Emitted lines: %u\n", emitted_lines);
3884- }
3885-#endif
3886-
3887- if (fd != 0) close (fd);
3888-
3889- if (error_occurred) return error_occurred; else return rv;
3890-}
3891
3892=== modified file 'Makefile.am'
3893--- Makefile.am 2009-11-11 17:14:44 +0000
3894+++ Makefile.am 2015-04-10 21:18:54 +0000
3895@@ -47,7 +47,6 @@
3896 printer/Brother-PT-9500PC.xml \
3897 printer/Brother-PT-9600.xml \
3898 opt/Brother-Ptouch-AdvanceDistance.xml \
3899- opt/Brother-Ptouch-AdvanceMedia.xml \
3900 opt/Brother-Ptouch-Align.xml \
3901 opt/Brother-Ptouch-BytesPerLine.xml \
3902 opt/Brother-Ptouch-ConcatPages.xml \
3903
3904=== modified file 'debian/changelog'
3905--- debian/changelog 2014-03-06 16:23:54 +0000
3906+++ debian/changelog 2015-04-10 21:18:54 +0000
3907@@ -1,3 +1,10 @@
3908+ptouch-driver (1.3-8ubuntu1) unstable; urgency=medium
3909+
3910+ * Fix the "ESC i A" (enable cutter) command patch to correctly send only on
3911+ printers which support it. (LP: #1342979)
3912+
3913+ -- Philip Pemberton <philpem@philpem.me.uk> Fri, 03 Apr 2015 09:49:33 +0100
3914+
3915 ptouch-driver (1.3-8) unstable; urgency=medium
3916
3917 [ Philip Pemberton ]
3918
3919=== modified file 'debian/patches/foomatic-data-fixes.patch'
3920--- debian/patches/foomatic-data-fixes.patch 2011-08-29 12:27:35 +0000
3921+++ debian/patches/foomatic-data-fixes.patch 2015-04-10 21:18:54 +0000
3922@@ -22,14 +22,3 @@
3923 </execution>
3924 <comments>
3925 <en>
3926---- a/printer/Brother-QL-550.xml
3927-+++ b/printer/Brother-QL-550.xml
3928-@@ -28,7 +28,7 @@
3929- <resolution>
3930- <dpi>
3931- <x>300</x>
3932-- <y>300</y>
3933-+ <y>275</y>
3934- </dpi>
3935- </resolution>
3936- <consumables>
3937
3938=== added file 'debian/patches/philpem-ptouch-fixes'
3939--- debian/patches/philpem-ptouch-fixes 1970-01-01 00:00:00 +0000
3940+++ debian/patches/philpem-ptouch-fixes 2015-04-10 21:18:54 +0000
3941@@ -0,0 +1,622 @@
3942+This patch fixes a number of issues with the ptouch-driver printer driver:
3943+
3944+ * Update the driver to use current CUPS APIs (not the older deprecated ones)
3945+ and fix some compile-time warnings
3946+ * Use the PPD API to get the value of the MediaType flag, which is used to
3947+ pass the "Roll-fed media" flag into the driver
3948+ * Correct the margins for QL-series P-Touch paper-label printers - these
3949+ have a fixed 3mm margin (see the command spec) while the PT-series
3950+ laminated plastic label printers have no appreciable margins.
3951+ * Correct the format of the "ESC i z" (Print Information) command to match
3952+ what is specified in the P-touch 500 raster command spec. Notably set the
3953+ "passed parameter valid" bits, and send valid values for die-cut labels
3954+ and continuous paper rolls.
3955+ * Send the "ESC i d" (Set Margin) command for QL series printers. This is
3956+ required by the command spec. The margin is set to 3mm for continuous
3957+ paper and zero for die-cut (see the command spec)
3958+ * Fix an issue with margins in the driver (disable blank-line padding). This
3959+ was partly responsible for the "excess paper feed" issue.
3960+ * Suppress the spurious "ESC i z" which was sent with incorrect contents at
3961+ the start of the job.
3962+ * Fix the Enable Cutter command.
3963+ * Send 350 bytes of NULL/no-op commands at the start of the job. This allows
3964+ the driver to recover the printer into a known state if communication was
3965+ interrupted mid-transfer. This is recommended in the command spec.
3966+ * Remove the "determined by page size" option from "Roll-fed media" as this
3967+ no longer works.
3968+ * Remove the "Advance Media" option, as this allowed users to configure the
3969+ driver to generate print control codes which are illegal per the Brother
3970+ documentation. This is now fixed at "Advance at end of job" (send a Form
3971+ Feed at the end of every page, except the last which has an Eject
3972+ command instead).
3973+ * Merge in the changes formerly provided by send-esc-i-A-for-QL-only.patch.
3974+
3975+See also:
3976+ Brother QL Series Command Reference (QL-500/550/560/570/580N/650TD/700/1050/1060N)
3977+ <http://download.brother.com/welcome/docp000678/cv_qlseries_eng_raster_600.pdf>
3978+
3979+Author: Philip Pemberton <philpem@philpem.me.uk>
3980+--- a/rastertoptch.c
3981++++ b/rastertoptch.c
3982+@@ -297,8 +297,6 @@
3983+ #define IMAGE_HEIGHT_DEFAULT 0
3984+ /** Feed amount default */
3985+ #define FEED_DEFAULT 0
3986+-/** When to perform feed default */
3987+-#define PERFORM_FEED_DEFAULT CUPS_ADVANCE_NONE
3988+
3989+ #include <config.h>
3990+ #include <stdio.h>
3991+@@ -432,6 +430,7 @@
3992+ int label_preamble; /**< emit ESC i z ... */
3993+ bool concat_pages; /**< remove interlabel margins */
3994+ unsigned long rle_alloc_max; /**< max bytes used for rle_buffer */
3995++ bool roll_fed_media; /**< continuous (not labels) roll media */
3996+ } job_options_t;
3997+
3998+ /**
3999+@@ -440,12 +439,10 @@
4000+ typedef struct {
4001+ cups_cut_t cut_media; /**< cut media mode */
4002+ cups_bool_t mirror; /**< mirror printing */
4003+- bool roll_fed_media; /**< continuous (not labels) roll media */
4004+ unsigned resolution [2]; /**< horiz & vertical resolution in DPI */
4005+ unsigned page_size [2]; /**< width & height of page in points */
4006+ unsigned image_height; /**< height of page image in pixels */
4007+ unsigned feed; /**< feed size in points */
4008+- cups_adv_t perform_feed; /**< When to feed */
4009+ } page_options_t;
4010+
4011+ /**
4012+@@ -469,12 +466,40 @@
4013+ LABEL_PREAMBLE_DEFAULT,
4014+ CONCAT_PAGES_DEFAULT,
4015+ RLE_ALLOC_MAX_DEFAULT,
4016++ ROLL_FED_MEDIA_DEFAULT,
4017+ };
4018+ if (argc < 6) return options;
4019+ int num_options = 0;
4020+ cups_option_t* cups_options = NULL;
4021++ ppd_file_t *ppd; /* PPD file */
4022+ num_options
4023+ = cupsParseOptions (argv [5], num_options, &cups_options);
4024++
4025++ // Load job options from the PPD file
4026++ ppd = ppdOpenFile(getenv("PPD"));
4027++ if (!ppd) {
4028++ ppd_status_t status; /* PPD error */
4029++ int linenum; /* Line number */
4030++
4031++ fprintf(stderr, "ERROR: The PPD file could not be opened.");
4032++
4033++ status = ppdLastError(&linenum);
4034++
4035++ fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
4036++
4037++ exit(EXIT_FAILURE);
4038++ }
4039++ ppdMarkDefaults(ppd);
4040++ cupsMarkOptions(ppd, num_options, cups_options);
4041++
4042++ // Use PPD API to decode RollFedMedia choice
4043++ ppd_choice_t *choice = ppdFindMarkedChoice(ppd, "RollFedMedia");
4044++ fprintf(stderr, "DEBUG: Markedchoice for roll fed media is '%s', text '%s'\n", choice->choice, choice->text);
4045++ options.roll_fed_media /* Default is continuous roll */
4046++ = (strcasecmp ("Labels", choice->choice) != 0);
4047++
4048++
4049++ // FIXME use PPD API
4050+ const char* cups_option
4051+ = cupsGetOption ("PixelXfer", num_options, cups_options);
4052+ if (cups_option) {
4053+@@ -526,8 +551,12 @@
4054+ OBTAIN_INT_OPTION ("TransferMode", xfer_mode, 0, 255);
4055+ OBTAIN_BOOL_OPTION ("SoftwareMirror", software_mirror);
4056+ OBTAIN_BOOL_OPTION ("LabelPreamble", label_preamble);
4057+- /* Release memory allocated for CUPS options struct */
4058++
4059++ /* Close the PPD file and
4060++ * Release memory allocated for CUPS options struct */
4061++ ppdClose(ppd);
4062+ cupsFreeOptions (num_options, cups_options);
4063++
4064+ return options;
4065+ }
4066+
4067+@@ -559,20 +588,25 @@
4068+ * @param page_options page options to be updated
4069+ */
4070+ void
4071+-update_page_options (cups_page_header_t* header,
4072++update_page_options (cups_page_header2_t* header,
4073+ page_options_t* page_options) {
4074+ page_options->cut_media = header->CutMedia;
4075+ page_options->mirror = header->MirrorPrint;
4076+ const char* media_type = header->MediaType;
4077+- page_options->roll_fed_media /* Default is continuous roll */
4078+- = (strcasecmp ("Labels", media_type) != 0);
4079+ page_options->resolution [0] = header->HWResolution [0];
4080+ page_options->resolution [1] = header->HWResolution [1];
4081+ page_options->page_size [0] = header->PageSize [0];
4082+ page_options->page_size [1] = header->PageSize [1];
4083+ page_options->image_height = header->cupsHeight;
4084+ page_options->feed = header->AdvanceDistance;
4085+- page_options->perform_feed = header->AdvanceMedia;
4086++
4087++ fprintf(stderr, "DEBUG: ==== PAGE OPTIONS ====\n");
4088++ fprintf(stderr, "DEBUG: Cut Media = %d\n", header->CutMedia);
4089++ fprintf(stderr, "DEBUG: Media Type = [%s]\n", header->MediaType);
4090++ fprintf(stderr, "DEBUG: Resolution = [%d %d]\n", header->HWResolution[0], header->HWResolution[1]);
4091++ fprintf(stderr, "DEBUG: PageSize = [%d %d]\n", header->PageSize[0], header->PageSize[1]);
4092++ fprintf(stderr, "DEBUG: ImageHeight (header->cupsHeight) = %d\n", header->cupsHeight);
4093++ fprintf(stderr, "DEBUG: Advance Distance = %d\n", header->AdvanceDistance);
4094+ }
4095+
4096+ void cancel_job (int signal);
4097+@@ -654,6 +688,13 @@
4098+ */
4099+ void
4100+ emit_job_cmds (job_options_t* job_options) {
4101++ /* Send 350 bytes of NULL to clear print buffer in case an error occurred
4102++ * previously. The printer ignores 0x00 bytes if it's waiting for a command.
4103++ */
4104++ int i;
4105++ for (i=0; i<350; i++) {
4106++ putchar(0x00);
4107++ }
4108+ /* Initialise printer */
4109+ putchar (ESC); putchar ('@');
4110+ /* Emit print density selection command if required */
4111+@@ -685,7 +726,8 @@
4112+ inline void
4113+ emit_feed_cut_mirror (bool do_feed, unsigned feed,
4114+ bool do_cut,
4115+- bool do_mirror) {
4116++ bool do_mirror,
4117++ xfer_t xfer_mode) {
4118+ /* Determine feed nibble */
4119+ unsigned feed_nibble;
4120+ if (do_feed) {
4121+@@ -698,6 +740,14 @@
4122+ /* Determine mirror print bit*/
4123+ unsigned char mirror_bit = do_mirror ? 0x80 : 0x00;
4124+ /* Combine & emit printer command code */
4125++ if (xfer_mode == ULP) {
4126++ /* ESC i A is Enable Cutter -- used for QL-560 only, according to
4127++ * <http://www.undocprint.org/formats/page_description_languages/brother_p-touch>
4128++ * The QL-560 (actually the whole QL series) uses ULP mode, so we check for that.
4129++ * The PT2450DX uses RLE and throw an INTERFACE ERROR if it sees this command.
4130++ */
4131++ putchar (ESC); putchar ('i'); putchar ('A'); putchar ((char) (do_cut ? 0x01 : 0x00));
4132++ }
4133+ putchar (ESC); putchar ('i'); putchar ('M');
4134+ putchar ((char) (feed & 0x1f) | auto_cut_bit | mirror_bit);
4135+ }
4136+@@ -714,11 +764,19 @@
4137+ page_options_t* page_options,
4138+ unsigned page_size_y,
4139+ unsigned image_height_px) {
4140+- bool roll_fed_media = page_options->roll_fed_media;
4141++
4142++ static bool first_page = true; // True if this is the first page
4143++ // (this function is only called once per page)
4144++
4145++ const unsigned char PI_KIND = 0x02; // Paper type (roll fed media bit) is valid
4146++ const unsigned char PI_WIDTH = 0x04; // Paper width is valid
4147++ const unsigned char PI_LENGTH = 0x08; // Paper length is valid
4148++
4149++ bool roll_fed_media = job_options->roll_fed_media;
4150+ /* Determine print quality bit */
4151+ unsigned char print_quality_bit
4152+ = (job_options->print_quality_high == CUPS_TRUE) ? 0x40 : 0x00;
4153+- unsigned char roll_fed_media_bit = roll_fed_media ? 0x00 : 0x01;
4154++ unsigned char paper_type_id = roll_fed_media ? 0x0A : 0x0B;
4155+ /* Get tape width in mm */
4156+ int tape_width_mm = lrint (page_options->page_size [0] * MM_PER_PT);
4157+ if (tape_width_mm > 0xff) {
4158+@@ -741,11 +799,28 @@
4159+ }
4160+ /* Combine & emit printer command code */
4161+ putchar (ESC); putchar ('i'); putchar ('z');
4162+- putchar (print_quality_bit); putchar (roll_fed_media_bit);
4163+- putchar (tape_width_mm & 0xff); putchar (tape_height_mm & 0xff);
4164++ putchar (print_quality_bit | PI_KIND | PI_WIDTH | PI_LENGTH);
4165++ putchar (paper_type_id);
4166++ putchar (tape_width_mm & 0xff);
4167++ putchar (tape_height_mm & 0xff);
4168+ putchar (image_height_px & 0xff);
4169+ putchar ((image_height_px >> 8) & 0xff);
4170+- putchar (0x00); putchar (0x00); putchar (0x00); putchar (0x00);
4171++ putchar ((image_height_px >> 16) & 0xff);
4172++ putchar ((image_height_px >> 24) & 0xff);
4173++ putchar (first_page ? 0x00 : 0x01); // n9: 0 for first page, 1 for other pages
4174++ putchar (0x00); // n10, always 0
4175++
4176++ first_page = false;
4177++
4178++ /* Send a SET MARGIN command */
4179++ putchar(ESC); putchar('i'); putchar('d');
4180++ if (roll_fed_media) {
4181++ /* Continuous tape, specify 35 dots (3mm) */
4182++ putchar(35); putchar(0);
4183++ } else {
4184++ /* Die-cut labels, specify no margin */
4185++ putchar(0); putchar(0);
4186++ }
4187+ }
4188+ /**
4189+ * Emit printer command codes at start of page for options that have
4190+@@ -795,31 +870,20 @@
4191+
4192+ /* Set feed, auto cut and mirror print */
4193+ unsigned feed = new_page_options->feed;
4194+- cups_adv_t perform_feed = new_page_options->perform_feed;
4195+ cups_cut_t cut_media = new_page_options->cut_media;
4196+ cups_bool_t mirror = new_page_options->mirror;
4197+ if (force
4198+ || feed != old_page_options->feed
4199+- || perform_feed != old_page_options->perform_feed
4200+ || cut_media != old_page_options->cut_media
4201+ || mirror != old_page_options->mirror)
4202+ /* We only know how to feed after each page */
4203+- emit_feed_cut_mirror (perform_feed == CUPS_ADVANCE_PAGE, feed,
4204++ emit_feed_cut_mirror (false, feed,
4205+ cut_media == CUPS_CUT_PAGE,
4206+- mirror == CUPS_TRUE);
4207+- /* Set media and quality if label preamble is requested */
4208++ mirror == CUPS_TRUE,
4209++ job_options->pixel_xfer);
4210++
4211+ unsigned page_size_y = new_page_options->page_size [1];
4212+ unsigned image_height_px = lrint (page_size_y * vres / 72.0);
4213+- if (job_options->label_preamble && !job_options->concat_pages
4214+- && (force
4215+- || (new_page_options->roll_fed_media
4216+- != old_page_options->roll_fed_media)
4217+- || new_page_size_x != old_page_size_x
4218+- || page_size_y != old_page_options->page_size [1]))
4219+- emit_quality_rollfed_size (job_options, new_page_options,
4220+- page_size_y, image_height_px);
4221+-
4222+- /* WHY DON'T WE SET MARGIN (ESC i d ...)? */
4223+
4224+ /* Set pixel data transfer compression */
4225+ if (force) {
4226+@@ -907,7 +971,7 @@
4227+ #ifdef DEBUG
4228+ if (debug)
4229+ fprintf (stderr, "DEBUG: generate_emit_line "
4230+- "(in_buffer=%0x, out_buffer=%0x, "
4231++ "(in_buffer=%p, out_buffer=%p, "
4232+ "buflen=%d, bytes_per_line=%d, right_padding_bytes=%d, "
4233+ "shift=%d, do_mirror=%d, xormask=%0x)\n",
4234+ in_buffer, out_buffer, buflen, bytes_per_line,
4235+@@ -1068,7 +1132,7 @@
4236+ #ifdef DEBUG
4237+ if (debug)
4238+ fprintf (stderr, "DEBUG: ensure_rle_buf_space (bytes=%d): "
4239+- "increasing rle_buffer from %d to %d\n",
4240++ "increasing rle_buffer from %zu to %zu\n",
4241+ bytes,
4242+ rle_alloced * sizeof (char),
4243+ new_alloced * sizeof (char));
4244+@@ -1291,7 +1355,7 @@
4245+ job_options_t* job_options,
4246+ page_options_t* page_options,
4247+ cups_raster_t* ras,
4248+- cups_page_header_t* header) {
4249++ cups_page_header2_t* header) {
4250+ unsigned char xormask = (header->NegativePrint ? ~0 : 0);
4251+ /* Determine whether we need to mirror the pixel data */
4252+ int do_mirror = job_options->software_mirror && page_options->mirror;
4253+@@ -1362,8 +1426,10 @@
4254+ unsigned top_distance_pt
4255+ = page_size_y - header->ImagingBoundingBox [3];
4256+ if (top_distance_pt != 0) {
4257++ fprintf(stderr, "DEBUG: philpem -- Top distance pt nonzero, %d\n", top_distance_pt);
4258+ top_empty_lines = lrint (top_distance_pt * scale_pt2ypixels);
4259+- empty_lines += top_empty_lines;
4260++ fprintf(stderr, "DEBUG: philpem -- Top empty lines %d\n", top_empty_lines);
4261++ //empty_lines += top_empty_lines;
4262+ }
4263+ }
4264+ /* Generate and store actual page data */
4265+@@ -1404,6 +1470,11 @@
4266+ bot_empty_lines = image_height_px - top_empty_lines - y;
4267+ else
4268+ bot_empty_lines = 0;
4269++
4270++
4271++ fprintf(stderr, "DEBUG: philpem -- Bottom empty lines %d\n", bot_empty_lines);
4272++ bot_empty_lines = 0;
4273++
4274+ if (bot_empty_lines != 0 && !job_options->concat_pages)
4275+ empty_lines += bot_empty_lines;
4276+ fprintf (stderr,
4277+@@ -1423,19 +1494,17 @@
4278+ process_rasterdata (int fd, job_options_t* job_options) {
4279+ int page = 1; /* Page number */
4280+ cups_raster_t* ras; /* Raster stream for printing */
4281+- cups_page_header_t header; /* Current page header */
4282++ cups_page_header2_t header; /* Current page header */
4283+ int first_page = true; /* Is this the first page? */
4284+ int more_pages; /* Are there more pages left? */
4285+ int bytes_per_line = job_options->bytes_per_line;
4286+ page_options_t page_options [2] = {{
4287+ CUT_MEDIA_DEFAULT,
4288+ MIRROR_DEFAULT,
4289+- ROLL_FED_MEDIA_DEFAULT,
4290+ RESOLUTION_DEFAULT,
4291+ PAGE_SIZE_DEFAULT,
4292+ IMAGE_HEIGHT_DEFAULT,
4293+- FEED_DEFAULT,
4294+- PERFORM_FEED_DEFAULT,}
4295++ FEED_DEFAULT,}
4296+ }; /* Current & preceding page opts */
4297+ page_options_t* new_page_options
4298+ = page_options + 0; /* Options for current page */
4299+@@ -1443,7 +1512,7 @@
4300+ = page_options + 1; /* Options for preceding page */
4301+ page_options_t* tmp_page_options;/* Temp variable for swapping */
4302+ ras = cupsRasterOpen (fd, CUPS_RASTER_READ);
4303+- for (more_pages = cupsRasterReadHeader (ras, &header);
4304++ for (more_pages = cupsRasterReadHeader2 (ras, &header);
4305+ more_pages;
4306+ tmp_page_options = old_page_options,
4307+ old_page_options = new_page_options,
4308+@@ -1452,6 +1521,7 @@
4309+ update_page_options (&header, new_page_options);
4310+ #ifdef DEBUG
4311+ if (debug) {
4312++ fprintf (stderr, "DEBUG: MediaType = %s\n", header.MediaType);
4313+ fprintf (stderr, "DEBUG: pixel_xfer = %d\n", job_options->pixel_xfer);
4314+ fprintf (stderr, "DEBUG: print_quality_high = %d\n", job_options->print_quality_high);
4315+ fprintf (stderr, "DEBUG: half_cut = %d\n", job_options->half_cut);
4316+@@ -1464,12 +1534,11 @@
4317+ fprintf (stderr, "DEBUG: concat_pages = %d\n", job_options->concat_pages);
4318+ fprintf (stderr, "DEBUG: cut_media = %d\n", new_page_options->cut_media);
4319+ fprintf (stderr, "DEBUG: mirror = %d\n", new_page_options->mirror);
4320+- fprintf (stderr, "DEBUG: roll_fed_media = %d\n", new_page_options->roll_fed_media);
4321++ fprintf (stderr, "DEBUG: roll_fed_media = %d\n", job_options->roll_fed_media);
4322+ fprintf (stderr, "DEBUG: resolution = %d x %d\n", new_page_options->resolution [0], new_page_options->resolution [1]);
4323+ fprintf (stderr, "DEBUG: page_size = %d x %d\n", new_page_options->page_size [0], new_page_options->page_size [1]);
4324+ fprintf (stderr, "DEBUG: image_height = %d\n", new_page_options->image_height);
4325+ fprintf (stderr, "DEBUG: feed = %d\n", new_page_options->feed);
4326+- fprintf (stderr, "DEBUG: perform_feed = %d\n", new_page_options->perform_feed);
4327+ fprintf (stderr, "DEBUG: header->ImagingBoundingBox = [%u, %u, %u, %u]\n",
4328+ header.ImagingBoundingBox [0], header.ImagingBoundingBox [1],
4329+ header.ImagingBoundingBox [2], header.ImagingBoundingBox [3]);
4330+@@ -1486,19 +1555,15 @@
4331+ emit_raster_lines (page, job_options, new_page_options, ras, &header);
4332+ unsigned char xormask = (header.NegativePrint ? ~0 : 0);
4333+ /* Determine whether this is the last page (fetch next) */
4334+- more_pages = cupsRasterReadHeader (ras, &header);
4335++ more_pages = cupsRasterReadHeader2 (ras, &header);
4336+ /* Do feeding or ejecting at the end of each page. */
4337+- cups_adv_t perform_feed = new_page_options->perform_feed;
4338+ if (more_pages) {
4339+ if (!job_options->concat_pages) {
4340+ RLE_store_empty_lines
4341+ (job_options, page_options, empty_lines, xormask);
4342+ empty_lines = 0;
4343+ flush_rle_buffer (job_options, page_options);
4344+- if (perform_feed == CUPS_ADVANCE_PAGE)
4345+- putchar (PTC_EJECT); /* Emit eject marker to force feed */
4346+- else
4347+- putchar (PTC_FORMFEED); /* Emit page end marker without feed */
4348++ putchar (PTC_FORMFEED); /* Emit page end marker without feed */
4349+ }
4350+ } else {
4351+ if (!job_options->concat_pages) {
4352+@@ -1506,7 +1571,6 @@
4353+ (job_options, page_options, empty_lines, xormask);
4354+ empty_lines = 0;
4355+ flush_rle_buffer (job_options, page_options);
4356+- putchar (PTC_FORMFEED);
4357+ } else {
4358+ double scale_pt2ypixels = header.HWResolution [1] / 72.0;
4359+ unsigned bot_empty_lines
4360+@@ -1518,18 +1582,8 @@
4361+ flush_rle_buffer (job_options, page_options);
4362+ }
4363+
4364+- /* If special feed or cut at job end, emit commands to that effect */
4365+- cups_cut_t cut_media = new_page_options->cut_media;
4366+- if (perform_feed == CUPS_ADVANCE_JOB || cut_media == CUPS_CUT_JOB) {
4367+- emit_feed_cut_mirror
4368+- (perform_feed == CUPS_ADVANCE_PAGE ||
4369+- perform_feed == CUPS_ADVANCE_JOB,
4370+- new_page_options->feed,
4371+- cut_media == CUPS_CUT_PAGE || cut_media == CUPS_CUT_JOB,
4372+- new_page_options->mirror == CUPS_TRUE);
4373+- /* Emit eject marker */
4374+- putchar (PTC_EJECT);
4375+- }
4376++ /* End of last page, send Eject command */
4377++ putchar (PTC_EJECT);
4378+ }
4379+ page_end ();
4380+ /* Emit page count according to CUPS requirements */
4381+--- a/printer/Brother-QL-500.xml
4382++++ b/printer/Brother-QL-500.xml
4383+@@ -31,6 +31,15 @@
4384+ <y>300</y>
4385+ </dpi>
4386+ </resolution>
4387++ <margins>
4388++ <general>
4389++ <unit>mm</unit>
4390++ <top>3</top>
4391++ <bottom>3</bottom>
4392++ <left>1.5</left>
4393++ <right>1.5</right>
4394++ </general>
4395++ </margins>
4396+ <consumables>
4397+ <comments>
4398+ <en>
4399+--- a/printer/Brother-QL-550.xml
4400++++ b/printer/Brother-QL-550.xml
4401+@@ -31,6 +31,15 @@
4402+ <y>300</y>
4403+ </dpi>
4404+ </resolution>
4405++ <margins>
4406++ <general>
4407++ <unit>mm</unit>
4408++ <top>3</top>
4409++ <bottom>3</bottom>
4410++ <left>1.5</left>
4411++ <right>1.5</right>
4412++ </general>
4413++ </margins>
4414+ <consumables>
4415+ <comments>
4416+ <en>
4417+--- a/printer/Brother-QL-650TD.xml
4418++++ b/printer/Brother-QL-650TD.xml
4419+@@ -31,6 +31,15 @@
4420+ <y>300</y>
4421+ </dpi>
4422+ </resolution>
4423++ <margins>
4424++ <general>
4425++ <unit>mm</unit>
4426++ <top>3</top>
4427++ <bottom>3</bottom>
4428++ <left>1.5</left>
4429++ <right>1.5</right>
4430++ </general>
4431++ </margins>
4432+ <consumables>
4433+ <comments>
4434+ <en>
4435+--- a/opt/Brother-Ptouch-RollFedMedia.xml
4436++++ b/opt/Brother-Ptouch-RollFedMedia.xml
4437+@@ -41,19 +41,6 @@
4438+ </constraint>
4439+ </constraints>
4440+ <enum_vals>
4441+- <enum_val id="ev/Auto">
4442+- <ev_longname>
4443+- <en>Automatically determined by page size</en>
4444+- </ev_longname>
4445+- <!-- A multilingual <comments> block can appear here, too;
4446+- it should be treated as documentation for the user. -->
4447+- <ev_shortname>
4448+- <en>Auto</en>
4449+- <!-- Until someone tells me how to learn the user locale in
4450+- backends, the shortname must be monolingual in <en>! -->
4451+- </ev_shortname>
4452+- <ev_driverval></ev_driverval>
4453+- </enum_val>
4454+ <enum_val id="ev/Roll">
4455+ <ev_longname>
4456+ <en>Continuous roll</en>
4457+--- a/opt/Brother-Ptouch-AdvanceMedia.xml
4458++++ /dev/null
4459+@@ -1,84 +0,0 @@
4460+-<!--
4461+-Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
4462+-
4463+-This file is part of ptouch-driver.
4464+-
4465+-ptouch-driver is free software; you can redistribute it and/or modify
4466+-it under the terms of the GNU General Public License as published by
4467+-the Free Software Foundation; either version 2 of the License, or (at
4468+-your option) any later version.
4469+-
4470+-ptouch-driver is distributed in the hope that it will be useful, but
4471+-WITHOUT ANY WARRANTY; without even the implied warranty of
4472+-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4473+-General Public License for more details.
4474+-
4475+-You should have received a copy of the GNU General Public License
4476+-along with ptouch-driver; if not, write to the Free Software
4477+-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
4478+-USA
4479+--->
4480+-<option type='enum' id='Brother-Ptouch-AdvanceMedia'>
4481+- <!-- A multilingual <comments> block can appear here, too;
4482+- it should be treated as documentation for the user. -->
4483+- <arg_longname>
4484+- <en>Advance Media</en>
4485+- </arg_longname>
4486+- <arg_shortname>
4487+- <en>AdvanceMedia</en><!-- backends only know <en> shortnames! -->
4488+- </arg_shortname>
4489+- <arg_execution>
4490+- <arg_group>Finishing</arg_group>
4491+- <arg_order>110</arg_order>
4492+- <arg_spot>A</arg_spot>
4493+- <arg_postscript />
4494+- <arg_proto>&lt;&lt;/AdvanceMedia %s&gt;&gt;setpagedevice</arg_proto>
4495+- </arg_execution>
4496+- <constraints>
4497+- <constraint sense='true'>
4498+- <driver>ptouch</driver>
4499+- <arg_defval>ev/Off</arg_defval>
4500+- </constraint>
4501+- </constraints>
4502+- <enum_vals>
4503+- <enum_val id="ev/Off">
4504+- <ev_longname>
4505+- <en>Do not advance the tape</en>
4506+- </ev_longname>
4507+- <!-- A multilingual <comments> block can appear here, too;
4508+- it should be treated as documentation for the user. -->
4509+- <ev_shortname>
4510+- <en>Off</en>
4511+- <!-- Until someone tells me how to learn the user locale in
4512+- backends, the shortname must be monolingual in <en>! -->
4513+- </ev_shortname>
4514+- <ev_driverval>0</ev_driverval>
4515+- </enum_val>
4516+- <enum_val id="ev/LabelEnd">
4517+- <ev_longname>
4518+- <en>Advance the tape after each label</en>
4519+- </ev_longname>
4520+- <!-- A multilingual <comments> block can appear here, too;
4521+- it should be treated as documentation for the user. -->
4522+- <ev_shortname>
4523+- <en>LabelEnd</en>
4524+- <!-- Until someone tells me how to learn the user locale in
4525+- backends, the shortname must be monolingual in <en>! -->
4526+- </ev_shortname>
4527+- <ev_driverval>4</ev_driverval>
4528+- </enum_val>
4529+- <enum_val id="ev/JobEnd">
4530+- <ev_longname>
4531+- <en>Advance the tape at the end of the job</en>
4532+- </ev_longname>
4533+- <!-- A multilingual <comments> block can appear here, too;
4534+- it should be treated as documentation for the user. -->
4535+- <ev_shortname>
4536+- <en>JobEnd</en>
4537+- <!-- Until someone tells me how to learn the user locale in
4538+- backends, the shortname must be monolingual in <en>! -->
4539+- </ev_shortname>
4540+- <ev_driverval>2</ev_driverval>
4541+- </enum_val>
4542+- </enum_vals>
4543+-</option>
4544+--- a/Makefile.am
4545++++ b/Makefile.am
4546+@@ -47,7 +47,6 @@
4547+ printer/Brother-PT-9500PC.xml \
4548+ printer/Brother-PT-9600.xml \
4549+ opt/Brother-Ptouch-AdvanceDistance.xml \
4550+- opt/Brother-Ptouch-AdvanceMedia.xml \
4551+ opt/Brother-Ptouch-Align.xml \
4552+ opt/Brother-Ptouch-BytesPerLine.xml \
4553+ opt/Brother-Ptouch-ConcatPages.xml \
4554+--- a/ptouch-driver-foomatic.spec.in
4555++++ b/ptouch-driver-foomatic.spec.in
4556+@@ -76,7 +76,6 @@
4557+ /usr/share/foomatic/db/source/printer/Brother-QL-550.xml
4558+ /usr/share/foomatic/db/source/printer/Brother-QL-650TD.xml
4559+ /usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceDistance.xml
4560+-/usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceMedia.xml
4561+ /usr/share/foomatic/db/source/opt/Brother-Ptouch-Align.xml
4562+ /usr/share/foomatic/db/source/opt/Brother-Ptouch-BytesPerLine.xml
4563+ /usr/share/foomatic/db/source/opt/Brother-Ptouch-ConcatPages.xml
4564
4565=== modified file 'debian/patches/send-esc-i-A-for-QL-only.patch'
4566--- debian/patches/send-esc-i-A-for-QL-only.patch 2014-03-06 16:23:54 +0000
4567+++ debian/patches/send-esc-i-A-for-QL-only.patch 2015-04-10 21:18:54 +0000
4568@@ -40,7 +40,7 @@
4569 cut_media == CUPS_CUT_PAGE,
4570 - mirror == CUPS_TRUE);
4571 + mirror == CUPS_TRUE,
4572-+ job_options->pixel_xfer == ULP);
4573++ job_options->pixel_xfer);
4574 /* Set media and quality if label preamble is requested */
4575 unsigned page_size_y = new_page_options->page_size [1];
4576 unsigned image_height_px = lrint (page_size_y * vres / 72.0);
4577
4578=== modified file 'debian/patches/series'
4579--- debian/patches/series 2014-03-06 16:23:54 +0000
4580+++ debian/patches/series 2015-04-10 21:18:54 +0000
4581@@ -1,2 +1,2 @@
4582 foomatic-data-fixes.patch
4583-send-esc-i-A-for-QL-only.patch
4584+philpem-ptouch-fixes
4585
4586=== removed file 'opt/Brother-Ptouch-AdvanceMedia.xml'
4587--- opt/Brother-Ptouch-AdvanceMedia.xml 2009-11-11 17:14:44 +0000
4588+++ opt/Brother-Ptouch-AdvanceMedia.xml 1970-01-01 00:00:00 +0000
4589@@ -1,84 +0,0 @@
4590-<!--
4591-Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
4592-
4593-This file is part of ptouch-driver.
4594-
4595-ptouch-driver is free software; you can redistribute it and/or modify
4596-it under the terms of the GNU General Public License as published by
4597-the Free Software Foundation; either version 2 of the License, or (at
4598-your option) any later version.
4599-
4600-ptouch-driver is distributed in the hope that it will be useful, but
4601-WITHOUT ANY WARRANTY; without even the implied warranty of
4602-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4603-General Public License for more details.
4604-
4605-You should have received a copy of the GNU General Public License
4606-along with ptouch-driver; if not, write to the Free Software
4607-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
4608-USA
4609--->
4610-<option type='enum' id='Brother-Ptouch-AdvanceMedia'>
4611- <!-- A multilingual <comments> block can appear here, too;
4612- it should be treated as documentation for the user. -->
4613- <arg_longname>
4614- <en>Advance Media</en>
4615- </arg_longname>
4616- <arg_shortname>
4617- <en>AdvanceMedia</en><!-- backends only know <en> shortnames! -->
4618- </arg_shortname>
4619- <arg_execution>
4620- <arg_group>Finishing</arg_group>
4621- <arg_order>110</arg_order>
4622- <arg_spot>A</arg_spot>
4623- <arg_postscript />
4624- <arg_proto>&lt;&lt;/AdvanceMedia %s&gt;&gt;setpagedevice</arg_proto>
4625- </arg_execution>
4626- <constraints>
4627- <constraint sense='true'>
4628- <driver>ptouch</driver>
4629- <arg_defval>ev/Off</arg_defval>
4630- </constraint>
4631- </constraints>
4632- <enum_vals>
4633- <enum_val id="ev/Off">
4634- <ev_longname>
4635- <en>Do not advance the tape</en>
4636- </ev_longname>
4637- <!-- A multilingual <comments> block can appear here, too;
4638- it should be treated as documentation for the user. -->
4639- <ev_shortname>
4640- <en>Off</en>
4641- <!-- Until someone tells me how to learn the user locale in
4642- backends, the shortname must be monolingual in <en>! -->
4643- </ev_shortname>
4644- <ev_driverval>0</ev_driverval>
4645- </enum_val>
4646- <enum_val id="ev/LabelEnd">
4647- <ev_longname>
4648- <en>Advance the tape after each label</en>
4649- </ev_longname>
4650- <!-- A multilingual <comments> block can appear here, too;
4651- it should be treated as documentation for the user. -->
4652- <ev_shortname>
4653- <en>LabelEnd</en>
4654- <!-- Until someone tells me how to learn the user locale in
4655- backends, the shortname must be monolingual in <en>! -->
4656- </ev_shortname>
4657- <ev_driverval>4</ev_driverval>
4658- </enum_val>
4659- <enum_val id="ev/JobEnd">
4660- <ev_longname>
4661- <en>Advance the tape at the end of the job</en>
4662- </ev_longname>
4663- <!-- A multilingual <comments> block can appear here, too;
4664- it should be treated as documentation for the user. -->
4665- <ev_shortname>
4666- <en>JobEnd</en>
4667- <!-- Until someone tells me how to learn the user locale in
4668- backends, the shortname must be monolingual in <en>! -->
4669- </ev_shortname>
4670- <ev_driverval>2</ev_driverval>
4671- </enum_val>
4672- </enum_vals>
4673-</option>
4674
4675=== modified file 'opt/Brother-Ptouch-RollFedMedia.xml'
4676--- opt/Brother-Ptouch-RollFedMedia.xml 2009-11-11 17:14:44 +0000
4677+++ opt/Brother-Ptouch-RollFedMedia.xml 2015-04-10 21:18:54 +0000
4678@@ -41,19 +41,6 @@
4679 </constraint>
4680 </constraints>
4681 <enum_vals>
4682- <enum_val id="ev/Auto">
4683- <ev_longname>
4684- <en>Automatically determined by page size</en>
4685- </ev_longname>
4686- <!-- A multilingual <comments> block can appear here, too;
4687- it should be treated as documentation for the user. -->
4688- <ev_shortname>
4689- <en>Auto</en>
4690- <!-- Until someone tells me how to learn the user locale in
4691- backends, the shortname must be monolingual in <en>! -->
4692- </ev_shortname>
4693- <ev_driverval></ev_driverval>
4694- </enum_val>
4695 <enum_val id="ev/Roll">
4696 <ev_longname>
4697 <en>Continuous roll</en>
4698
4699=== modified file 'printer/Brother-QL-500.xml'
4700--- printer/Brother-QL-500.xml 2009-11-11 17:14:44 +0000
4701+++ printer/Brother-QL-500.xml 2015-04-10 21:18:54 +0000
4702@@ -31,6 +31,15 @@
4703 <y>300</y>
4704 </dpi>
4705 </resolution>
4706+ <margins>
4707+ <general>
4708+ <unit>mm</unit>
4709+ <top>3</top>
4710+ <bottom>3</bottom>
4711+ <left>1.5</left>
4712+ <right>1.5</right>
4713+ </general>
4714+ </margins>
4715 <consumables>
4716 <comments>
4717 <en>
4718
4719=== modified file 'printer/Brother-QL-550.xml'
4720--- printer/Brother-QL-550.xml 2011-08-29 12:27:35 +0000
4721+++ printer/Brother-QL-550.xml 2015-04-10 21:18:54 +0000
4722@@ -28,9 +28,18 @@
4723 <resolution>
4724 <dpi>
4725 <x>300</x>
4726- <y>275</y>
4727+ <y>300</y>
4728 </dpi>
4729 </resolution>
4730+ <margins>
4731+ <general>
4732+ <unit>mm</unit>
4733+ <top>3</top>
4734+ <bottom>3</bottom>
4735+ <left>1.5</left>
4736+ <right>1.5</right>
4737+ </general>
4738+ </margins>
4739 <consumables>
4740 <comments>
4741 <en>
4742
4743=== modified file 'printer/Brother-QL-650TD.xml'
4744--- printer/Brother-QL-650TD.xml 2009-11-11 17:14:44 +0000
4745+++ printer/Brother-QL-650TD.xml 2015-04-10 21:18:54 +0000
4746@@ -31,6 +31,15 @@
4747 <y>300</y>
4748 </dpi>
4749 </resolution>
4750+ <margins>
4751+ <general>
4752+ <unit>mm</unit>
4753+ <top>3</top>
4754+ <bottom>3</bottom>
4755+ <left>1.5</left>
4756+ <right>1.5</right>
4757+ </general>
4758+ </margins>
4759 <consumables>
4760 <comments>
4761 <en>
4762
4763=== modified file 'ptouch-driver-foomatic.spec.in'
4764--- ptouch-driver-foomatic.spec.in 2009-11-11 17:14:44 +0000
4765+++ ptouch-driver-foomatic.spec.in 2015-04-10 21:18:54 +0000
4766@@ -76,7 +76,6 @@
4767 /usr/share/foomatic/db/source/printer/Brother-QL-550.xml
4768 /usr/share/foomatic/db/source/printer/Brother-QL-650TD.xml
4769 /usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceDistance.xml
4770-/usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceMedia.xml
4771 /usr/share/foomatic/db/source/opt/Brother-Ptouch-Align.xml
4772 /usr/share/foomatic/db/source/opt/Brother-Ptouch-BytesPerLine.xml
4773 /usr/share/foomatic/db/source/opt/Brother-Ptouch-ConcatPages.xml
4774
4775=== modified file 'rastertoptch.c'
4776--- rastertoptch.c 2014-03-06 16:23:54 +0000
4777+++ rastertoptch.c 2015-04-10 21:18:54 +0000
4778@@ -297,8 +297,6 @@
4779 #define IMAGE_HEIGHT_DEFAULT 0
4780 /** Feed amount default */
4781 #define FEED_DEFAULT 0
4782-/** When to perform feed default */
4783-#define PERFORM_FEED_DEFAULT CUPS_ADVANCE_NONE
4784
4785 #include <config.h>
4786 #include <stdio.h>
4787@@ -432,6 +430,7 @@
4788 int label_preamble; /**< emit ESC i z ... */
4789 bool concat_pages; /**< remove interlabel margins */
4790 unsigned long rle_alloc_max; /**< max bytes used for rle_buffer */
4791+ bool roll_fed_media; /**< continuous (not labels) roll media */
4792 } job_options_t;
4793
4794 /**
4795@@ -440,12 +439,10 @@
4796 typedef struct {
4797 cups_cut_t cut_media; /**< cut media mode */
4798 cups_bool_t mirror; /**< mirror printing */
4799- bool roll_fed_media; /**< continuous (not labels) roll media */
4800 unsigned resolution [2]; /**< horiz & vertical resolution in DPI */
4801 unsigned page_size [2]; /**< width & height of page in points */
4802 unsigned image_height; /**< height of page image in pixels */
4803 unsigned feed; /**< feed size in points */
4804- cups_adv_t perform_feed; /**< When to feed */
4805 } page_options_t;
4806
4807 /**
4808@@ -469,12 +466,40 @@
4809 LABEL_PREAMBLE_DEFAULT,
4810 CONCAT_PAGES_DEFAULT,
4811 RLE_ALLOC_MAX_DEFAULT,
4812+ ROLL_FED_MEDIA_DEFAULT,
4813 };
4814 if (argc < 6) return options;
4815 int num_options = 0;
4816 cups_option_t* cups_options = NULL;
4817+ ppd_file_t *ppd; /* PPD file */
4818 num_options
4819 = cupsParseOptions (argv [5], num_options, &cups_options);
4820+
4821+ // Load job options from the PPD file
4822+ ppd = ppdOpenFile(getenv("PPD"));
4823+ if (!ppd) {
4824+ ppd_status_t status; /* PPD error */
4825+ int linenum; /* Line number */
4826+
4827+ fprintf(stderr, "ERROR: The PPD file could not be opened.");
4828+
4829+ status = ppdLastError(&linenum);
4830+
4831+ fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
4832+
4833+ exit(EXIT_FAILURE);
4834+ }
4835+ ppdMarkDefaults(ppd);
4836+ cupsMarkOptions(ppd, num_options, cups_options);
4837+
4838+ // Use PPD API to decode RollFedMedia choice
4839+ ppd_choice_t *choice = ppdFindMarkedChoice(ppd, "RollFedMedia");
4840+ fprintf(stderr, "DEBUG: Markedchoice for roll fed media is '%s', text '%s'\n", choice->choice, choice->text);
4841+ options.roll_fed_media /* Default is continuous roll */
4842+ = (strcasecmp ("Labels", choice->choice) != 0);
4843+
4844+
4845+ // FIXME use PPD API
4846 const char* cups_option
4847 = cupsGetOption ("PixelXfer", num_options, cups_options);
4848 if (cups_option) {
4849@@ -526,8 +551,12 @@
4850 OBTAIN_INT_OPTION ("TransferMode", xfer_mode, 0, 255);
4851 OBTAIN_BOOL_OPTION ("SoftwareMirror", software_mirror);
4852 OBTAIN_BOOL_OPTION ("LabelPreamble", label_preamble);
4853- /* Release memory allocated for CUPS options struct */
4854+
4855+ /* Close the PPD file and
4856+ * Release memory allocated for CUPS options struct */
4857+ ppdClose(ppd);
4858 cupsFreeOptions (num_options, cups_options);
4859+
4860 return options;
4861 }
4862
4863@@ -559,20 +588,25 @@
4864 * @param page_options page options to be updated
4865 */
4866 void
4867-update_page_options (cups_page_header_t* header,
4868+update_page_options (cups_page_header2_t* header,
4869 page_options_t* page_options) {
4870 page_options->cut_media = header->CutMedia;
4871 page_options->mirror = header->MirrorPrint;
4872 const char* media_type = header->MediaType;
4873- page_options->roll_fed_media /* Default is continuous roll */
4874- = (strcasecmp ("Labels", media_type) != 0);
4875 page_options->resolution [0] = header->HWResolution [0];
4876 page_options->resolution [1] = header->HWResolution [1];
4877 page_options->page_size [0] = header->PageSize [0];
4878 page_options->page_size [1] = header->PageSize [1];
4879 page_options->image_height = header->cupsHeight;
4880 page_options->feed = header->AdvanceDistance;
4881- page_options->perform_feed = header->AdvanceMedia;
4882+
4883+ fprintf(stderr, "DEBUG: ==== PAGE OPTIONS ====\n");
4884+ fprintf(stderr, "DEBUG: Cut Media = %d\n", header->CutMedia);
4885+ fprintf(stderr, "DEBUG: Media Type = [%s]\n", header->MediaType);
4886+ fprintf(stderr, "DEBUG: Resolution = [%d %d]\n", header->HWResolution[0], header->HWResolution[1]);
4887+ fprintf(stderr, "DEBUG: PageSize = [%d %d]\n", header->PageSize[0], header->PageSize[1]);
4888+ fprintf(stderr, "DEBUG: ImageHeight (header->cupsHeight) = %d\n", header->cupsHeight);
4889+ fprintf(stderr, "DEBUG: Advance Distance = %d\n", header->AdvanceDistance);
4890 }
4891
4892 void cancel_job (int signal);
4893@@ -654,6 +688,13 @@
4894 */
4895 void
4896 emit_job_cmds (job_options_t* job_options) {
4897+ /* Send 350 bytes of NULL to clear print buffer in case an error occurred
4898+ * previously. The printer ignores 0x00 bytes if it's waiting for a command.
4899+ */
4900+ int i;
4901+ for (i=0; i<350; i++) {
4902+ putchar(0x00);
4903+ }
4904 /* Initialise printer */
4905 putchar (ESC); putchar ('@');
4906 /* Emit print density selection command if required */
4907@@ -723,11 +764,19 @@
4908 page_options_t* page_options,
4909 unsigned page_size_y,
4910 unsigned image_height_px) {
4911- bool roll_fed_media = page_options->roll_fed_media;
4912+
4913+ static bool first_page = true; // True if this is the first page
4914+ // (this function is only called once per page)
4915+
4916+ const unsigned char PI_KIND = 0x02; // Paper type (roll fed media bit) is valid
4917+ const unsigned char PI_WIDTH = 0x04; // Paper width is valid
4918+ const unsigned char PI_LENGTH = 0x08; // Paper length is valid
4919+
4920+ bool roll_fed_media = job_options->roll_fed_media;
4921 /* Determine print quality bit */
4922 unsigned char print_quality_bit
4923 = (job_options->print_quality_high == CUPS_TRUE) ? 0x40 : 0x00;
4924- unsigned char roll_fed_media_bit = roll_fed_media ? 0x00 : 0x01;
4925+ unsigned char paper_type_id = roll_fed_media ? 0x0A : 0x0B;
4926 /* Get tape width in mm */
4927 int tape_width_mm = lrint (page_options->page_size [0] * MM_PER_PT);
4928 if (tape_width_mm > 0xff) {
4929@@ -750,11 +799,28 @@
4930 }
4931 /* Combine & emit printer command code */
4932 putchar (ESC); putchar ('i'); putchar ('z');
4933- putchar (print_quality_bit); putchar (roll_fed_media_bit);
4934- putchar (tape_width_mm & 0xff); putchar (tape_height_mm & 0xff);
4935+ putchar (print_quality_bit | PI_KIND | PI_WIDTH | PI_LENGTH);
4936+ putchar (paper_type_id);
4937+ putchar (tape_width_mm & 0xff);
4938+ putchar (tape_height_mm & 0xff);
4939 putchar (image_height_px & 0xff);
4940 putchar ((image_height_px >> 8) & 0xff);
4941- putchar (0x00); putchar (0x00); putchar (0x00); putchar (0x00);
4942+ putchar ((image_height_px >> 16) & 0xff);
4943+ putchar ((image_height_px >> 24) & 0xff);
4944+ putchar (first_page ? 0x00 : 0x01); // n9: 0 for first page, 1 for other pages
4945+ putchar (0x00); // n10, always 0
4946+
4947+ first_page = false;
4948+
4949+ /* Send a SET MARGIN command */
4950+ putchar(ESC); putchar('i'); putchar('d');
4951+ if (roll_fed_media) {
4952+ /* Continuous tape, specify 35 dots (3mm) */
4953+ putchar(35); putchar(0);
4954+ } else {
4955+ /* Die-cut labels, specify no margin */
4956+ putchar(0); putchar(0);
4957+ }
4958 }
4959 /**
4960 * Emit printer command codes at start of page for options that have
4961@@ -804,32 +870,20 @@
4962
4963 /* Set feed, auto cut and mirror print */
4964 unsigned feed = new_page_options->feed;
4965- cups_adv_t perform_feed = new_page_options->perform_feed;
4966 cups_cut_t cut_media = new_page_options->cut_media;
4967 cups_bool_t mirror = new_page_options->mirror;
4968 if (force
4969 || feed != old_page_options->feed
4970- || perform_feed != old_page_options->perform_feed
4971 || cut_media != old_page_options->cut_media
4972 || mirror != old_page_options->mirror)
4973 /* We only know how to feed after each page */
4974- emit_feed_cut_mirror (perform_feed == CUPS_ADVANCE_PAGE, feed,
4975+ emit_feed_cut_mirror (false, feed,
4976 cut_media == CUPS_CUT_PAGE,
4977 mirror == CUPS_TRUE,
4978- job_options->pixel_xfer == ULP);
4979- /* Set media and quality if label preamble is requested */
4980+ job_options->pixel_xfer);
4981+
4982 unsigned page_size_y = new_page_options->page_size [1];
4983 unsigned image_height_px = lrint (page_size_y * vres / 72.0);
4984- if (job_options->label_preamble && !job_options->concat_pages
4985- && (force
4986- || (new_page_options->roll_fed_media
4987- != old_page_options->roll_fed_media)
4988- || new_page_size_x != old_page_size_x
4989- || page_size_y != old_page_options->page_size [1]))
4990- emit_quality_rollfed_size (job_options, new_page_options,
4991- page_size_y, image_height_px);
4992-
4993- /* WHY DON'T WE SET MARGIN (ESC i d ...)? */
4994
4995 /* Set pixel data transfer compression */
4996 if (force) {
4997@@ -917,7 +971,7 @@
4998 #ifdef DEBUG
4999 if (debug)
5000 fprintf (stderr, "DEBUG: generate_emit_line "
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches