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
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2014-03-06 16:23:54 +0000
+++ .pc/applied-patches 2015-04-10 21:18:54 +0000
@@ -1,2 +1,2 @@
1foomatic-data-fixes.patch1foomatic-data-fixes.patch
2send-esc-i-A-for-QL-only.patch2philpem-ptouch-fixes
33
=== added file '.pc/foomatic-data-fixes.patch/.timestamp'
=== added directory '.pc/philpem-ptouch-fixes'
=== added file '.pc/philpem-ptouch-fixes/.timestamp'
=== added file '.pc/philpem-ptouch-fixes/Makefile.am'
--- .pc/philpem-ptouch-fixes/Makefile.am 1970-01-01 00:00:00 +0000
+++ .pc/philpem-ptouch-fixes/Makefile.am 2015-04-10 21:18:54 +0000
@@ -0,0 +1,91 @@
1## Process this file with automake to produce Makefile.in
2## Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
3##
4## This file is part of ptouch-driver.
5##
6## ptouch-driver is free software; you can redistribute it and/or modify
7## it under the terms of the GNU General Public License as published by
8## the Free Software Foundation; either version 2 of the License, or (at
9## your option) any later version.
10##
11## ptouch-driver is distributed in the hope that it will be useful, but
12## WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14## General Public License for more details.
15##
16## You should have received a copy of the GNU General Public License
17## along with ptouch-driver; if not, write to the Free Software
18## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19## USA
20
21execfilterdir = $(libdir)/cups/filter
22execfilter_PROGRAMS = rastertoptch
23rastertoptch_CPPFLAGS = -D_GNU_SOURCE
24
25foomaticdbdir = $(datadir)/foomatic/db/source
26nobase_dist_foomaticdb_DATA = driver/ptouch.xml \
27 printer/Brother-QL-500.xml \
28 printer/Brother-QL-550.xml \
29 printer/Brother-QL-650TD.xml \
30 printer/Brother-PT-PC.xml \
31 printer/Brother-PT-18R.xml \
32 printer/Brother-PT-1500PC.xml \
33 printer/Brother-PT-1950VP.xml \
34 printer/Brother-PT-1950.xml \
35 printer/Brother-PT-1960.xml \
36 printer/Brother-PT-2300.xml \
37 printer/Brother-PT-2420PC.xml \
38 printer/Brother-PT-2450DX.xml \
39 printer/Brother-PT-2500PC.xml \
40 printer/Brother-PT-2600.xml \
41 printer/Brother-PT-2610.xml \
42 printer/Brother-PT-3600.xml \
43 printer/Brother-PT-550A.xml \
44 printer/Brother-PT-9200DX.xml \
45 printer/Brother-PT-9200PC.xml \
46 printer/Brother-PT-9400.xml \
47 printer/Brother-PT-9500PC.xml \
48 printer/Brother-PT-9600.xml \
49 opt/Brother-Ptouch-AdvanceDistance.xml \
50 opt/Brother-Ptouch-AdvanceMedia.xml \
51 opt/Brother-Ptouch-Align.xml \
52 opt/Brother-Ptouch-BytesPerLine.xml \
53 opt/Brother-Ptouch-ConcatPages.xml \
54 opt/Brother-Ptouch-CutMark.xml \
55 opt/Brother-Ptouch-CutMedia.xml \
56 opt/Brother-Ptouch-HalfCut.xml \
57 opt/Brother-Ptouch-SoftwareMirror.xml \
58 opt/Brother-Ptouch-LabelPreamble.xml \
59 opt/Brother-Ptouch-MirrorPrint.xml \
60 opt/Brother-Ptouch-NegativePrint.xml \
61 opt/Brother-Ptouch-PageSize.xml \
62 opt/Brother-Ptouch-PixelTransfer.xml \
63 opt/Brother-Ptouch-PrintDensity.xml \
64 opt/Brother-Ptouch-PrintQuality.xml \
65 opt/Brother-Ptouch-Resolution.xml \
66 opt/Brother-Ptouch-RollFedMedia.xml \
67 opt/Brother-Ptouch-TransferMode.xml
68
69EXTRA_DIST = Doxyfile $(PACKAGE).spec.in \
70 $(PACKAGE)-foomatic.spec.in
71
72RPMBUILD = rpmbuild -ba
73RPMSOURCESDIR = $(HOME)/src/SOURCES
74
75dist-rpm: $(RPMSOURCESDIR)/$(distdir).tar.gz \
76 $(PACKAGE).spec $(PACKAGE)-foomatic.spec
77 $(RPMBUILD) $(PACKAGE).spec
78 $(RPMBUILD) $(PACKAGE)-foomatic.spec
79
80$(RPMSOURCESDIR)/$(distdir).tar.gz: $(distdir).tar.gz
81 cp $< $@
82
83%.spec: $(srcdir)/%.spec.in $(top_builddir)/config.status
84 @case '$?' in \
85 *config.status*) \
86 echo ' $(SHELL) ./config.status'; \
87 $(SHELL) ./config.status;; \
88 *) \
89 echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
90 cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
91 esac;
092
=== added directory '.pc/philpem-ptouch-fixes/opt'
=== added file '.pc/philpem-ptouch-fixes/opt/Brother-Ptouch-AdvanceMedia.xml'
--- .pc/philpem-ptouch-fixes/opt/Brother-Ptouch-AdvanceMedia.xml 1970-01-01 00:00:00 +0000
+++ .pc/philpem-ptouch-fixes/opt/Brother-Ptouch-AdvanceMedia.xml 2015-04-10 21:18:54 +0000
@@ -0,0 +1,84 @@
1<!--
2Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
3
4This file is part of ptouch-driver.
5
6ptouch-driver is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or (at
9your option) any later version.
10
11ptouch-driver is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with ptouch-driver; if not, write to the Free Software
18Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19USA
20-->
21<option type='enum' id='Brother-Ptouch-AdvanceMedia'>
22 <!-- A multilingual <comments> block can appear here, too;
23 it should be treated as documentation for the user. -->
24 <arg_longname>
25 <en>Advance Media</en>
26 </arg_longname>
27 <arg_shortname>
28 <en>AdvanceMedia</en><!-- backends only know <en> shortnames! -->
29 </arg_shortname>
30 <arg_execution>
31 <arg_group>Finishing</arg_group>
32 <arg_order>110</arg_order>
33 <arg_spot>A</arg_spot>
34 <arg_postscript />
35 <arg_proto>&lt;&lt;/AdvanceMedia %s&gt;&gt;setpagedevice</arg_proto>
36 </arg_execution>
37 <constraints>
38 <constraint sense='true'>
39 <driver>ptouch</driver>
40 <arg_defval>ev/Off</arg_defval>
41 </constraint>
42 </constraints>
43 <enum_vals>
44 <enum_val id="ev/Off">
45 <ev_longname>
46 <en>Do not advance the tape</en>
47 </ev_longname>
48 <!-- A multilingual <comments> block can appear here, too;
49 it should be treated as documentation for the user. -->
50 <ev_shortname>
51 <en>Off</en>
52 <!-- Until someone tells me how to learn the user locale in
53 backends, the shortname must be monolingual in <en>! -->
54 </ev_shortname>
55 <ev_driverval>0</ev_driverval>
56 </enum_val>
57 <enum_val id="ev/LabelEnd">
58 <ev_longname>
59 <en>Advance the tape after each label</en>
60 </ev_longname>
61 <!-- A multilingual <comments> block can appear here, too;
62 it should be treated as documentation for the user. -->
63 <ev_shortname>
64 <en>LabelEnd</en>
65 <!-- Until someone tells me how to learn the user locale in
66 backends, the shortname must be monolingual in <en>! -->
67 </ev_shortname>
68 <ev_driverval>4</ev_driverval>
69 </enum_val>
70 <enum_val id="ev/JobEnd">
71 <ev_longname>
72 <en>Advance the tape at the end of the job</en>
73 </ev_longname>
74 <!-- A multilingual <comments> block can appear here, too;
75 it should be treated as documentation for the user. -->
76 <ev_shortname>
77 <en>JobEnd</en>
78 <!-- Until someone tells me how to learn the user locale in
79 backends, the shortname must be monolingual in <en>! -->
80 </ev_shortname>
81 <ev_driverval>2</ev_driverval>
82 </enum_val>
83 </enum_vals>
84</option>
085
=== added file '.pc/philpem-ptouch-fixes/opt/Brother-Ptouch-RollFedMedia.xml'
--- .pc/philpem-ptouch-fixes/opt/Brother-Ptouch-RollFedMedia.xml 1970-01-01 00:00:00 +0000
+++ .pc/philpem-ptouch-fixes/opt/Brother-Ptouch-RollFedMedia.xml 2015-04-10 21:18:54 +0000
@@ -0,0 +1,84 @@
1<!--
2Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
3
4This file is part of ptouch-driver.
5
6ptouch-driver is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or (at
9your option) any later version.
10
11ptouch-driver is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with ptouch-driver; if not, write to the Free Software
18Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19USA
20-->
21<option type="enum" id="opt/Brother-Ptouch-RollFedMedia">
22 <!-- A multilingual <comments> block can appear here, too;
23 it should be treated as documentation for the user. -->
24 <arg_longname>
25 <en>Roll Fed Media</en>
26 </arg_longname>
27 <arg_shortname>
28 <en>RollFedMedia</en><!-- backends only know <en> shortnames! -->
29 </arg_shortname>
30 <arg_execution>
31 <arg_group>General</arg_group>
32 <arg_order>110</arg_order>
33 <arg_spot>A</arg_spot>
34 <arg_postscript />
35 <arg_proto>%s</arg_proto>
36 </arg_execution>
37 <constraints>
38 <constraint sense='true'>
39 <driver>ptouch</driver>
40 <arg_defval>ev/Auto</arg_defval>
41 </constraint>
42 </constraints>
43 <enum_vals>
44 <enum_val id="ev/Auto">
45 <ev_longname>
46 <en>Automatically determined by page size</en>
47 </ev_longname>
48 <!-- A multilingual <comments> block can appear here, too;
49 it should be treated as documentation for the user. -->
50 <ev_shortname>
51 <en>Auto</en>
52 <!-- Until someone tells me how to learn the user locale in
53 backends, the shortname must be monolingual in <en>! -->
54 </ev_shortname>
55 <ev_driverval></ev_driverval>
56 </enum_val>
57 <enum_val id="ev/Roll">
58 <ev_longname>
59 <en>Continuous roll</en>
60 </ev_longname>
61 <!-- A multilingual <comments> block can appear here, too;
62 it should be treated as documentation for the user. -->
63 <ev_shortname>
64 <en>Roll</en>
65 <!-- Until someone tells me how to learn the user locale in
66 backends, the shortname must be monolingual in <en>! -->
67 </ev_shortname>
68 <ev_driverval>&lt;&lt;/MediaType (roll)&gt;&gt;setpagedevice</ev_driverval>
69 </enum_val>
70 <enum_val id="ev/Labels">
71 <ev_longname>
72 <en>Labels</en>
73 </ev_longname>
74 <!-- A multilingual <comments> block can appear here, too;
75 it should be treated as documentation for the user. -->
76 <ev_shortname>
77 <en>Labels</en>
78 <!-- Until someone tells me how to learn the user locale in
79 backends, the shortname must be monolingual in <en>! -->
80 </ev_shortname>
81 <ev_driverval>&lt;&lt;/MediaType (labels)&gt;&gt;setpagedevice</ev_driverval>
82 </enum_val>
83 </enum_vals>
84</option>
085
=== added directory '.pc/philpem-ptouch-fixes/printer'
=== added file '.pc/philpem-ptouch-fixes/printer/Brother-QL-500.xml'
--- .pc/philpem-ptouch-fixes/printer/Brother-QL-500.xml 1970-01-01 00:00:00 +0000
+++ .pc/philpem-ptouch-fixes/printer/Brother-QL-500.xml 2015-04-10 21:18:54 +0000
@@ -0,0 +1,97 @@
1<!--
2Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
3
4This file is part of ptouch-driver.
5
6ptouch-driver is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or (at
9your option) any later version.
10
11ptouch-driver is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with ptouch-driver; if not, write to the Free Software
18Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19USA
20-->
21<printer id="printer/Brother-QL-500">
22 <make>Brother</make>
23 <model>QL-500</model>
24 <pcmodel>BRQ500</pcmodel>
25 <mechanism>
26 <thermal/>
27 <!--not "color"-->
28 <resolution>
29 <dpi>
30 <x>300</x>
31 <y>300</y>
32 </dpi>
33 </resolution>
34 <consumables>
35 <comments>
36 <en>
37 Special &quot;DK&quot; adhesive labels or adhesive tape thermal paper.
38 No ink or ribbons needed.
39 Die Cut Standard Address Labels 29mm x 90mm, 400 Labels - $7.99
40 Die Cut Shipping Labels 62mm x 100mm, 300 Labels - $13.99
41 Die Cut File Folder Labels 17mm x 87mm, 300 labels - $6.99
42 Multipurpose Die Cut Labels 17mm x 54mm, 400 Labels - $7.99
43 CD/DVD Film Labels 58mm x 58mm, 100 Labels - $14.99
44 Large Die Cut Address Labels 38mm x 90mm, 400 Labels/Roll - $10.99
45 Small Address Label 29mm x 62mm, 800 Labels - $13.99
46 Clear Continuous Film Roll 62mm x 15.24m, Clear - $44.99
47 White Continuous Film Roll 62mm x 30.48m, White - $13.99
48 White Continuous Film Roll 29mm x 30.48m, White - $8.99
49 White Continuous Film Roll 29mm x 15.24m, White - $15.99
50 White Continuous Film Roll 62mm x 15.24m, White - $30.99
51 White Continuous Film Roll 12mm x 30.48m, White - $7.99
52 Yellow Continuous Film Roll 62mm x 15.24m, Yellow - $44.99
53 Cutter Unit, 2 pcs
54 Cleaning Sheets, 10 sheets
55 </en>
56 </comments>
57 <partno>DK-11201</partno>
58 <partno>DK-11202</partno>
59 <partno>DK-11203</partno>
60 <partno>DK-11204</partno>
61 <partno>DK-11207</partno>
62 <partno>DK-11208</partno>
63 <partno>DK-11209</partno>
64 <partno>DK-22113</partno>
65 <partno>DK-22205</partno>
66 <partno>DK-22210</partno>
67 <partno>DK-22211</partno>
68 <partno>DK-22212</partno>
69 <partno>DK-22214</partno>
70 <partno>DK-22606</partno>
71 <partno>DKBU99</partno>
72 <partno>DKCL99</partno>
73 </consumables>
74 </mechanism>
75 <url>http://www.brother.co.uk/cms.cfm/s_page/55570/s_level/17510/s_product/QL500</url>
76 <lang>
77 <proprietary />
78 </lang>
79 <autodetect>
80 <general>
81 <ieee1284>MFG:Brother;CMD:PT-CBP;MDL:QL-500;CLS:PRINTER;</ieee1284>
82 <commandset>PT-CBP</commandset>
83 <description>Brother QL-500</description>
84 <manufacturer>Brother</manufacturer>
85 <model>QL-500</model>
86 </general>
87 </autodetect>
88 <functionality>B</functionality>
89 <driver>ptouch</driver>
90 <unverified />
91 <!--no "contrib_url"-->
92 <comments>
93 <en>
94 Prints 3 inches per second.
95 </en>
96 </comments>
97</printer>
098
=== added file '.pc/philpem-ptouch-fixes/printer/Brother-QL-550.xml'
--- .pc/philpem-ptouch-fixes/printer/Brother-QL-550.xml 1970-01-01 00:00:00 +0000
+++ .pc/philpem-ptouch-fixes/printer/Brother-QL-550.xml 2015-04-10 21:18:54 +0000
@@ -0,0 +1,97 @@
1<!--
2Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
3
4This file is part of ptouch-driver.
5
6ptouch-driver is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or (at
9your option) any later version.
10
11ptouch-driver is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with ptouch-driver; if not, write to the Free Software
18Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19USA
20-->
21<printer id="printer/Brother-QL-550">
22 <make>Brother</make>
23 <model>QL-550</model>
24 <pcmodel>BRQ550</pcmodel>
25 <mechanism>
26 <thermal/>
27 <!--not "color"-->
28 <resolution>
29 <dpi>
30 <x>300</x>
31 <y>300</y>
32 </dpi>
33 </resolution>
34 <consumables>
35 <comments>
36 <en>
37 Special &quot;DK&quot; adhesive labels or adhesive tape thermal paper.
38 No ink or ribbons needed.
39 Die Cut Standard Address Labels 29mm x 90mm, 400 Labels - $7.99
40 Die Cut Shipping Labels 62mm x 100mm, 300 Labels - $13.99
41 Die Cut File Folder Labels 17mm x 87mm, 300 labels - $6.99
42 Multipurpose Die Cut Labels 17mm x 54mm, 400 Labels - $7.99
43 CD/DVD Film Labels 58mm x 58mm, 100 Labels - $14.99
44 Large Die Cut Address Labels 38mm x 90mm, 400 Labels/Roll - $10.99
45 Small Address Label 29mm x 62mm, 800 Labels - $13.99
46 Clear Continuous Film Roll 62mm x 15.24m, Clear - $44.99
47 White Continuous Film Roll 62mm x 30.48m, White - $13.99
48 White Continuous Film Roll 29mm x 30.48m, White - $8.99
49 White Continuous Film Roll 29mm x 15.24m, White - $15.99
50 White Continuous Film Roll 62mm x 15.24m, White - $30.99
51 White Continuous Film Roll 12mm x 30.48m, White - $7.99
52 Yellow Continuous Film Roll 62mm x 15.24m, Yellow - $44.99
53 Cutter Unit, 2 pcs
54 Cleaning Sheets, 10 sheets
55 </en>
56 </comments>
57 <partno>DK-11201</partno>
58 <partno>DK-11202</partno>
59 <partno>DK-11203</partno>
60 <partno>DK-11204</partno>
61 <partno>DK-11207</partno>
62 <partno>DK-11208</partno>
63 <partno>DK-11209</partno>
64 <partno>DK-22113</partno>
65 <partno>DK-22205</partno>
66 <partno>DK-22210</partno>
67 <partno>DK-22211</partno>
68 <partno>DK-22212</partno>
69 <partno>DK-22214</partno>
70 <partno>DK-22606</partno>
71 <partno>DKBU99</partno>
72 <partno>DKCL99</partno>
73 </consumables>
74 </mechanism>
75 <url>http://www.brother.co.uk/cms.cfm/s_page/55570/s_level/17510/s_product/QL550</url>
76 <lang>
77 <proprietary />
78 </lang>
79 <autodetect>
80 <general>
81 <ieee1284>MFG:Brother;CMD:PT-CBP;MDL:QL-550;CLS:PRINTER;</ieee1284>
82 <commandset>PT-CBP</commandset>
83 <description>Brother QL-550</description>
84 <manufacturer>Brother</manufacturer>
85 <model>QL-550</model>
86 </general>
87 </autodetect>
88 <functionality>B</functionality>
89 <driver>ptouch</driver>
90 <unverified />
91 <!--no "contrib_url"-->
92 <comments>
93 <en>
94 Prints 3 inches per second.
95 </en>
96 </comments>
97</printer>
098
=== added file '.pc/philpem-ptouch-fixes/printer/Brother-QL-650TD.xml'
--- .pc/philpem-ptouch-fixes/printer/Brother-QL-650TD.xml 1970-01-01 00:00:00 +0000
+++ .pc/philpem-ptouch-fixes/printer/Brother-QL-650TD.xml 2015-04-10 21:18:54 +0000
@@ -0,0 +1,97 @@
1<!--
2Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
3
4This file is part of ptouch-driver.
5
6ptouch-driver is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or (at
9your option) any later version.
10
11ptouch-driver is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with ptouch-driver; if not, write to the Free Software
18Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19USA
20-->
21<printer id="printer/Brother-QL-650TD">
22 <make>Brother</make>
23 <model>QL-650TD</model>
24 <pcmodel>BRQ650</pcmodel>
25 <mechanism>
26 <thermal/>
27 <!--not "color"-->
28 <resolution>
29 <dpi>
30 <x>300</x>
31 <y>300</y>
32 </dpi>
33 </resolution>
34 <consumables>
35 <comments>
36 <en>
37 Special &quot;DK&quot; adhesive labels or adhesive tape thermal paper.
38 No ink or ribbons needed.
39 Die Cut Standard Address Labels 29mm x 90mm, 400 Labels - $7.99
40 Die Cut Shipping Labels 62mm x 100mm, 300 Labels - $13.99
41 Die Cut File Folder Labels 17mm x 87mm, 300 labels - $6.99
42 Multipurpose Die Cut Labels 17mm x 54mm, 400 Labels - $7.99
43 CD/DVD Film Labels 58mm x 58mm, 100 Labels - $14.99
44 Large Die Cut Address Labels 38mm x 90mm, 400 Labels/Roll - $10.99
45 Small Address Label 29mm x 62mm, 800 Labels - $13.99
46 Clear Continuous Film Roll 62mm x 15.24m, Clear - $44.99
47 White Continuous Film Roll 62mm x 30.48m, White - $13.99
48 White Continuous Film Roll 29mm x 30.48m, White - $8.99
49 White Continuous Film Roll 29mm x 15.24m, White - $15.99
50 White Continuous Film Roll 62mm x 15.24m, White - $30.99
51 White Continuous Film Roll 12mm x 30.48m, White - $7.99
52 Yellow Continuous Film Roll 62mm x 15.24m, Yellow - $44.99
53 Cutter Unit, 2 pcs
54 Cleaning Sheets, 10 sheets
55 </en>
56 </comments>
57 <partno>DK-11201</partno>
58 <partno>DK-11202</partno>
59 <partno>DK-11203</partno>
60 <partno>DK-11204</partno>
61 <partno>DK-11207</partno>
62 <partno>DK-11208</partno>
63 <partno>DK-11209</partno>
64 <partno>DK-22113</partno>
65 <partno>DK-22205</partno>
66 <partno>DK-22210</partno>
67 <partno>DK-22211</partno>
68 <partno>DK-22212</partno>
69 <partno>DK-22214</partno>
70 <partno>DK-22606</partno>
71 <partno>DKBU99</partno>
72 <partno>DKCL99</partno>
73 </consumables>
74 </mechanism>
75 <url>http://www.advizia.com/brother/modelDetail.asp?PkgID=386702&amp;User=ptouch&amp;Rnd=785</url>
76 <lang>
77 <proprietary />
78 </lang>
79 <autodetect>
80 <general>
81 <ieee1284>MFG:Brother;CMD:PT-CBP;MDL:QL-650TD;CLS:PRINTER;</ieee1284>
82 <commandset>PT-CBP</commandset>
83 <description>Brother QL-650TD</description>
84 <manufacturer>Brother</manufacturer>
85 <model>QL-650TD</model>
86 </general>
87 </autodetect>
88 <functionality>B</functionality>
89 <driver>ptouch</driver>
90 <unverified />
91 <!--no "contrib_url"-->
92 <comments>
93 <en>
94 Prints 3 inches per second.
95 </en>
96 </comments>
97</printer>
098
=== added file '.pc/philpem-ptouch-fixes/ptouch-driver-foomatic.spec.in'
--- .pc/philpem-ptouch-fixes/ptouch-driver-foomatic.spec.in 1970-01-01 00:00:00 +0000
+++ .pc/philpem-ptouch-fixes/ptouch-driver-foomatic.spec.in 2015-04-10 21:18:54 +0000
@@ -0,0 +1,102 @@
1## -*- RPM-spec -*- file for the ptouch-driver package
2## Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
3##
4## This file is part of ptouch-driver.
5##
6## ptouch-driver is free software; you can redistribute it and/or modify
7## it under the terms of the GNU General Public License as published by
8## the Free Software Foundation; either version 2 of the License, or (at
9## your option) any later version.
10##
11## ptouch-driver is distributed in the hope that it will be useful, but
12## WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14## General Public License for more details.
15##
16## You should have received a copy of the GNU General Public License
17## along with ptouch-driver; if not, write to the Free Software
18## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19## USA
20Name: ptouch-driver-foomatic
21Version: @VERSION@
22Release: 1
23Summary: Foomatic database data for Brother P-touch label printers
24
25Group: System Environment/Libraries
26License: GPL
27URL: http://ptouch-driver.sourceforge.net/
28Source0: ptouch-driver-%{version}.tar.gz
29BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
30
31Requires: foomatic ptouch-driver
32
33%description
34The ptouch-driver consists of a CUPS raster filter and foomatic
35database XML documents for driving the family of Brother P-touch label
36printers.
37
38%prep
39%setup -q -n ptouch-driver-%{version}
40
41%build
42%configure
43
44%install
45rm -rf $RPM_BUILD_ROOT
46make install-data DESTDIR=$RPM_BUILD_ROOT
47
48%clean
49rm -rf $RPM_BUILD_ROOT
50
51
52%files
53%defattr(-,root,root,-)
54%doc AUTHORS ChangeLog COPYING NEWS README
55/usr/share/foomatic/db/source/driver/ptouch.xml
56/usr/share/foomatic/db/source/printer/Brother-PT-1500PC.xml
57/usr/share/foomatic/db/source/printer/Brother-PT-18R.xml
58/usr/share/foomatic/db/source/printer/Brother-PT-1950VP.xml
59/usr/share/foomatic/db/source/printer/Brother-PT-1950.xml
60/usr/share/foomatic/db/source/printer/Brother-PT-1960.xml
61/usr/share/foomatic/db/source/printer/Brother-PT-2300.xml
62/usr/share/foomatic/db/source/printer/Brother-PT-2420PC.xml
63/usr/share/foomatic/db/source/printer/Brother-PT-2450DX.xml
64/usr/share/foomatic/db/source/printer/Brother-PT-2500PC.xml
65/usr/share/foomatic/db/source/printer/Brother-PT-2600.xml
66/usr/share/foomatic/db/source/printer/Brother-PT-2610.xml
67/usr/share/foomatic/db/source/printer/Brother-PT-3600.xml
68/usr/share/foomatic/db/source/printer/Brother-PT-550A.xml
69/usr/share/foomatic/db/source/printer/Brother-PT-9200DX.xml
70/usr/share/foomatic/db/source/printer/Brother-PT-9200PC.xml
71/usr/share/foomatic/db/source/printer/Brother-PT-9400.xml
72/usr/share/foomatic/db/source/printer/Brother-PT-9500PC.xml
73/usr/share/foomatic/db/source/printer/Brother-PT-9600.xml
74/usr/share/foomatic/db/source/printer/Brother-PT-PC.xml
75/usr/share/foomatic/db/source/printer/Brother-QL-500.xml
76/usr/share/foomatic/db/source/printer/Brother-QL-550.xml
77/usr/share/foomatic/db/source/printer/Brother-QL-650TD.xml
78/usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceDistance.xml
79/usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceMedia.xml
80/usr/share/foomatic/db/source/opt/Brother-Ptouch-Align.xml
81/usr/share/foomatic/db/source/opt/Brother-Ptouch-BytesPerLine.xml
82/usr/share/foomatic/db/source/opt/Brother-Ptouch-ConcatPages.xml
83/usr/share/foomatic/db/source/opt/Brother-Ptouch-CutMark.xml
84/usr/share/foomatic/db/source/opt/Brother-Ptouch-CutMedia.xml
85/usr/share/foomatic/db/source/opt/Brother-Ptouch-HalfCut.xml
86/usr/share/foomatic/db/source/opt/Brother-Ptouch-LabelPreamble.xml
87/usr/share/foomatic/db/source/opt/Brother-Ptouch-MirrorPrint.xml
88/usr/share/foomatic/db/source/opt/Brother-Ptouch-NegativePrint.xml
89/usr/share/foomatic/db/source/opt/Brother-Ptouch-PageSize.xml
90/usr/share/foomatic/db/source/opt/Brother-Ptouch-PixelTransfer.xml
91/usr/share/foomatic/db/source/opt/Brother-Ptouch-PrintDensity.xml
92/usr/share/foomatic/db/source/opt/Brother-Ptouch-PrintQuality.xml
93/usr/share/foomatic/db/source/opt/Brother-Ptouch-Resolution.xml
94/usr/share/foomatic/db/source/opt/Brother-Ptouch-RollFedMedia.xml
95/usr/share/foomatic/db/source/opt/Brother-Ptouch-SoftwareMirror.xml
96/usr/share/foomatic/db/source/opt/Brother-Ptouch-TransferMode.xml
97
98
99%changelog
100* Mon Jan 30 2006 Arne John Glenstrup <panic@itu.dk> - 0.9-1
101- Initial build.
102
0103
=== added file '.pc/philpem-ptouch-fixes/rastertoptch.c'
--- .pc/philpem-ptouch-fixes/rastertoptch.c 1970-01-01 00:00:00 +0000
+++ .pc/philpem-ptouch-fixes/rastertoptch.c 2015-04-10 21:18:54 +0000
@@ -0,0 +1,1590 @@
1/* rastertoptch is a filter to convert CUPS raster data into a Brother
2 * P-touch label printer command byte stream.
3 *
4 * Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
5 *
6 * This file is part of ptouch-driver
7 *
8 * ptouch-driver is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * ptouch-driver is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with ptouch-driver; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 *
23 * Please note: This software is not in any way related to Brother
24 * Industries, Ltd., except that it is intended for use with their
25 * products. Any comments to this software should NOT be directed to
26 * Brother Industries, Ltd.
27 */
28
29/** @file
30 * This filter processes CUPS raster data, converting it into a byte
31 * stream on stdout suitable for sending directly to a label printer
32 * of the Brother P-touch family.
33 *
34 * @version 1.2
35 * @author Arne John Glenstrup <panic@itu.dk>
36 * @date 2006
37
38 * <h2>Invocation</h2>
39 * The filter is invoked thus:
40 *
41 * rastertoptch job user title copies options [filename]
42 *
43 * @param printer The name of the printer queue (ignored)
44 * @param job The numeric job ID (ignored)
45 * @param user The string from the originating-user-name (ignored)
46 * @param title The string from the job-name attribute (ignored)
47 * @param copies The number of copies to be printed (ignored)
48 * @param options String representations of the job template
49 * parameters, separated by spaces. Boolean attributes
50 * are provided as "name" for true values and "noname"
51 * for false values. All other attributes are provided
52 * as "name=value" for single-valued attributes and
53 * "name=value1,value2,...,valueN" for set attributes
54 * @param filename The request file (if omitted, read from stdin)
55 *
56 * Available options (default values in [brackets]):
57 *
58 * @param PixelXfer=ULP|RLE|BIP Use uncompressed line printing (ULP),
59 * run-length encoding (RLE) or bit
60 * image printing (BIP) when emitting
61 * pixel data [ULP]
62 * @param PrintQuality=High|Fast Use high quality or fast printing [High]
63 * @param HalfCut Perform half-cut (crack & peel) when
64 * cutting [noHalfCut]
65 * @param BytesPerLine=N Emit N bytes per line [90]
66 * @param Align=Right|Center Pixel data alignment on tape [Right]
67 * @param PrintDensity=1|...|5 Print density level: 1=light, 5=dark
68 * @param ConcatPages Output all pages in one page [noConcatPages]
69 * @param RLEMemMax Maximum memory used for RLE buffer [1000000]
70 * @param SoftwareMirror Make the filter mirror pixel data
71 * if MirrorPrint is requested [noSoftwareMirror]
72 * @param LabelPreamble Emit preamble containing print quality,
73 * roll/label type, tape width, label height,
74 * and pixel lines [noLabelPreamble]
75 * @param Debug Emit diagnostic output to stderr [noDebug]
76 * (only if compiled with DEBUG set)
77 *
78 * Information about media type, resolution, mirror print, negative
79 * print, cut media, advance distance (feed) is extracted from the
80 * CUPS raster page headers given in the input stream. The MediaType
81 * page header field can be either "roll" or "labels" for continuous
82 * tape or pre-cut labels, respectively.
83 *
84 * LabelPreamble should usually not be used for the PT series printers.
85 *
86 * <h2>Output</h2>
87 * Each invocation of this filter is one job, containing a number of
88 * pages, each page containing a number of lines, each line consisting
89 * of a number of pixel bytes.
90 *
91 * Output consists of job-related printer initialisation commands,
92 * followed by a number of pages, each page consisting of page-related
93 * commands, followed by raster line data. Each page is followed by a
94 * finish page or (after the final page) finish job command.
95 *
96 * The following printer command language, printer, and tape
97 * information has been deduced from many sources, but is not official
98 * Brother documentation and may thus contain errors. Please send any
99 * corrections based on actual experience with these printers to the
100 * maintainer.
101 *
102 * <h3>Job-related commands</h3>
103 * <table>
104 * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
105 * <tr><td>ESC @ (1b 40)</td>
106 <td>Initialise</td><td>Clear print buffer</td></tr>
107 * <tr><td>ESC i D # (1b 69 44 ##)
108 * <td>Set print density</td>
109 * <td>bit 0-3: 0=no change, 1-5=density level</td></tr>
110 * <tr><td>ESC i K # (1b 69 4b ##)
111 * <td>Set half cut</td>
112 * <td>bit 2: 0=full cut, 1=half cut</td></tr>
113 * <tr><td>ESC i R ## (1b 69 52 ##)</td>
114 * <td>Set transfer mode</td>
115 * <td>##: ?: 1=?</td></tr>
116 * <tr><td>M ## (4d ##)</td>
117 * <td>Set compression</td>
118 * <td>##: Compression type: 2=RLE</td></tr>
119 * </table>
120 *
121 * <h3>Page-related commands</h3>
122 * <table>
123 * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
124 * <tr><td>ESC i c #1 #2 #3 NUL #4 <br>(1b 63 #1 #2 #3 00 #4)
125 * <td>Set width & resolution</td>
126 * <td>360x360DPI: #1 #2 #4 = 0x84 0x00 0x00<br>
127 * 360x720DPI: #1 #2 #4 = 0x86 0x09 0x01<br>
128 * #3: Tape width in mm</td></tr>
129 * <tr><td>ESC i M # <br>(1b 69 4d ##)</td>
130 * <td>Set mode</td>
131 * <td>bit 0-4: Feed amount (default=large): 0-7=none, 8-11=small,
132 * 12-25=medium, 26-31=large<br>
133 * bit 6: Auto cut/cut mark (default=on): 0=off, 1=on<br>
134 * bit 7: Mirror print (default=off): 0=off, 1=on.
135 * (note that it seems that QL devices do not reverse the
136 * data stream themselves, but rely on the driver doing
137 * it!)</td></tr>
138 * <tr><td>ESC i z #1 #2 #3 #4 #5 #6 NUL NUL NUL NUL<br>
139 * (1b 69 7a #1 #2 #3 #4 #5 #6 00 00 00 00)</td>
140 * <td>Set media & quality</td>
141 * <td>#1, bit 6: Print quality: 0=fast, 1=high<br>
142 * #2, bit 0: Media type: 0=continuous roll,
143 * 1=pre-cut labels<br>
144 * #3: Tape width in mm<br>
145 * #4: Label height in mm (0 for continuous roll)<br>
146 * #5 #6: Page consists of N=#5+256*#6 pixel lines</td></tr>
147 * <tr><td>ESC i d #1 #2 <br>(1b 69 64 #1 #2)</td>
148 * <td>Set margin</td>
149 * <td>Set size of right(?) margin to N=#1+256*#2 pixels</td></tr>
150 * <tr><td>FF (0c)</td>
151 * <td>Form feed</td>
152 * <td>Print buffer data without ejecting.</td></tr>
153 * <tr><td>SUB (1a)</td>
154 * <td>Eject</td>
155 * <td>Print buffer data and ejects.</td></tr>
156 * </table>
157 *
158 * <h3>Line-related commands</h3>
159 * <table>
160 * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
161 * <tr><td>G #1 #2 ...data... <br>(47 #1 #2 ...data...)</td>
162 * <td>Send raster line</td>
163 * <td>data consists of
164 * N=#1+256*#2 bytes of RLE compressed raster data.
165 * </td></tr>
166 * <tr><td>Z (5a)</td>
167 * <td>Advance tape</td><td>Print 1 empty line</td></tr>
168 * <tr><td>g #1 #2 ...data... <br>(67 #1 #2 ...data...)</td>
169 * <td>Send raster line</td>
170 * <td>data consists of
171 * N=#2 bytes of uncompressed raster data.</td></tr>
172 * <tr><td>ESC * ' #1 #2 ...data... <br>(1b 2a 27 #1 #2 ...data...)</td>
173 * <td>Bit image printing (BIP)</td>
174 * <td>Print N=#1+256*#2 lines of 24 pixels; data consists of 3*N
175 * bytes</td></tr>
176 * </table>
177 *
178 * <h3>Compressed-data-related commands (RLE)</h3>
179 * <table>
180 * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
181 * <tr><td>#1 ...data...</td>
182 * <td>#1 >= 0: Print uncompressed</td>
183 * <td>data consists of 1+#1 uncompressed bytes</td></tr>
184 * <tr><td>#1 #2</td>
185 * <td>#1 < 0: Print compressed</td>
186 * <td>#2 should be printed 1-#1 times</td></tr>
187 * </table>
188 * #1 is represented as a 2-complement signed integer.
189 *
190 * <h2>Printer model characteristics</h2>
191 * The following table lists for each model what kind of cutter it has
192 * (manual, auto, half cut), what kind of pixel data transfer mode it
193 * requires, its resolution, number of print head pixels, number of
194 * bytes of pixel data that must be transmitted per line (regardless
195 * of actual tape width!), and what kinds of tape it can take.
196 *
197 * For PC models, pixel data must be centered, so narrow tapes require
198 * padding raster data with zero bits on each side. For QL models,
199 * labels are left-aligned, so pixel data must be right aligned, so
200 * narrow tapes require padding raster data with zero bits at the end.
201 *
202 * For PC-PT, only the central 24 pixels (= 3,4mm!) can be used for
203 * pixel-based graphics. It might be possible to print several strips
204 * of 24 pixels side-by side by issuing CR and line-positioning
205 * commands. That is currently not supported, let alone attempted,
206 * with this driver.
207 *
208 * <table>
209 * <tr><th>Model <th>Cutter <th>Xfer<th>DPI<th>Pixels<th>Bytes<th>Tape
210 * <tr><td>QL-500 <td>manual <td>ULP<td>300<td>720<td>90<td>DK12-62mm
211 * <tr><td>QL-550 <td>auto <td>ULP<td>300<td>720<td>90<td>DK12-62mm
212 * <tr><td>QL-650TD <td>auto <td>ULP<td>300<td>720<td>90<td>DK12-62mm
213 * <tr><td>PT-PC <td>auto <td>BIP<td>180<td>128<td> 3<td>TZ6-24mm
214 * <tr><td>PT-18R <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-18mm
215 * <tr><td>PT-550A <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-36mm
216 * <tr><td>PT-1500PC<td>manual <td>RLE<td>180<td>112<td>14<td>TZ6-24mm
217 * <tr><td>PT-1950 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-18mm
218 * <tr><td>PT-1950VP<td>auto <td>RLE<td>180<td>112<td>14<td>TZ6-18mm
219 * <tr><td>PT-1960 <td>auto <td>RLE<td>180<td> 96<td>12<td>TZ6-18mm
220 * <tr><td>PT-2300 <td>auto <td>RLE<td>180<td>112<td>14<td>TZ6-18mm
221 * <tr><td>PT-2420PC<td>manual <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
222 * <tr><td>PT-2450DX<td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
223 * <tr><td>PT-2500PC<td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
224 * <tr><td>PT-2600 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ,AV6-24mm
225 * <tr><td>PT-2610 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ,AV6-24mm
226 * <tr><td>PT-3600 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ,AV6-36mm
227 * <tr><td>PT-9200DX<td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
228 * <tr><td>PT-9200PC<td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
229 * <tr><td>PT-9400 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
230 * <tr><td>PT-9500PC<td>auto/half<td>RLE<td>360<br>
231 360x720<td>384<td>48<td>TZ,AV6-36mm
232 * <tr><td>PT-9600 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ,AV6-36mm
233 * </table>
234 *
235 * <h2>Tape characteristics</h2>
236 * <table>
237 * <tr><th>Tape width
238 * <th colspan=2>Print area <th>Margins</th><th>DPI</th></tr>
239 * <tr><td>62mm<td>61.0mm<td>720pixels</td><td>0.5mm</td><td>300</td></tr>
240 * <tr><td>36mm<td>27.1mm<td>384pixels</td><td>4.5mm</td><td>360</td></tr>
241 * <tr><td>24mm<td>18.0mm<td>128pixels</td><td>3mm</td><td>180</td></tr>
242 * <tr><td>18mm<td>12.0mm<td> 85pixels</td><td>3mm</td><td>180</td></tr>
243 * <tr><td>12mm<td> 8.0mm<td> 57pixels</td><td>2mm</td><td>180</td></tr>
244 * <tr><td> 9mm<td> 6.9mm<td> 49pixels</td><td>1mm</td><td>180</td></tr>
245 * <tr><td> 6mm<td> 3.9mm<td> 28pixels</td><td>1mm</td><td>180</td></tr>
246 * </table>
247 *
248 * <h2>Notes</h2>
249 * - Pixels bytes sent are printed from right to left, with bit 7
250 * rightmost!
251 * - Bit image printing (BIP) using "ESC * ' #1 #2 ...data..."
252 * probably only works for the PT-PC model.
253 * - QL Printer documentation might state that the print area is less
254 * than 61mm, which is probably to ensure that printed pixels stay
255 * within the tape even if it is not precisely positioned. The
256 * print head really IS 720 pixels.
257 */
258/** Default pixel transfer method */
259#define PIXEL_XFER_DEFAULT RLE
260/** Default print quality */
261#define PRINT_QUALITY_HIGH_DEFAULT true
262/** Default half cut mode */
263#define HALF_CUT_DEFAULT false
264/** Maximum number of bytes per line */
265#define BYTES_PER_LINE_MAX 255 /* cf. ULP_emit_line */
266/** Default number of bytes per line */
267#define BYTES_PER_LINE_DEFAULT 90
268/** Default pixel data alignment on narrow tapes */
269#define ALIGN_DEFAULT RIGHT
270/** Maximum print density value */
271#define PRINT_DENSITY_MAX 5
272/** Default print density value (1: light, ..., 5:dark, 0: no change) */
273#define PRINT_DENSITY_DEFAULT 0
274/** Transfer mode default ??? (-1 = don't set) */
275#define TRANSFER_MODE_DEFAULT -1
276/** Driver pixel data mirroring default */
277#define SOFTWARE_MIRROR_DEFAULT false
278/** Label preamble emitting default */
279#define LABEL_PREAMBLE_DEFAULT false
280/** Interlabel margin removal default */
281#define CONCAT_PAGES_DEFAULT false
282/** RLE buffer maximum memory usage */
283#define RLE_ALLOC_MAX_DEFAULT 1000000
284/** Mirror printing default */
285#define MIRROR_DEFAULT false
286/** Negative printing default */
287#define NEGATIVE_DEFAULT false
288/** Cut media mode default */
289#define CUT_MEDIA_DEFAULT CUPS_CUT_NONE
290/** Roll fed media default */
291#define ROLL_FED_MEDIA_DEFAULT true
292/** Device resolution default in DPI */
293#define RESOLUTION_DEFAULT { 300, 300 }
294/** Page size default in PostScript points */
295#define PAGE_SIZE_DEFAULT { 176, 142 } /* 62x50mm */
296/** Image size default in pixels */
297#define IMAGE_HEIGHT_DEFAULT 0
298/** Feed amount default */
299#define FEED_DEFAULT 0
300/** When to perform feed default */
301#define PERFORM_FEED_DEFAULT CUPS_ADVANCE_NONE
302
303#include <config.h>
304#include <stdio.h>
305#include <unistd.h>
306#include <limits.h>
307#include <stdlib.h>
308#include <string.h>
309#include <errno.h>
310#include <fcntl.h>
311#include <signal.h>
312#include <math.h>
313#include <cups/raster.h>
314#include <cups/cups.h>
315
316#if STDC_HEADERS
317# include <string.h>
318#else
319# if !HAVE_MEMCPY
320# define memcpy(d, s, n) bcopy ((s), (d), (n))
321# endif
322#endif
323#if HAVE_STDBOOL_H
324# include <stdbool.h>
325#else
326# if ! HAVE__BOOL
327# ifdef __cplusplus
328typedef bool _Bool;
329# else
330typedef unsigned char _Bool;
331# endif
332# endif
333# define bool _Bool
334# define false 0
335# define true 1
336# define __bool_true_false_are_defined 1
337#endif
338
339
340
341#ifdef DEBUG
342#include <sys/times.h>
343/** Debug flag */
344int debug = 0;
345/** Number of emitted lines */
346unsigned emitted_lines = 0;
347#endif
348
349/** Length of a PostScript point in mm */
350#define MM_PER_PT (25.4 / 72.0)
351/** Printer code: Eject */
352#define PTC_EJECT 0x1a
353/** Printer code: Form feed */
354#define PTC_FORMFEED 0x0c
355
356/** ASCII escape value */
357#define ESC 0x1b
358
359/**
360 * Pixel transfer mode type.
361 */
362typedef enum {
363 ULP, /**< Uncompressed line printing */
364 RLE, /**< Run-length encoding */
365 BIP, /**< Bit image printing */
366} xfer_t;
367
368/**
369 * Pixel data alignment type.
370 */
371typedef enum {RIGHT, CENTER} align_t;
372
373/** Flag signalling whether any errors were encountered. */
374int error_occurred;
375
376/** CUPS Raster line buffer. */
377unsigned char* buffer;
378/** Buffer holding line data to emit to the printer. */
379unsigned char* emit_line_buffer;
380/** Buffer holding RLE line data to emit to the printer. */
381unsigned char* rle_buffer = NULL;
382/** Pointer to first free pos in rle_buffer. */
383unsigned char* rle_buffer_next = NULL;
384/** Size of rle_buffer. */
385unsigned long rle_alloced = 0;
386/** Number of empty lines (input data only zeros) waiting to be stored */
387int empty_lines = 0;
388/** Number of pixel lines waiting to be emitted. */
389unsigned lines_waiting = 0;
390/** Threshold for flushing waiting lines to printer. */
391unsigned max_lines_waiting = INT_MAX;
392
393/** Macro for obtaining integer option values. */
394#define OBTAIN_INT_OPTION(name, var, min, max) \
395 cups_option \
396 = cupsGetOption (name, num_options, cups_options); \
397 if (cups_option) { \
398 errno = 0; \
399 char* rest; \
400 long int var = strtol (cups_option, &rest, 0); \
401 if (errno || *rest != '\0' || rest == cups_option \
402 || var < min || var > max) { \
403 fprintf (stderr, "ERROR: " name " '%s', " \
404 "must be an integer N, where %ld <= N <= %ld\n", \
405 cups_option, (long) min, (long) max); \
406 error_occurred = 1; \
407 } else \
408 options.var = var; \
409 }
410
411/** Macro for obtaining boolean option values. */
412#define OBTAIN_BOOL_OPTION(name, var) \
413 cups_option \
414 = cupsGetOption (name, num_options, cups_options); \
415 if (cups_option) options.var = true; \
416 cups_option \
417 = cupsGetOption ("no"name, num_options, cups_options); \
418 if (cups_option) options.var = false; \
419
420/**
421 * Struct type for holding all the job options.
422 */
423typedef struct {
424 xfer_t pixel_xfer; /**< pixel transfer mode */
425 cups_bool_t print_quality_high; /**< print quality is high */
426 bool half_cut; /**< half cut */
427 int bytes_per_line; /**< bytes per line (print head width) */
428 align_t align; /**< pixel data alignment */
429 int software_mirror; /**< mirror pixel data if mirror printing */
430 int print_density; /**< printing density (0=don't change) */
431 int xfer_mode; /**< transfer mode ??? */
432 int label_preamble; /**< emit ESC i z ... */
433 bool concat_pages; /**< remove interlabel margins */
434 unsigned long rle_alloc_max; /**< max bytes used for rle_buffer */
435} job_options_t;
436
437/**
438 * Struct type for holding current page options.
439 */
440typedef struct {
441 cups_cut_t cut_media; /**< cut media mode */
442 cups_bool_t mirror; /**< mirror printing */
443 bool roll_fed_media; /**< continuous (not labels) roll media */
444 unsigned resolution [2]; /**< horiz & vertical resolution in DPI */
445 unsigned page_size [2]; /**< width & height of page in points */
446 unsigned image_height; /**< height of page image in pixels */
447 unsigned feed; /**< feed size in points */
448 cups_adv_t perform_feed; /**< When to feed */
449} page_options_t;
450
451/**
452 * Parse options given in command line argument 5.
453 * @param argc number of command line arguments plus one
454 * @param argv command line arguments
455 * @return options, where each option set to its default value if
456 * not specified in argv [5]
457 */
458job_options_t
459parse_options (int argc, const char* argv []) {
460 job_options_t options = {
461 PIXEL_XFER_DEFAULT,
462 PRINT_QUALITY_HIGH_DEFAULT,
463 HALF_CUT_DEFAULT,
464 BYTES_PER_LINE_DEFAULT,
465 ALIGN_DEFAULT,
466 SOFTWARE_MIRROR_DEFAULT,
467 PRINT_DENSITY_DEFAULT,
468 TRANSFER_MODE_DEFAULT,
469 LABEL_PREAMBLE_DEFAULT,
470 CONCAT_PAGES_DEFAULT,
471 RLE_ALLOC_MAX_DEFAULT,
472 };
473 if (argc < 6) return options;
474 int num_options = 0;
475 cups_option_t* cups_options = NULL;
476 num_options
477 = cupsParseOptions (argv [5], num_options, &cups_options);
478 const char* cups_option
479 = cupsGetOption ("PixelXfer", num_options, cups_options);
480 if (cups_option) {
481 if (strcasecmp (cups_option, "ULP") == 0)
482 options.pixel_xfer = ULP;
483 else if (strcasecmp (cups_option, "RLE") == 0)
484 options.pixel_xfer = RLE;
485 else if (strcasecmp (cups_option, "BIP") == 0)
486 options.pixel_xfer = BIP;
487 else {
488 fprintf (stderr, "ERROR: Unknown PicelXfer '%s', "
489 "must be RLE, BIP or ULP\n", cups_option);
490 error_occurred = 1;
491 }
492 }
493 cups_option
494 = cupsGetOption ("PrintQuality", num_options, cups_options);
495 if (cups_option) {
496 if (strcasecmp (cups_option, "High") == 0)
497 options.print_quality_high = true;
498 else if (strcasecmp (cups_option, "Fast") == 0)
499 options.print_quality_high = false;
500 else {
501 fprintf (stderr, "ERROR: Unknown PrintQuality '%s', "
502 "must be High or Fast\n", cups_option);
503 error_occurred = 1;
504 }
505 }
506 OBTAIN_BOOL_OPTION ("HalfCut", half_cut);
507 OBTAIN_INT_OPTION ("BytesPerLine", bytes_per_line,
508 1, BYTES_PER_LINE_MAX);
509 cups_option
510 = cupsGetOption ("Align", num_options, cups_options);
511 if (cups_option) {
512 if (strcasecmp (cups_option, "Right") == 0)
513 options.align = RIGHT;
514 else if (strcasecmp (cups_option, "Center") == 0)
515 options.align = CENTER;
516 else {
517 fprintf (stderr, "ERROR: Unknown Align '%s', "
518 "must be Right or Center\n", cups_option);
519 error_occurred = 1;
520 }
521 }
522 OBTAIN_INT_OPTION ("PrintDensity", print_density,
523 0, PRINT_DENSITY_MAX);
524 OBTAIN_BOOL_OPTION ("ConcatPages", concat_pages);
525 OBTAIN_INT_OPTION ("RLEMemMax", rle_alloc_max, 0, LONG_MAX);
526 OBTAIN_INT_OPTION ("TransferMode", xfer_mode, 0, 255);
527 OBTAIN_BOOL_OPTION ("SoftwareMirror", software_mirror);
528 OBTAIN_BOOL_OPTION ("LabelPreamble", label_preamble);
529 /* Release memory allocated for CUPS options struct */
530 cupsFreeOptions (num_options, cups_options);
531 return options;
532}
533
534/**
535 * Determine input stream and open it. If there are 6 command line
536 * arguments, argv[6] is taken to be the input file name
537 * otherwise stdin is used. This funtion exits the program on error.
538 * @param argc number of command line arguments plus one
539 * @param argv command line arguments
540 * @return file descriptor for the opened input stream
541 */
542int
543open_input_file (int argc, const char* argv []) {
544 int fd;
545 if (argc == 7) {
546 if ((fd = open (argv[6], O_RDONLY)) < 0) {
547 perror ("ERROR: Unable to open raster file - ");
548 sleep (1);
549 exit (1);
550 }
551 } else
552 fd = 0;
553 return fd;
554}
555
556/**
557 * Update page_options with information found in header.
558 * @param header CUPS page header
559 * @param page_options page options to be updated
560 */
561void
562update_page_options (cups_page_header_t* header,
563 page_options_t* page_options) {
564 page_options->cut_media = header->CutMedia;
565 page_options->mirror = header->MirrorPrint;
566 const char* media_type = header->MediaType;
567 page_options->roll_fed_media /* Default is continuous roll */
568 = (strcasecmp ("Labels", media_type) != 0);
569 page_options->resolution [0] = header->HWResolution [0];
570 page_options->resolution [1] = header->HWResolution [1];
571 page_options->page_size [0] = header->PageSize [0];
572 page_options->page_size [1] = header->PageSize [1];
573 page_options->image_height = header->cupsHeight;
574 page_options->feed = header->AdvanceDistance;
575 page_options->perform_feed = header->AdvanceMedia;
576}
577
578void cancel_job (int signal);
579/**
580 * Prepare for a new page by setting up signalling infrastructure and
581 * memory allocation.
582 * @param cups_buffer_size Required size of CUPS raster line buffer
583 * @param device_buffer_size Required size of device pixel line buffer
584 */
585void
586page_prepare (unsigned cups_buffer_size, unsigned device_buffer_size) {
587 /* Set up signalling to handle print job cancelling */
588#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
589 struct sigaction action;
590#endif
591
592#ifdef HAVE_SIGSET
593 sigset (SIGTERM, cancel_job);
594#elif defined(HAVE_SIGACTION)
595 memset (&action, 0, sizeof (action));
596 sigemptyset (&action.sa_mask);
597 action.sa_handler = cancel_job;
598 sigaction (SIGTERM, &action, NULL);
599#else
600 signal (SIGTERM, cancel_job);
601#endif
602
603 /* Allocate line buffer */
604 buffer = malloc (cups_buffer_size);
605 emit_line_buffer = malloc (device_buffer_size);
606 if (!buffer || !emit_line_buffer) {
607 fprintf
608 (stderr,
609 "ERROR: Cannot allocate memory for raster line buffer\n");
610 exit (1);
611 }
612}
613
614/**
615 * Clean up signalling and memory after emitting a page
616*/
617void
618page_end () {
619#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
620 struct sigaction action;
621#endif
622
623#ifdef HAVE_SIGSET
624 sigset (SIGTERM, SIG_IGN);
625#elif defined(HAVE_SIGACTION)
626 memset (&action, 0, sizeof (action));
627 sigemptyset (&action.sa_mask);
628 action.sa_handler = SIG_IGN;
629 sigaction (SIGTERM, &action, NULL);
630#else
631 signal (SIGTERM, SIG_IGN);
632#endif
633 /* Release line buffer memory */
634 free (buffer);
635 free (emit_line_buffer);
636}
637
638/**
639 * Cancel print job.
640 */
641void
642cancel_job (int signal) {
643 /* Emit page end & eject marker */
644 putchar (PTC_EJECT);
645 page_end ();
646 if (rle_buffer) free (rle_buffer);
647 exit (0);
648}
649
650/**
651 * Emit printer command codes at start of print job.
652 * This function does not emit P-touch page specific codes.
653 * @param job_options Job options
654 */
655void
656emit_job_cmds (job_options_t* job_options) {
657 /* Initialise printer */
658 putchar (ESC); putchar ('@');
659 /* Emit print density selection command if required */
660 int density = job_options->print_density;
661 switch (density) {
662 case 1: case 2: case 3: case 4: case 5:
663 putchar (ESC); putchar ('i'); putchar ('D'); putchar (density);
664 break;
665 default: break;
666 }
667 /* Emit transfer mode selection command if required */
668 int xfer_mode = job_options->xfer_mode;
669 if (xfer_mode >= 0 && xfer_mode < 0x100) {
670 putchar (ESC); putchar ('i'); putchar ('R'); putchar (xfer_mode);
671 }
672 /* Emit half cut selection command if required */
673 if (job_options->half_cut) {
674 putchar (ESC); putchar ('i'); putchar ('K'); putchar (0x04);
675 }
676}
677
678/**
679 * Emit feed, cut and mirror command codes.
680 * @param do_feed Emit codes to actually feed
681 * @param feed Feed size
682 * @param do_cut Emit codes to actually cut
683 * @param do_mirror Emit codes to mirror print
684 */
685inline void
686emit_feed_cut_mirror (bool do_feed, unsigned feed,
687 bool do_cut,
688 bool do_mirror) {
689 /* Determine feed nibble */
690 unsigned feed_nibble;
691 if (do_feed) {
692 feed_nibble = lrint (feed / 2.6 + 2.4); /* one suggested conversion */
693 if (feed_nibble > 31) feed_nibble = 31;
694 } else
695 feed_nibble = 0;
696 /* Determine auto cut bit - we only handle after each page */
697 unsigned char auto_cut_bit = do_cut ? 0x40 : 0x00;
698 /* Determine mirror print bit*/
699 unsigned char mirror_bit = do_mirror ? 0x80 : 0x00;
700 /* Combine & emit printer command code */
701 putchar (ESC); putchar ('i'); putchar ('M');
702 putchar ((char) (feed & 0x1f) | auto_cut_bit | mirror_bit);
703}
704
705/**
706 * Emit quality, roll fed media, and label size command codes.
707 * @param job_options Current job options
708 * @param page_options Current page options
709 * @param page_size_y Page size (height) in pt
710 * @param image_height_px Number of pixel lines in current page
711 */
712void
713emit_quality_rollfed_size (job_options_t* job_options,
714 page_options_t* page_options,
715 unsigned page_size_y,
716 unsigned image_height_px) {
717 bool roll_fed_media = page_options->roll_fed_media;
718 /* Determine print quality bit */
719 unsigned char print_quality_bit
720 = (job_options->print_quality_high == CUPS_TRUE) ? 0x40 : 0x00;
721 unsigned char roll_fed_media_bit = roll_fed_media ? 0x00 : 0x01;
722 /* Get tape width in mm */
723 int tape_width_mm = lrint (page_options->page_size [0] * MM_PER_PT);
724 if (tape_width_mm > 0xff) {
725 fprintf (stderr,
726 "ERROR: Page width (%umm) exceeds 255mm\n",
727 tape_width_mm);
728 tape_width_mm = 0xff;
729 }
730 /* Get tape height in mm */
731 unsigned tape_height_mm;
732 if (roll_fed_media)
733 tape_height_mm = 0;
734 else
735 tape_height_mm = lrint (page_size_y * MM_PER_PT);
736 if (tape_height_mm > 0xff) {
737 fprintf (stderr,
738 "ERROR: Page height (%umm) exceeds 255mm; use continuous tape (MediaType=roll)\n",
739 tape_height_mm);
740 tape_height_mm = 0xff;
741 }
742 /* Combine & emit printer command code */
743 putchar (ESC); putchar ('i'); putchar ('z');
744 putchar (print_quality_bit); putchar (roll_fed_media_bit);
745 putchar (tape_width_mm & 0xff); putchar (tape_height_mm & 0xff);
746 putchar (image_height_px & 0xff);
747 putchar ((image_height_px >> 8) & 0xff);
748 putchar (0x00); putchar (0x00); putchar (0x00); putchar (0x00);
749}
750/**
751 * Emit printer command codes at start of page for options that have
752 * changed.
753 * @param job_options Job options
754 * @param old_page_options Page options for preceding page
755 * @param new_page_options Page options for page to be printed
756 * @param force Ignore old_page_options and emit commands
757 * for selecting all options in new_page_options
758 */
759void
760emit_page_cmds (job_options_t* job_options,
761 page_options_t* old_page_options,
762 page_options_t* new_page_options,
763 bool force) {
764 int tape_width_mm = -1;
765
766 /* Set width and resolution */
767 unsigned hres = new_page_options->resolution [0];
768 unsigned vres = new_page_options->resolution [1];
769 unsigned old_page_size_x = old_page_options->page_size [0];
770 unsigned new_page_size_x = new_page_options->page_size [0];
771 if (force
772 || hres != old_page_options->resolution [0]
773 || vres != old_page_options->resolution [1]
774 || new_page_size_x != old_page_size_x)
775 /* We only know how to select 360x360DPI or 360x720DPI */
776 if (hres == 360 && (vres == 360 || vres == 720)) {
777 /* Get tape width in mm */
778 tape_width_mm = lrint (new_page_size_x * MM_PER_PT);
779 if (tape_width_mm > 0xff) {
780 fprintf (stderr,
781 "ERROR: Page width (%umm) exceeds 255mm\n",
782 tape_width_mm);
783 tape_width_mm = 0xff;
784 }
785 /* Emit printer commands */
786 putchar (ESC); putchar ('i'); putchar ('c');
787 if (vres == 360) {
788 putchar (0x84); putchar (0x00); putchar (tape_width_mm & 0xff);
789 putchar (0x00); putchar (0x00);
790 } else {
791 putchar (0x86); putchar (0x09); putchar (tape_width_mm & 0xff);
792 putchar (0x00); putchar (0x01);
793 }
794 }
795
796 /* Set feed, auto cut and mirror print */
797 unsigned feed = new_page_options->feed;
798 cups_adv_t perform_feed = new_page_options->perform_feed;
799 cups_cut_t cut_media = new_page_options->cut_media;
800 cups_bool_t mirror = new_page_options->mirror;
801 if (force
802 || feed != old_page_options->feed
803 || perform_feed != old_page_options->perform_feed
804 || cut_media != old_page_options->cut_media
805 || mirror != old_page_options->mirror)
806 /* We only know how to feed after each page */
807 emit_feed_cut_mirror (perform_feed == CUPS_ADVANCE_PAGE, feed,
808 cut_media == CUPS_CUT_PAGE,
809 mirror == CUPS_TRUE);
810 /* Set media and quality if label preamble is requested */
811 unsigned page_size_y = new_page_options->page_size [1];
812 unsigned image_height_px = lrint (page_size_y * vres / 72.0);
813 if (job_options->label_preamble && !job_options->concat_pages
814 && (force
815 || (new_page_options->roll_fed_media
816 != old_page_options->roll_fed_media)
817 || new_page_size_x != old_page_size_x
818 || page_size_y != old_page_options->page_size [1]))
819 emit_quality_rollfed_size (job_options, new_page_options,
820 page_size_y, image_height_px);
821
822 /* WHY DON'T WE SET MARGIN (ESC i d ...)? */
823
824 /* Set pixel data transfer compression */
825 if (force) {
826 if (job_options->pixel_xfer == RLE) {
827 putchar ('M'); putchar (0x02);
828 }
829 }
830 /* Emit number of raster lines to follow if using BIP */
831 if (job_options->pixel_xfer == BIP) {
832 unsigned image_height_px = lrint (page_size_y * vres / 72.0);
833 putchar (ESC); putchar (0x2a); putchar (0x27);
834 putchar (image_height_px & 0xff);
835 putchar ((image_height_px >> 8) & 0xff);
836 }
837}
838
839/** mirror [i] = bit mirror image of i.
840 * I.e., (mirror [i] >> j) & 1 == (i >> (7 - j)) & 1 for 0 <= j <= 7
841 */
842const unsigned char mirror [0x100] = {
843 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
844 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
845 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
846 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
847 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
848 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
849 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
850 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
851 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
852 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
853 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
854 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
855 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
856 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
857 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
858 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
859 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
860 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
861 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
862 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
863 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
864 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
865 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
866 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
867 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
868 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
869 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
870 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
871 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
872 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
873 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
874 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
875};
876
877/**
878 * Generate a buffer of pixel data ready to emit.
879 * Requirement: buflen + right_padding_bytes
880 * + (shift > 0 ? 1 : 0) <= bytes_per_line
881 * @param in_buffer Buffer containing raster data in
882 * left-to-right order
883 * @param out_buffer Buffer for returning generated line in
884 * right-to-left order; must be
885 * bytes_per_line long
886 * @param buflen in_buffer length
887 * @param bytes_per_line Number of pixel bytes to generate
888 * @param right_padding_bytes Number of zero bytes to pad
889 * with to the right of pixels
890 * @param shift Number of bits to shift left
891 * If do_mirror is false and shift < 0
892 * Then shift right -shift bits
893 * @param do_mirror Mirror in_buffer pixel data
894 * @param xormask The XOR mask for negative printing
895 * @return 0 if entire line is empty (zeros)
896 * nonzero if line contains nonzero pixels
897 */
898inline int
899generate_emit_line (unsigned char* in_buffer,
900 unsigned char* out_buffer,
901 int buflen,
902 unsigned char bytes_per_line,
903 int right_padding_bytes,
904 int shift,
905 int do_mirror,
906 unsigned char xormask) {
907#ifdef DEBUG
908 if (debug)
909 fprintf (stderr, "DEBUG: generate_emit_line "
910 "(in_buffer=%0x, out_buffer=%0x, "
911 "buflen=%d, bytes_per_line=%d, right_padding_bytes=%d, "
912 "shift=%d, do_mirror=%d, xormask=%0x)\n",
913 in_buffer, out_buffer, buflen, bytes_per_line,
914 right_padding_bytes, shift, do_mirror, xormask);
915#endif
916 /* Generate right padding zero bytes */
917 memset (out_buffer, xormask, right_padding_bytes);
918 unsigned int nonzero = 0;
919 int j = right_padding_bytes;
920 /* Copy pixel data from in_buffer to out_buffer, */
921 /* shifted and mirrored if required */
922 unsigned int box = 0; /* Box for shifting pixel data left */
923 int i;
924 if (do_mirror)
925 if (shift) {
926 for (i = 0; i < buflen; i++) {
927 unsigned int data = in_buffer [i]; nonzero |= data;
928 box |= data << shift;
929 out_buffer [j++] = (box & 0xff) ^ xormask;
930 box >>= 8;
931 }
932 out_buffer [j++] = box & 0xff;
933 } else
934 for (i = 0; i < buflen; i++) {
935 unsigned char data = in_buffer [i]; nonzero |= data;
936 out_buffer [j++] = data ^ xormask;
937 }
938 else
939 if (shift) {
940 if (buflen > 0) {
941 if (shift < 0) {
942 box = in_buffer [buflen - 1] >> -shift; nonzero |= box;
943 shift += 8;
944 } else {
945 box = in_buffer [buflen - 1] << shift; nonzero |= box;
946 out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
947 box >>= 8;
948 }
949 for (i = buflen - 2; i >= 0; i--) {
950 unsigned data = in_buffer [i]; nonzero |= data;
951 box |= data << shift;
952 out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
953 box >>= 8;
954 }
955 out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
956 }
957 } else
958 for (i = buflen - 1; i >= 0; i--) {
959 unsigned char data = in_buffer [i]; nonzero |= data;
960 out_buffer [j++] = (mirror [data]) ^ xormask;
961 }
962 /* Generate left padding bytes */
963 memset (out_buffer + j, xormask, bytes_per_line - j);
964 return nonzero != 0;
965}
966
967/**
968 * Emit lines waiting in RLE buffer.
969 * Resets global variable rle_buffer_next to rle_buffer,
970 * and lines_waiting to zero.
971 * @param job_options Job options
972 * @param page_options Page options
973 */
974inline void
975flush_rle_buffer (job_options_t* job_options,
976 page_options_t* page_options) {
977#ifdef DEBUG
978 if (debug)
979 fprintf (stderr, "DEBUG: flush_rle_buffer (): "
980 "lines_waiting = %d\n",
981 lines_waiting);
982#endif
983 if (lines_waiting > 0) {
984 if (job_options->label_preamble)
985 emit_quality_rollfed_size (job_options, page_options,
986 page_options->page_size [1],
987 lines_waiting);
988 xfer_t pixel_xfer = job_options->pixel_xfer;
989 int bytes_per_line = job_options->bytes_per_line;
990 switch (pixel_xfer) {
991 case RLE: {
992 size_t dummy
993 = fwrite (rle_buffer, sizeof (char), rle_buffer_next - rle_buffer, stdout);
994 break;
995 }
996 case ULP:
997 case BIP: {
998 unsigned char* p = rle_buffer;
999 unsigned emitted_lines = 0;
1000 while (rle_buffer_next - p > 0) {
1001 if (pixel_xfer == ULP) {
1002 putchar ('g'); putchar (0x00); putchar (bytes_per_line);
1003 }
1004 int emitted = 0;
1005 int linelen;
1006 switch (*p++) {
1007 case 'G':
1008 linelen = *p++;
1009 linelen += ((int)(*p++)) << 8;
1010 while (linelen > 0) {
1011 signed char l = *p++; linelen--;
1012 if (l < 0) { /* emit repeated data */
1013 char data = *p++; linelen--;
1014 emitted -= l; emitted++;
1015 for (; l <= 0; l++) putchar (data);
1016 } else { /* emit the l + 1 following bytes of data */
1017 size_t dummy = fwrite (p, sizeof (char), l + 1, stdout);
1018 p += l; p++;
1019 linelen -= l; linelen--;
1020 emitted += l; emitted++;
1021 }
1022 }
1023 if (emitted > bytes_per_line)
1024 fprintf (stderr,
1025 "ERROR: Emitted %d > %d bytes for one pixel line!\n",
1026 emitted, bytes_per_line);
1027 /* No break; fall through to next case: */
1028 case 'Z':
1029 for (; emitted < bytes_per_line; emitted++) putchar (0x00);
1030 break;
1031 default:
1032 fprintf (stderr, "ERROR: Unknown RLE flag at %p: '0x%02x'\n",
1033 p - 1, (int)*(p - 1));
1034 }
1035 emitted_lines++;
1036 }
1037#ifdef DEBUG
1038 if (debug)
1039 fprintf (stderr, "DEBUG: emitted %d lines\n", emitted_lines);
1040#endif
1041 break;
1042 }
1043 default:
1044 fprintf (stderr, "ERROR: Unknown pixel transfer mode: '%d'\n",
1045 pixel_xfer);
1046 }
1047 rle_buffer_next = rle_buffer;
1048 lines_waiting = 0;
1049 }
1050}
1051
1052/**
1053 * Ensure sufficient memory available in rle buffer.
1054 * If rle buffer needs to be extended, global variables rle_buffer and
1055 * rle_buffer_next might be altered.
1056 * @param job_options Job options
1057 * @param page_options Page options
1058 * @param bytes Number of bytes required.
1059 */
1060inline void
1061ensure_rle_buf_space (job_options_t* job_options,
1062 page_options_t* page_options,
1063 unsigned bytes) {
1064 unsigned long nextpos = rle_buffer_next - rle_buffer;
1065 if (nextpos + bytes > rle_alloced) {
1066 /* Exponential size increase avoids too frequent reallocation */
1067 unsigned long new_alloced = rle_alloced * 2 + 0x4000;
1068#ifdef DEBUG
1069 if (debug)
1070 fprintf (stderr, "DEBUG: ensure_rle_buf_space (bytes=%d): "
1071 "increasing rle_buffer from %d to %d\n",
1072 bytes,
1073 rle_alloced * sizeof (char),
1074 new_alloced * sizeof (char));
1075#endif
1076 void* p = NULL;
1077 if (new_alloced <= job_options->rle_alloc_max) {
1078 if (rle_buffer)
1079 p = (unsigned char*) realloc (rle_buffer, new_alloced * sizeof (char));
1080 else
1081 p = (unsigned char*) malloc (new_alloced * sizeof (char));
1082 }
1083 if (p) {
1084 rle_buffer = p;
1085 rle_buffer_next = rle_buffer + nextpos;
1086 rle_alloced = new_alloced;
1087 } else { /* Gain memory by flushing buffer to printer */
1088 flush_rle_buffer (job_options, page_options);
1089 if (rle_buffer_next - rle_buffer + bytes > rle_alloced) {
1090 fprintf (stderr,
1091 "ERROR: Out of memory when attempting to increase RLE "
1092 "buffer from %ld to %ld bytes\n",
1093 rle_alloced * sizeof (char),
1094 new_alloced * sizeof (char));
1095 exit (-1);
1096 }
1097 }
1098 }
1099}
1100
1101/** @def APPEND_MIXED_BYTES
1102 * Macro for appending mixed-bytes run to rle_buffer */
1103/** @def APPEND_REPEATED_BYTE
1104 * Macro for appending repeated-byte run to rle_buffer */
1105/**
1106 * Store buffer data in rle buffer using run-length encoding.
1107 * @param job_options Job options
1108 * @param page_options Page options
1109 * @param buf Buffer containing data to store
1110 * @param buf_len Length of buffer
1111 *
1112 * Global variable rle_buffer_next is a pointer into buffer for holding RLE data.
1113 * Must have room for at least 3 + buf_len + buf_len/128 + 1
1114 * bytes (ensured by reallocation).
1115 * On return, rle_buffer_next points to first unused buffer byte.
1116 *
1117 * This implementation enjoys the property that
1118 * the resulting RLE is at most buf_len + buf_len/128 + 1 bytes
1119 * long, because:
1120 * # a repeated-byte run has a repeat factor of at least 3
1121 * # two mixed-bytes runs never follow directly after each other,
1122 * unless the first one is 128 bytes long
1123 * The first property ensures that a repeated-run output sequence is
1124 * always at least 1 byte shorter than the input sequence it
1125 * represents. This combined with the second property means that only
1126 * - a terminating mixed-bytes run, and
1127 * - a mixed-bytes run of 128 bytes
1128 * can cause the RLE representation to be longer (by 1 byte) than the
1129 * corresponding input sequence in buf.
1130 */
1131inline void
1132RLE_store_line (job_options_t* job_options,
1133 page_options_t* page_options,
1134 const unsigned char* buf, unsigned buf_len) {
1135 ensure_rle_buf_space (job_options, page_options,
1136 4 + buf_len + buf_len / 128);
1137 unsigned char* rle_next = rle_buffer_next + 3;
1138 /* Make room for 3 initial meta data bytes, */
1139 /* written when actual length is known */
1140 const unsigned char* buf_end = buf + buf_len; /* Buffer end */
1141 const unsigned char* mix_start; /* Start of mixed bytes run */
1142
1143 const unsigned char* rep_start; /* End + 1 of mixed bytes run,
1144 and start of repeated byte run */
1145 const unsigned char* next; /* Next byte pointer,
1146 and end + 1 of repeated byte run */
1147 unsigned char next_val; /* Next byte value to consider */
1148 unsigned char rep_val; /* Repeated byte value */
1149 unsigned char nonzero = 0; /* OR of all buffer bytes */
1150
1151#define APPEND_MIXED_BYTES \
1152 if (mix_len > 128) mix_len = 128; \
1153 *rle_next++ = mix_len - 1; \
1154 memcpy (rle_next, mix_start, mix_len); \
1155 rle_next += mix_len;
1156#define APPEND_REPEATED_BYTE \
1157 unsigned rep_len = next - rep_start; \
1158 *rle_next++ = (signed char)(1 - rep_len); \
1159 *rle_next++ = rep_val;
1160
1161 for (mix_start = rep_start = next = buf, rep_val = next_val = *next;
1162 next != buf_end;
1163 next++, next_val = *next) {
1164 /* Loop invariants at this point:
1165 * 1) [mix_start..rep_start - 1] contains mixed bytes waiting
1166 * to be appended to rle_buffer,
1167 * 2) [rep_start..next - 1] contains repeats of rep_val
1168 * waiting to be appended to rle_buffer
1169 * 3) If next - rep_start > 2 then mix_start == rep_start
1170 * 4) next - rep_start <= 129
1171 * 5) rep_start - mix_start < 128
1172 * 6) [rle_buffer_next..rle_next - 1] = RLE ([buf..mix_start - 1])
1173 * 7) rep_val = *rep_start
1174 * 8) next_val = *next
1175 */
1176 nonzero |= next_val;
1177 if (next - rep_start >= 129) {
1178 /* RLE cannot represent repeated runs longer than 129 bytes */
1179 APPEND_REPEATED_BYTE;
1180 rep_start += rep_len;
1181 rep_val = *rep_start;
1182 mix_start = rep_start;
1183 }
1184 if (next_val == rep_val) { /* Run of repeated byte values */
1185 if (next - rep_start == 2) {
1186 unsigned mix_len = rep_start - mix_start;
1187 if (mix_len > 0) {
1188 APPEND_MIXED_BYTES;
1189 mix_start = rep_start;
1190 }
1191 }
1192 } else {
1193 if (next - rep_start > 2) { /* End of repeated run found */
1194 APPEND_REPEATED_BYTE;
1195 mix_start = next;
1196 }
1197 rep_start = next;
1198 rep_val = next_val;
1199 unsigned mix_len = rep_start - mix_start;
1200 if (mix_len >= 128) {
1201 /* RLE cannot represent mixed runs longer than 128 bytes */
1202 APPEND_MIXED_BYTES;
1203 mix_start += mix_len;
1204 }
1205 }
1206 }
1207 /* Handle final bytes */
1208 if (next - rep_start > 2) { /* Handle final repeated byte run */
1209 APPEND_REPEATED_BYTE;
1210 mix_start = next;
1211 }
1212 rep_start = next;
1213 unsigned mix_len = rep_start - mix_start;
1214 if (mix_len > 0) { /* Handle any remaining final mixed run */
1215 APPEND_MIXED_BYTES;
1216 mix_start += mix_len;
1217 }
1218 mix_len = rep_start - mix_start;
1219 if (mix_len > 0) { /* Case where final mixed run is 129 bytes */
1220 APPEND_MIXED_BYTES;
1221 }
1222 unsigned rle_len = rle_next - rle_buffer_next - 3;
1223 /* Store rle line meta data (length and (non)zero status) */
1224 if (nonzero) { /* Check for nonempty (no black pixels) line */
1225 rle_buffer_next [0] = 'G';
1226 rle_buffer_next [1] = rle_len & 0xff;
1227 rle_buffer_next [2] = (rle_len >> 8) & 0xff;
1228 rle_buffer_next = rle_next;
1229 } else {
1230 rle_buffer_next [0] = 'Z';
1231 rle_buffer_next++;
1232 }
1233 lines_waiting++;
1234 if (lines_waiting >= max_lines_waiting)
1235 flush_rle_buffer (job_options, page_options);
1236}
1237
1238/**
1239 * Store a number of empty lines in rle_buffer using RLE.
1240 * @param job_options Job options
1241 * @param page_options Page options
1242 * @param empty_lines Number of empty lines to store
1243 * @param xormask The XOR mask for negative printing
1244 */
1245inline void
1246RLE_store_empty_lines (job_options_t* job_options,
1247 page_options_t* page_options,
1248 int empty_lines,
1249 unsigned char xormask) {
1250 int bytes_per_line = job_options->bytes_per_line;
1251#ifdef DEBUG
1252 if (debug)
1253 fprintf (stderr, "DEBUG: RLE_store_empty_lines (empty_lines=%d, "
1254 "bytes_per_line=%d): lines_waiting = %d\n",
1255 empty_lines, bytes_per_line, lines_waiting);
1256#endif
1257 lines_waiting += empty_lines;
1258 if (xormask) {
1259 int blocks = (bytes_per_line + 127) / 128;
1260 ensure_rle_buf_space (job_options, page_options,
1261 empty_lines * blocks);
1262 for (; empty_lines--; ) {
1263 *(rle_buffer_next++) = 'G';
1264 *(rle_buffer_next++) = 0x02;
1265 *(rle_buffer_next++) = 0x00;
1266 int rep_len;
1267 for (; bytes_per_line > 0; bytes_per_line -= rep_len) {
1268 rep_len = bytes_per_line;
1269 if (rep_len > 128) rep_len = 128;
1270 *(rle_buffer_next++) = (signed char) (1 - rep_len);
1271 *(rle_buffer_next++) = xormask;
1272 }
1273 }
1274 } else {
1275 ensure_rle_buf_space (job_options, page_options, empty_lines);
1276 for (; empty_lines--; ) *(rle_buffer_next++) = 'Z';
1277 }
1278}
1279
1280/**
1281 * Emit raster lines for current page.
1282 * @param page Page number of page to be emitted
1283 * @param job_options Job options
1284 * @param page_options Page options
1285 * @param ras Raster data stream
1286 * @param header Current page header
1287 * @return 0 on success, nonzero otherwise
1288 */
1289int
1290emit_raster_lines (int page,
1291 job_options_t* job_options,
1292 page_options_t* page_options,
1293 cups_raster_t* ras,
1294 cups_page_header_t* header) {
1295 unsigned char xormask = (header->NegativePrint ? ~0 : 0);
1296 /* Determine whether we need to mirror the pixel data */
1297 int do_mirror = job_options->software_mirror && page_options->mirror;
1298
1299 unsigned cupsBytesPerLine = header->cupsBytesPerLine;
1300 unsigned cupsHeight = header->cupsHeight;
1301 unsigned cupsWidth = header->cupsWidth;
1302 int bytes_per_line = job_options->bytes_per_line;
1303 unsigned buflen = cupsBytesPerLine;
1304 /* Make sure buflen can be written as a byte */
1305 if (buflen > 0xff) buflen = 0xff;
1306 /* Truncate buflen if greater than bytes_per_line */
1307 if (buflen >= bytes_per_line) buflen = bytes_per_line;
1308 /* Calculate extra horizontal spacing pixels if the right side of */
1309 /* ImagingBoundingBox doesn't touch the PageSize box */
1310 double scale_pt2xpixels = header->HWResolution [0] / 72.0;
1311 unsigned right_spacing_px = 0;
1312 if (header->ImagingBoundingBox [2] != 0) {
1313 unsigned right_distance_pt
1314 = header->PageSize [0] - header->ImagingBoundingBox [2];
1315 if (right_distance_pt != 0)
1316 right_spacing_px = right_distance_pt * scale_pt2xpixels;
1317 }
1318 /* Calculate right_padding_bytes and shift */
1319 int right_padding_bits;
1320 if (job_options->align == CENTER) {
1321 unsigned left_spacing_px = 0;
1322 if (header->ImagingBoundingBox [0] != 0)
1323 left_spacing_px
1324 = header->ImagingBoundingBox [0] * scale_pt2xpixels;
1325 right_padding_bits
1326 = (bytes_per_line * 8
1327 - (left_spacing_px + cupsWidth + right_spacing_px)) / 2
1328 + right_spacing_px;
1329 if (right_padding_bits < 0) right_padding_bits = 0;
1330 } else
1331 right_padding_bits = right_spacing_px;
1332 int right_padding_bytes = right_padding_bits / 8;
1333 int shift = right_padding_bits % 8;
1334 /* If width is not an integral number of bytes, we must shift */
1335 /* right if we don't mirror, to ensure printing starts leftmost */
1336 if (!do_mirror) shift -= (8 - cupsWidth % 8) % 8;
1337 int shift_positive = (shift > 0 ? 1 : 0);
1338 /* We cannot allow buffer+padding to exceed device width */
1339 if (buflen + right_padding_bytes + shift_positive > bytes_per_line) {
1340#ifdef DEBUG
1341 if (debug) {
1342 fprintf (stderr, "DEBUG: Warning: buflen = %d, right_padding_bytes = %d, "
1343 "shift = %d, bytes_per_line = %d\n",
1344 buflen, right_padding_bytes, shift, bytes_per_line);
1345 }
1346#endif
1347 /* We cannot allow padding to exceed device width */
1348 if (right_padding_bytes + shift_positive > bytes_per_line)
1349 right_padding_bytes = bytes_per_line - shift_positive;
1350 /* Truncate buffer to fit device width */
1351 buflen = bytes_per_line - right_padding_bytes - shift_positive;
1352 }
1353 /* Percentage of page emitted */
1354 int completed = -1;
1355 /* Generate and store empty lines if the top of ImagingBoundingBox */
1356 /* doesn't touch the PageSize box */
1357 double scale_pt2ypixels = header->HWResolution [1] / 72.0;
1358 unsigned top_empty_lines = 0;
1359 unsigned page_size_y = header->PageSize [1];
1360 if (header->ImagingBoundingBox [3] != 0
1361 && (!job_options->concat_pages || page == 1)) {
1362 unsigned top_distance_pt
1363 = page_size_y - header->ImagingBoundingBox [3];
1364 if (top_distance_pt != 0) {
1365 top_empty_lines = lrint (top_distance_pt * scale_pt2ypixels);
1366 empty_lines += top_empty_lines;
1367 }
1368 }
1369 /* Generate and store actual page data */
1370 int y;
1371 for (y = 0; y < cupsHeight; y++) {
1372 /* Feedback to the user */
1373 if ((y & 0x1f) == 0) {
1374 int now_completed = 100 * y / cupsHeight;
1375 if (now_completed > completed) {
1376 completed = now_completed;
1377 fprintf (stderr,
1378 "INFO: Printing page %d, %d%% complete...\n",
1379 page, completed);
1380 fflush (stderr);
1381 }
1382 }
1383 /* Read one line of pixels */
1384 if (cupsRasterReadPixels (ras, buffer, cupsBytesPerLine) < 1)
1385 break; /* Escape if no pixels read */
1386 bool nonempty_line =
1387 generate_emit_line (buffer, emit_line_buffer, buflen, bytes_per_line,
1388 right_padding_bytes, shift, do_mirror, xormask);
1389 if (nonempty_line) {
1390 if (empty_lines) {
1391 RLE_store_empty_lines
1392 (job_options, page_options, empty_lines, xormask);
1393 empty_lines = 0;
1394 }
1395 RLE_store_line (job_options, page_options,
1396 emit_line_buffer, bytes_per_line);
1397 } else
1398 empty_lines++;
1399 }
1400
1401 unsigned image_height_px = lrint (page_size_y * scale_pt2ypixels);
1402 unsigned bot_empty_lines;
1403 if (image_height_px >= top_empty_lines + y)
1404 bot_empty_lines = image_height_px - top_empty_lines - y;
1405 else
1406 bot_empty_lines = 0;
1407 if (bot_empty_lines != 0 && !job_options->concat_pages)
1408 empty_lines += bot_empty_lines;
1409 fprintf (stderr,
1410 "INFO: Printing page %d, 100%% complete.\n",
1411 page);
1412 fflush (stderr);
1413 return 0;
1414}
1415/**
1416 * Process CUPS raster data from input file, emitting printer data on
1417 * stdout.
1418 * @param fd File descriptor for input file
1419 * @param job_options Pointer to print options
1420 * @return 0 on success, nonzero otherwise
1421 */
1422int
1423process_rasterdata (int fd, job_options_t* job_options) {
1424 int page = 1; /* Page number */
1425 cups_raster_t* ras; /* Raster stream for printing */
1426 cups_page_header_t header; /* Current page header */
1427 int first_page = true; /* Is this the first page? */
1428 int more_pages; /* Are there more pages left? */
1429 int bytes_per_line = job_options->bytes_per_line;
1430 page_options_t page_options [2] = {{
1431 CUT_MEDIA_DEFAULT,
1432 MIRROR_DEFAULT,
1433 ROLL_FED_MEDIA_DEFAULT,
1434 RESOLUTION_DEFAULT,
1435 PAGE_SIZE_DEFAULT,
1436 IMAGE_HEIGHT_DEFAULT,
1437 FEED_DEFAULT,
1438 PERFORM_FEED_DEFAULT,}
1439 }; /* Current & preceding page opts */
1440 page_options_t* new_page_options
1441 = page_options + 0; /* Options for current page */
1442 page_options_t* old_page_options
1443 = page_options + 1; /* Options for preceding page */
1444 page_options_t* tmp_page_options;/* Temp variable for swapping */
1445 ras = cupsRasterOpen (fd, CUPS_RASTER_READ);
1446 for (more_pages = cupsRasterReadHeader (ras, &header);
1447 more_pages;
1448 tmp_page_options = old_page_options,
1449 old_page_options = new_page_options,
1450 new_page_options = tmp_page_options,
1451 first_page = false) {
1452 update_page_options (&header, new_page_options);
1453#ifdef DEBUG
1454 if (debug) {
1455 fprintf (stderr, "DEBUG: pixel_xfer = %d\n", job_options->pixel_xfer);
1456 fprintf (stderr, "DEBUG: print_quality_high = %d\n", job_options->print_quality_high);
1457 fprintf (stderr, "DEBUG: half_cut = %d\n", job_options->half_cut);
1458 fprintf (stderr, "DEBUG: bytes_per_line = %d\n", job_options->bytes_per_line);
1459 fprintf (stderr, "DEBUG: align = %d\n", job_options->align);
1460 fprintf (stderr, "DEBUG: software_mirror = %d\n", job_options->software_mirror);
1461 fprintf (stderr, "DEBUG: label_preamble = %d\n", job_options->label_preamble);
1462 fprintf (stderr, "DEBUG: print_density = %d\n", job_options->print_density);
1463 fprintf (stderr, "DEBUG: xfer_mode = %d\n", job_options->xfer_mode);
1464 fprintf (stderr, "DEBUG: concat_pages = %d\n", job_options->concat_pages);
1465 fprintf (stderr, "DEBUG: cut_media = %d\n", new_page_options->cut_media);
1466 fprintf (stderr, "DEBUG: mirror = %d\n", new_page_options->mirror);
1467 fprintf (stderr, "DEBUG: roll_fed_media = %d\n", new_page_options->roll_fed_media);
1468 fprintf (stderr, "DEBUG: resolution = %d x %d\n", new_page_options->resolution [0], new_page_options->resolution [1]);
1469 fprintf (stderr, "DEBUG: page_size = %d x %d\n", new_page_options->page_size [0], new_page_options->page_size [1]);
1470 fprintf (stderr, "DEBUG: image_height = %d\n", new_page_options->image_height);
1471 fprintf (stderr, "DEBUG: feed = %d\n", new_page_options->feed);
1472 fprintf (stderr, "DEBUG: perform_feed = %d\n", new_page_options->perform_feed);
1473 fprintf (stderr, "DEBUG: header->ImagingBoundingBox = [%u, %u, %u, %u]\n",
1474 header.ImagingBoundingBox [0], header.ImagingBoundingBox [1],
1475 header.ImagingBoundingBox [2], header.ImagingBoundingBox [3]);
1476 fprintf (stderr, "DEBUG: header.Margins = [%u, %u]\n",
1477 header.Margins [0], header.Margins [1]);
1478 }
1479#endif
1480 page_prepare (header.cupsBytesPerLine, bytes_per_line);
1481 if (first_page) {
1482 emit_job_cmds (job_options);
1483 emit_page_cmds (job_options, old_page_options,
1484 new_page_options, first_page);
1485 }
1486 emit_raster_lines (page, job_options, new_page_options, ras, &header);
1487 unsigned char xormask = (header.NegativePrint ? ~0 : 0);
1488 /* Determine whether this is the last page (fetch next) */
1489 more_pages = cupsRasterReadHeader (ras, &header);
1490 /* Do feeding or ejecting at the end of each page. */
1491 cups_adv_t perform_feed = new_page_options->perform_feed;
1492 if (more_pages) {
1493 if (!job_options->concat_pages) {
1494 RLE_store_empty_lines
1495 (job_options, page_options, empty_lines, xormask);
1496 empty_lines = 0;
1497 flush_rle_buffer (job_options, page_options);
1498 if (perform_feed == CUPS_ADVANCE_PAGE)
1499 putchar (PTC_EJECT); /* Emit eject marker to force feed */
1500 else
1501 putchar (PTC_FORMFEED); /* Emit page end marker without feed */
1502 }
1503 } else {
1504 if (!job_options->concat_pages) {
1505 RLE_store_empty_lines
1506 (job_options, page_options, empty_lines, xormask);
1507 empty_lines = 0;
1508 flush_rle_buffer (job_options, page_options);
1509 putchar (PTC_FORMFEED);
1510 } else {
1511 double scale_pt2ypixels = header.HWResolution [1] / 72.0;
1512 unsigned bot_empty_lines
1513 = lrint (header.ImagingBoundingBox [1] * scale_pt2ypixels);
1514 empty_lines = bot_empty_lines;
1515 RLE_store_empty_lines
1516 (job_options, page_options, empty_lines, xormask);
1517 empty_lines = 0;
1518 flush_rle_buffer (job_options, page_options);
1519 }
1520
1521 /* If special feed or cut at job end, emit commands to that effect */
1522 cups_cut_t cut_media = new_page_options->cut_media;
1523 if (perform_feed == CUPS_ADVANCE_JOB || cut_media == CUPS_CUT_JOB) {
1524 emit_feed_cut_mirror
1525 (perform_feed == CUPS_ADVANCE_PAGE ||
1526 perform_feed == CUPS_ADVANCE_JOB,
1527 new_page_options->feed,
1528 cut_media == CUPS_CUT_PAGE || cut_media == CUPS_CUT_JOB,
1529 new_page_options->mirror == CUPS_TRUE);
1530 /* Emit eject marker */
1531 putchar (PTC_EJECT);
1532 }
1533 }
1534 page_end ();
1535 /* Emit page count according to CUPS requirements */
1536 fprintf (stderr, "PAGE: %d 1\n", page);
1537 page++;
1538 }
1539 return 0;
1540}
1541/**
1542 * Main entry function.
1543 * @param argc number of command line arguments plus one
1544 * @param argv command line arguments
1545 * @return 0 if success, nonzero otherwise
1546 */
1547int
1548main (int argc, const char* argv []) {
1549 error_occurred = 0;
1550#ifdef DEBUG
1551 int i;
1552 if (argc > 5)
1553 if (strcasestr (argv [5], "debug") == argv [5]
1554 || strcasestr (argv [5], " debug") != NULL)
1555 debug = true;
1556 struct tms time_start, time_end;
1557 if (debug) {
1558 fprintf (stderr, "DEBUG: args = ");
1559 for (i = 0; i < argc; i++) fprintf (stderr, "%d:'%s' ", i, argv [i]);
1560 fprintf (stderr, "\nDEBUG: environment =\n");
1561 char** envvarbind;
1562 for (envvarbind = environ; *envvarbind; envvarbind++)
1563 fprintf (stderr, "DEBUG: %s\n", *envvarbind);
1564 times (&time_start);
1565 }
1566#endif
1567
1568 job_options_t job_options = parse_options (argc, argv);
1569
1570 int fd = open_input_file (argc, argv);
1571
1572 int rv = process_rasterdata (fd, &job_options);
1573
1574#ifdef DEBUG
1575 if (debug) {
1576 times (&time_end);
1577 fprintf (stderr, "DEBUG: User time System time (usec)\n");
1578 fprintf (stderr, "DEBUG: %9.3g %9.3g\n",
1579 (time_end.tms_utime - time_start.tms_utime)
1580 * 1000000.0 / CLOCKS_PER_SEC,
1581 (time_end.tms_stime - time_start.tms_stime)
1582 * 1000000.0 / CLOCKS_PER_SEC);
1583 fprintf (stderr, "DEBUG: Emitted lines: %u\n", emitted_lines);
1584 }
1585#endif
1586
1587 if (fd != 0) close (fd);
1588
1589 if (error_occurred) return error_occurred; else return rv;
1590}
01591
=== removed directory '.pc/send-esc-i-A-for-QL-only.patch'
=== removed file '.pc/send-esc-i-A-for-QL-only.patch/rastertoptch.c'
--- .pc/send-esc-i-A-for-QL-only.patch/rastertoptch.c 2014-03-06 16:23:54 +0000
+++ .pc/send-esc-i-A-for-QL-only.patch/rastertoptch.c 1970-01-01 00:00:00 +0000
@@ -1,1590 +0,0 @@
1/* rastertoptch is a filter to convert CUPS raster data into a Brother
2 * P-touch label printer command byte stream.
3 *
4 * Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
5 *
6 * This file is part of ptouch-driver
7 *
8 * ptouch-driver is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * ptouch-driver is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with ptouch-driver; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 *
23 * Please note: This software is not in any way related to Brother
24 * Industries, Ltd., except that it is intended for use with their
25 * products. Any comments to this software should NOT be directed to
26 * Brother Industries, Ltd.
27 */
28
29/** @file
30 * This filter processes CUPS raster data, converting it into a byte
31 * stream on stdout suitable for sending directly to a label printer
32 * of the Brother P-touch family.
33 *
34 * @version 1.2
35 * @author Arne John Glenstrup <panic@itu.dk>
36 * @date 2006
37
38 * <h2>Invocation</h2>
39 * The filter is invoked thus:
40 *
41 * rastertoptch job user title copies options [filename]
42 *
43 * @param printer The name of the printer queue (ignored)
44 * @param job The numeric job ID (ignored)
45 * @param user The string from the originating-user-name (ignored)
46 * @param title The string from the job-name attribute (ignored)
47 * @param copies The number of copies to be printed (ignored)
48 * @param options String representations of the job template
49 * parameters, separated by spaces. Boolean attributes
50 * are provided as "name" for true values and "noname"
51 * for false values. All other attributes are provided
52 * as "name=value" for single-valued attributes and
53 * "name=value1,value2,...,valueN" for set attributes
54 * @param filename The request file (if omitted, read from stdin)
55 *
56 * Available options (default values in [brackets]):
57 *
58 * @param PixelXfer=ULP|RLE|BIP Use uncompressed line printing (ULP),
59 * run-length encoding (RLE) or bit
60 * image printing (BIP) when emitting
61 * pixel data [ULP]
62 * @param PrintQuality=High|Fast Use high quality or fast printing [High]
63 * @param HalfCut Perform half-cut (crack & peel) when
64 * cutting [noHalfCut]
65 * @param BytesPerLine=N Emit N bytes per line [90]
66 * @param Align=Right|Center Pixel data alignment on tape [Right]
67 * @param PrintDensity=1|...|5 Print density level: 1=light, 5=dark
68 * @param ConcatPages Output all pages in one page [noConcatPages]
69 * @param RLEMemMax Maximum memory used for RLE buffer [1000000]
70 * @param SoftwareMirror Make the filter mirror pixel data
71 * if MirrorPrint is requested [noSoftwareMirror]
72 * @param LabelPreamble Emit preamble containing print quality,
73 * roll/label type, tape width, label height,
74 * and pixel lines [noLabelPreamble]
75 * @param Debug Emit diagnostic output to stderr [noDebug]
76 * (only if compiled with DEBUG set)
77 *
78 * Information about media type, resolution, mirror print, negative
79 * print, cut media, advance distance (feed) is extracted from the
80 * CUPS raster page headers given in the input stream. The MediaType
81 * page header field can be either "roll" or "labels" for continuous
82 * tape or pre-cut labels, respectively.
83 *
84 * LabelPreamble should usually not be used for the PT series printers.
85 *
86 * <h2>Output</h2>
87 * Each invocation of this filter is one job, containing a number of
88 * pages, each page containing a number of lines, each line consisting
89 * of a number of pixel bytes.
90 *
91 * Output consists of job-related printer initialisation commands,
92 * followed by a number of pages, each page consisting of page-related
93 * commands, followed by raster line data. Each page is followed by a
94 * finish page or (after the final page) finish job command.
95 *
96 * The following printer command language, printer, and tape
97 * information has been deduced from many sources, but is not official
98 * Brother documentation and may thus contain errors. Please send any
99 * corrections based on actual experience with these printers to the
100 * maintainer.
101 *
102 * <h3>Job-related commands</h3>
103 * <table>
104 * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
105 * <tr><td>ESC @ (1b 40)</td>
106 <td>Initialise</td><td>Clear print buffer</td></tr>
107 * <tr><td>ESC i D # (1b 69 44 ##)
108 * <td>Set print density</td>
109 * <td>bit 0-3: 0=no change, 1-5=density level</td></tr>
110 * <tr><td>ESC i K # (1b 69 4b ##)
111 * <td>Set half cut</td>
112 * <td>bit 2: 0=full cut, 1=half cut</td></tr>
113 * <tr><td>ESC i R ## (1b 69 52 ##)</td>
114 * <td>Set transfer mode</td>
115 * <td>##: ?: 1=?</td></tr>
116 * <tr><td>M ## (4d ##)</td>
117 * <td>Set compression</td>
118 * <td>##: Compression type: 2=RLE</td></tr>
119 * </table>
120 *
121 * <h3>Page-related commands</h3>
122 * <table>
123 * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
124 * <tr><td>ESC i c #1 #2 #3 NUL #4 <br>(1b 63 #1 #2 #3 00 #4)
125 * <td>Set width & resolution</td>
126 * <td>360x360DPI: #1 #2 #4 = 0x84 0x00 0x00<br>
127 * 360x720DPI: #1 #2 #4 = 0x86 0x09 0x01<br>
128 * #3: Tape width in mm</td></tr>
129 * <tr><td>ESC i M # <br>(1b 69 4d ##)</td>
130 * <td>Set mode</td>
131 * <td>bit 0-4: Feed amount (default=large): 0-7=none, 8-11=small,
132 * 12-25=medium, 26-31=large<br>
133 * bit 6: Auto cut/cut mark (default=on): 0=off, 1=on<br>
134 * bit 7: Mirror print (default=off): 0=off, 1=on.
135 * (note that it seems that QL devices do not reverse the
136 * data stream themselves, but rely on the driver doing
137 * it!)</td></tr>
138 * <tr><td>ESC i z #1 #2 #3 #4 #5 #6 NUL NUL NUL NUL<br>
139 * (1b 69 7a #1 #2 #3 #4 #5 #6 00 00 00 00)</td>
140 * <td>Set media & quality</td>
141 * <td>#1, bit 6: Print quality: 0=fast, 1=high<br>
142 * #2, bit 0: Media type: 0=continuous roll,
143 * 1=pre-cut labels<br>
144 * #3: Tape width in mm<br>
145 * #4: Label height in mm (0 for continuous roll)<br>
146 * #5 #6: Page consists of N=#5+256*#6 pixel lines</td></tr>
147 * <tr><td>ESC i d #1 #2 <br>(1b 69 64 #1 #2)</td>
148 * <td>Set margin</td>
149 * <td>Set size of right(?) margin to N=#1+256*#2 pixels</td></tr>
150 * <tr><td>FF (0c)</td>
151 * <td>Form feed</td>
152 * <td>Print buffer data without ejecting.</td></tr>
153 * <tr><td>SUB (1a)</td>
154 * <td>Eject</td>
155 * <td>Print buffer data and ejects.</td></tr>
156 * </table>
157 *
158 * <h3>Line-related commands</h3>
159 * <table>
160 * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
161 * <tr><td>G #1 #2 ...data... <br>(47 #1 #2 ...data...)</td>
162 * <td>Send raster line</td>
163 * <td>data consists of
164 * N=#1+256*#2 bytes of RLE compressed raster data.
165 * </td></tr>
166 * <tr><td>Z (5a)</td>
167 * <td>Advance tape</td><td>Print 1 empty line</td></tr>
168 * <tr><td>g #1 #2 ...data... <br>(67 #1 #2 ...data...)</td>
169 * <td>Send raster line</td>
170 * <td>data consists of
171 * N=#2 bytes of uncompressed raster data.</td></tr>
172 * <tr><td>ESC * ' #1 #2 ...data... <br>(1b 2a 27 #1 #2 ...data...)</td>
173 * <td>Bit image printing (BIP)</td>
174 * <td>Print N=#1+256*#2 lines of 24 pixels; data consists of 3*N
175 * bytes</td></tr>
176 * </table>
177 *
178 * <h3>Compressed-data-related commands (RLE)</h3>
179 * <table>
180 * <tr><th>Byte sequence</th><th>Function</th><th>Description</th></tr>
181 * <tr><td>#1 ...data...</td>
182 * <td>#1 >= 0: Print uncompressed</td>
183 * <td>data consists of 1+#1 uncompressed bytes</td></tr>
184 * <tr><td>#1 #2</td>
185 * <td>#1 < 0: Print compressed</td>
186 * <td>#2 should be printed 1-#1 times</td></tr>
187 * </table>
188 * #1 is represented as a 2-complement signed integer.
189 *
190 * <h2>Printer model characteristics</h2>
191 * The following table lists for each model what kind of cutter it has
192 * (manual, auto, half cut), what kind of pixel data transfer mode it
193 * requires, its resolution, number of print head pixels, number of
194 * bytes of pixel data that must be transmitted per line (regardless
195 * of actual tape width!), and what kinds of tape it can take.
196 *
197 * For PC models, pixel data must be centered, so narrow tapes require
198 * padding raster data with zero bits on each side. For QL models,
199 * labels are left-aligned, so pixel data must be right aligned, so
200 * narrow tapes require padding raster data with zero bits at the end.
201 *
202 * For PC-PT, only the central 24 pixels (= 3,4mm!) can be used for
203 * pixel-based graphics. It might be possible to print several strips
204 * of 24 pixels side-by side by issuing CR and line-positioning
205 * commands. That is currently not supported, let alone attempted,
206 * with this driver.
207 *
208 * <table>
209 * <tr><th>Model <th>Cutter <th>Xfer<th>DPI<th>Pixels<th>Bytes<th>Tape
210 * <tr><td>QL-500 <td>manual <td>ULP<td>300<td>720<td>90<td>DK12-62mm
211 * <tr><td>QL-550 <td>auto <td>ULP<td>300<td>720<td>90<td>DK12-62mm
212 * <tr><td>QL-650TD <td>auto <td>ULP<td>300<td>720<td>90<td>DK12-62mm
213 * <tr><td>PT-PC <td>auto <td>BIP<td>180<td>128<td> 3<td>TZ6-24mm
214 * <tr><td>PT-18R <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-18mm
215 * <tr><td>PT-550A <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-36mm
216 * <tr><td>PT-1500PC<td>manual <td>RLE<td>180<td>112<td>14<td>TZ6-24mm
217 * <tr><td>PT-1950 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-18mm
218 * <tr><td>PT-1950VP<td>auto <td>RLE<td>180<td>112<td>14<td>TZ6-18mm
219 * <tr><td>PT-1960 <td>auto <td>RLE<td>180<td> 96<td>12<td>TZ6-18mm
220 * <tr><td>PT-2300 <td>auto <td>RLE<td>180<td>112<td>14<td>TZ6-18mm
221 * <tr><td>PT-2420PC<td>manual <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
222 * <tr><td>PT-2450DX<td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
223 * <tr><td>PT-2500PC<td>auto <td>RLE<td>180<td>128<td>16<td>TZ6-24mm
224 * <tr><td>PT-2600 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ,AV6-24mm
225 * <tr><td>PT-2610 <td>auto <td>RLE<td>180<td>128<td>16<td>TZ,AV6-24mm
226 * <tr><td>PT-3600 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ,AV6-36mm
227 * <tr><td>PT-9200DX<td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
228 * <tr><td>PT-9200PC<td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
229 * <tr><td>PT-9400 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ6-36mm
230 * <tr><td>PT-9500PC<td>auto/half<td>RLE<td>360<br>
231 360x720<td>384<td>48<td>TZ,AV6-36mm
232 * <tr><td>PT-9600 <td>auto/half<td>RLE<td>360<td>384<td>48<td>TZ,AV6-36mm
233 * </table>
234 *
235 * <h2>Tape characteristics</h2>
236 * <table>
237 * <tr><th>Tape width
238 * <th colspan=2>Print area <th>Margins</th><th>DPI</th></tr>
239 * <tr><td>62mm<td>61.0mm<td>720pixels</td><td>0.5mm</td><td>300</td></tr>
240 * <tr><td>36mm<td>27.1mm<td>384pixels</td><td>4.5mm</td><td>360</td></tr>
241 * <tr><td>24mm<td>18.0mm<td>128pixels</td><td>3mm</td><td>180</td></tr>
242 * <tr><td>18mm<td>12.0mm<td> 85pixels</td><td>3mm</td><td>180</td></tr>
243 * <tr><td>12mm<td> 8.0mm<td> 57pixels</td><td>2mm</td><td>180</td></tr>
244 * <tr><td> 9mm<td> 6.9mm<td> 49pixels</td><td>1mm</td><td>180</td></tr>
245 * <tr><td> 6mm<td> 3.9mm<td> 28pixels</td><td>1mm</td><td>180</td></tr>
246 * </table>
247 *
248 * <h2>Notes</h2>
249 * - Pixels bytes sent are printed from right to left, with bit 7
250 * rightmost!
251 * - Bit image printing (BIP) using "ESC * ' #1 #2 ...data..."
252 * probably only works for the PT-PC model.
253 * - QL Printer documentation might state that the print area is less
254 * than 61mm, which is probably to ensure that printed pixels stay
255 * within the tape even if it is not precisely positioned. The
256 * print head really IS 720 pixels.
257 */
258/** Default pixel transfer method */
259#define PIXEL_XFER_DEFAULT RLE
260/** Default print quality */
261#define PRINT_QUALITY_HIGH_DEFAULT true
262/** Default half cut mode */
263#define HALF_CUT_DEFAULT false
264/** Maximum number of bytes per line */
265#define BYTES_PER_LINE_MAX 255 /* cf. ULP_emit_line */
266/** Default number of bytes per line */
267#define BYTES_PER_LINE_DEFAULT 90
268/** Default pixel data alignment on narrow tapes */
269#define ALIGN_DEFAULT RIGHT
270/** Maximum print density value */
271#define PRINT_DENSITY_MAX 5
272/** Default print density value (1: light, ..., 5:dark, 0: no change) */
273#define PRINT_DENSITY_DEFAULT 0
274/** Transfer mode default ??? (-1 = don't set) */
275#define TRANSFER_MODE_DEFAULT -1
276/** Driver pixel data mirroring default */
277#define SOFTWARE_MIRROR_DEFAULT false
278/** Label preamble emitting default */
279#define LABEL_PREAMBLE_DEFAULT false
280/** Interlabel margin removal default */
281#define CONCAT_PAGES_DEFAULT false
282/** RLE buffer maximum memory usage */
283#define RLE_ALLOC_MAX_DEFAULT 1000000
284/** Mirror printing default */
285#define MIRROR_DEFAULT false
286/** Negative printing default */
287#define NEGATIVE_DEFAULT false
288/** Cut media mode default */
289#define CUT_MEDIA_DEFAULT CUPS_CUT_NONE
290/** Roll fed media default */
291#define ROLL_FED_MEDIA_DEFAULT true
292/** Device resolution default in DPI */
293#define RESOLUTION_DEFAULT { 300, 300 }
294/** Page size default in PostScript points */
295#define PAGE_SIZE_DEFAULT { 176, 142 } /* 62x50mm */
296/** Image size default in pixels */
297#define IMAGE_HEIGHT_DEFAULT 0
298/** Feed amount default */
299#define FEED_DEFAULT 0
300/** When to perform feed default */
301#define PERFORM_FEED_DEFAULT CUPS_ADVANCE_NONE
302
303#include <config.h>
304#include <stdio.h>
305#include <unistd.h>
306#include <limits.h>
307#include <stdlib.h>
308#include <string.h>
309#include <errno.h>
310#include <fcntl.h>
311#include <signal.h>
312#include <math.h>
313#include <cups/raster.h>
314#include <cups/cups.h>
315
316#if STDC_HEADERS
317# include <string.h>
318#else
319# if !HAVE_MEMCPY
320# define memcpy(d, s, n) bcopy ((s), (d), (n))
321# endif
322#endif
323#if HAVE_STDBOOL_H
324# include <stdbool.h>
325#else
326# if ! HAVE__BOOL
327# ifdef __cplusplus
328typedef bool _Bool;
329# else
330typedef unsigned char _Bool;
331# endif
332# endif
333# define bool _Bool
334# define false 0
335# define true 1
336# define __bool_true_false_are_defined 1
337#endif
338
339
340
341#ifdef DEBUG
342#include <sys/times.h>
343/** Debug flag */
344int debug = 0;
345/** Number of emitted lines */
346unsigned emitted_lines = 0;
347#endif
348
349/** Length of a PostScript point in mm */
350#define MM_PER_PT (25.4 / 72.0)
351/** Printer code: Eject */
352#define PTC_EJECT 0x1a
353/** Printer code: Form feed */
354#define PTC_FORMFEED 0x0c
355
356/** ASCII escape value */
357#define ESC 0x1b
358
359/**
360 * Pixel transfer mode type.
361 */
362typedef enum {
363 ULP, /**< Uncompressed line printing */
364 RLE, /**< Run-length encoding */
365 BIP, /**< Bit image printing */
366} xfer_t;
367
368/**
369 * Pixel data alignment type.
370 */
371typedef enum {RIGHT, CENTER} align_t;
372
373/** Flag signalling whether any errors were encountered. */
374int error_occurred;
375
376/** CUPS Raster line buffer. */
377unsigned char* buffer;
378/** Buffer holding line data to emit to the printer. */
379unsigned char* emit_line_buffer;
380/** Buffer holding RLE line data to emit to the printer. */
381unsigned char* rle_buffer = NULL;
382/** Pointer to first free pos in rle_buffer. */
383unsigned char* rle_buffer_next = NULL;
384/** Size of rle_buffer. */
385unsigned long rle_alloced = 0;
386/** Number of empty lines (input data only zeros) waiting to be stored */
387int empty_lines = 0;
388/** Number of pixel lines waiting to be emitted. */
389unsigned lines_waiting = 0;
390/** Threshold for flushing waiting lines to printer. */
391unsigned max_lines_waiting = INT_MAX;
392
393/** Macro for obtaining integer option values. */
394#define OBTAIN_INT_OPTION(name, var, min, max) \
395 cups_option \
396 = cupsGetOption (name, num_options, cups_options); \
397 if (cups_option) { \
398 errno = 0; \
399 char* rest; \
400 long int var = strtol (cups_option, &rest, 0); \
401 if (errno || *rest != '\0' || rest == cups_option \
402 || var < min || var > max) { \
403 fprintf (stderr, "ERROR: " name " '%s', " \
404 "must be an integer N, where %ld <= N <= %ld\n", \
405 cups_option, (long) min, (long) max); \
406 error_occurred = 1; \
407 } else \
408 options.var = var; \
409 }
410
411/** Macro for obtaining boolean option values. */
412#define OBTAIN_BOOL_OPTION(name, var) \
413 cups_option \
414 = cupsGetOption (name, num_options, cups_options); \
415 if (cups_option) options.var = true; \
416 cups_option \
417 = cupsGetOption ("no"name, num_options, cups_options); \
418 if (cups_option) options.var = false; \
419
420/**
421 * Struct type for holding all the job options.
422 */
423typedef struct {
424 xfer_t pixel_xfer; /**< pixel transfer mode */
425 cups_bool_t print_quality_high; /**< print quality is high */
426 bool half_cut; /**< half cut */
427 int bytes_per_line; /**< bytes per line (print head width) */
428 align_t align; /**< pixel data alignment */
429 int software_mirror; /**< mirror pixel data if mirror printing */
430 int print_density; /**< printing density (0=don't change) */
431 int xfer_mode; /**< transfer mode ??? */
432 int label_preamble; /**< emit ESC i z ... */
433 bool concat_pages; /**< remove interlabel margins */
434 unsigned long rle_alloc_max; /**< max bytes used for rle_buffer */
435} job_options_t;
436
437/**
438 * Struct type for holding current page options.
439 */
440typedef struct {
441 cups_cut_t cut_media; /**< cut media mode */
442 cups_bool_t mirror; /**< mirror printing */
443 bool roll_fed_media; /**< continuous (not labels) roll media */
444 unsigned resolution [2]; /**< horiz & vertical resolution in DPI */
445 unsigned page_size [2]; /**< width & height of page in points */
446 unsigned image_height; /**< height of page image in pixels */
447 unsigned feed; /**< feed size in points */
448 cups_adv_t perform_feed; /**< When to feed */
449} page_options_t;
450
451/**
452 * Parse options given in command line argument 5.
453 * @param argc number of command line arguments plus one
454 * @param argv command line arguments
455 * @return options, where each option set to its default value if
456 * not specified in argv [5]
457 */
458job_options_t
459parse_options (int argc, const char* argv []) {
460 job_options_t options = {
461 PIXEL_XFER_DEFAULT,
462 PRINT_QUALITY_HIGH_DEFAULT,
463 HALF_CUT_DEFAULT,
464 BYTES_PER_LINE_DEFAULT,
465 ALIGN_DEFAULT,
466 SOFTWARE_MIRROR_DEFAULT,
467 PRINT_DENSITY_DEFAULT,
468 TRANSFER_MODE_DEFAULT,
469 LABEL_PREAMBLE_DEFAULT,
470 CONCAT_PAGES_DEFAULT,
471 RLE_ALLOC_MAX_DEFAULT,
472 };
473 if (argc < 6) return options;
474 int num_options = 0;
475 cups_option_t* cups_options = NULL;
476 num_options
477 = cupsParseOptions (argv [5], num_options, &cups_options);
478 const char* cups_option
479 = cupsGetOption ("PixelXfer", num_options, cups_options);
480 if (cups_option) {
481 if (strcasecmp (cups_option, "ULP") == 0)
482 options.pixel_xfer = ULP;
483 else if (strcasecmp (cups_option, "RLE") == 0)
484 options.pixel_xfer = RLE;
485 else if (strcasecmp (cups_option, "BIP") == 0)
486 options.pixel_xfer = BIP;
487 else {
488 fprintf (stderr, "ERROR: Unknown PicelXfer '%s', "
489 "must be RLE, BIP or ULP\n", cups_option);
490 error_occurred = 1;
491 }
492 }
493 cups_option
494 = cupsGetOption ("PrintQuality", num_options, cups_options);
495 if (cups_option) {
496 if (strcasecmp (cups_option, "High") == 0)
497 options.print_quality_high = true;
498 else if (strcasecmp (cups_option, "Fast") == 0)
499 options.print_quality_high = false;
500 else {
501 fprintf (stderr, "ERROR: Unknown PrintQuality '%s', "
502 "must be High or Fast\n", cups_option);
503 error_occurred = 1;
504 }
505 }
506 OBTAIN_BOOL_OPTION ("HalfCut", half_cut);
507 OBTAIN_INT_OPTION ("BytesPerLine", bytes_per_line,
508 1, BYTES_PER_LINE_MAX);
509 cups_option
510 = cupsGetOption ("Align", num_options, cups_options);
511 if (cups_option) {
512 if (strcasecmp (cups_option, "Right") == 0)
513 options.align = RIGHT;
514 else if (strcasecmp (cups_option, "Center") == 0)
515 options.align = CENTER;
516 else {
517 fprintf (stderr, "ERROR: Unknown Align '%s', "
518 "must be Right or Center\n", cups_option);
519 error_occurred = 1;
520 }
521 }
522 OBTAIN_INT_OPTION ("PrintDensity", print_density,
523 0, PRINT_DENSITY_MAX);
524 OBTAIN_BOOL_OPTION ("ConcatPages", concat_pages);
525 OBTAIN_INT_OPTION ("RLEMemMax", rle_alloc_max, 0, LONG_MAX);
526 OBTAIN_INT_OPTION ("TransferMode", xfer_mode, 0, 255);
527 OBTAIN_BOOL_OPTION ("SoftwareMirror", software_mirror);
528 OBTAIN_BOOL_OPTION ("LabelPreamble", label_preamble);
529 /* Release memory allocated for CUPS options struct */
530 cupsFreeOptions (num_options, cups_options);
531 return options;
532}
533
534/**
535 * Determine input stream and open it. If there are 6 command line
536 * arguments, argv[6] is taken to be the input file name
537 * otherwise stdin is used. This funtion exits the program on error.
538 * @param argc number of command line arguments plus one
539 * @param argv command line arguments
540 * @return file descriptor for the opened input stream
541 */
542int
543open_input_file (int argc, const char* argv []) {
544 int fd;
545 if (argc == 7) {
546 if ((fd = open (argv[6], O_RDONLY)) < 0) {
547 perror ("ERROR: Unable to open raster file - ");
548 sleep (1);
549 exit (1);
550 }
551 } else
552 fd = 0;
553 return fd;
554}
555
556/**
557 * Update page_options with information found in header.
558 * @param header CUPS page header
559 * @param page_options page options to be updated
560 */
561void
562update_page_options (cups_page_header_t* header,
563 page_options_t* page_options) {
564 page_options->cut_media = header->CutMedia;
565 page_options->mirror = header->MirrorPrint;
566 const char* media_type = header->MediaType;
567 page_options->roll_fed_media /* Default is continuous roll */
568 = (strcasecmp ("Labels", media_type) != 0);
569 page_options->resolution [0] = header->HWResolution [0];
570 page_options->resolution [1] = header->HWResolution [1];
571 page_options->page_size [0] = header->PageSize [0];
572 page_options->page_size [1] = header->PageSize [1];
573 page_options->image_height = header->cupsHeight;
574 page_options->feed = header->AdvanceDistance;
575 page_options->perform_feed = header->AdvanceMedia;
576}
577
578void cancel_job (int signal);
579/**
580 * Prepare for a new page by setting up signalling infrastructure and
581 * memory allocation.
582 * @param cups_buffer_size Required size of CUPS raster line buffer
583 * @param device_buffer_size Required size of device pixel line buffer
584 */
585void
586page_prepare (unsigned cups_buffer_size, unsigned device_buffer_size) {
587 /* Set up signalling to handle print job cancelling */
588#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
589 struct sigaction action;
590#endif
591
592#ifdef HAVE_SIGSET
593 sigset (SIGTERM, cancel_job);
594#elif defined(HAVE_SIGACTION)
595 memset (&action, 0, sizeof (action));
596 sigemptyset (&action.sa_mask);
597 action.sa_handler = cancel_job;
598 sigaction (SIGTERM, &action, NULL);
599#else
600 signal (SIGTERM, cancel_job);
601#endif
602
603 /* Allocate line buffer */
604 buffer = malloc (cups_buffer_size);
605 emit_line_buffer = malloc (device_buffer_size);
606 if (!buffer || !emit_line_buffer) {
607 fprintf
608 (stderr,
609 "ERROR: Cannot allocate memory for raster line buffer\n");
610 exit (1);
611 }
612}
613
614/**
615 * Clean up signalling and memory after emitting a page
616*/
617void
618page_end () {
619#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
620 struct sigaction action;
621#endif
622
623#ifdef HAVE_SIGSET
624 sigset (SIGTERM, SIG_IGN);
625#elif defined(HAVE_SIGACTION)
626 memset (&action, 0, sizeof (action));
627 sigemptyset (&action.sa_mask);
628 action.sa_handler = SIG_IGN;
629 sigaction (SIGTERM, &action, NULL);
630#else
631 signal (SIGTERM, SIG_IGN);
632#endif
633 /* Release line buffer memory */
634 free (buffer);
635 free (emit_line_buffer);
636}
637
638/**
639 * Cancel print job.
640 */
641void
642cancel_job (int signal) {
643 /* Emit page end & eject marker */
644 putchar (PTC_EJECT);
645 page_end ();
646 if (rle_buffer) free (rle_buffer);
647 exit (0);
648}
649
650/**
651 * Emit printer command codes at start of print job.
652 * This function does not emit P-touch page specific codes.
653 * @param job_options Job options
654 */
655void
656emit_job_cmds (job_options_t* job_options) {
657 /* Initialise printer */
658 putchar (ESC); putchar ('@');
659 /* Emit print density selection command if required */
660 int density = job_options->print_density;
661 switch (density) {
662 case 1: case 2: case 3: case 4: case 5:
663 putchar (ESC); putchar ('i'); putchar ('D'); putchar (density);
664 break;
665 default: break;
666 }
667 /* Emit transfer mode selection command if required */
668 int xfer_mode = job_options->xfer_mode;
669 if (xfer_mode >= 0 && xfer_mode < 0x100) {
670 putchar (ESC); putchar ('i'); putchar ('R'); putchar (xfer_mode);
671 }
672 /* Emit half cut selection command if required */
673 if (job_options->half_cut) {
674 putchar (ESC); putchar ('i'); putchar ('K'); putchar (0x04);
675 }
676}
677
678/**
679 * Emit feed, cut and mirror command codes.
680 * @param do_feed Emit codes to actually feed
681 * @param feed Feed size
682 * @param do_cut Emit codes to actually cut
683 * @param do_mirror Emit codes to mirror print
684 */
685inline void
686emit_feed_cut_mirror (bool do_feed, unsigned feed,
687 bool do_cut,
688 bool do_mirror) {
689 /* Determine feed nibble */
690 unsigned feed_nibble;
691 if (do_feed) {
692 feed_nibble = lrint (feed / 2.6 + 2.4); /* one suggested conversion */
693 if (feed_nibble > 31) feed_nibble = 31;
694 } else
695 feed_nibble = 0;
696 /* Determine auto cut bit - we only handle after each page */
697 unsigned char auto_cut_bit = do_cut ? 0x40 : 0x00;
698 /* Determine mirror print bit*/
699 unsigned char mirror_bit = do_mirror ? 0x80 : 0x00;
700 /* Combine & emit printer command code */
701 putchar (ESC); putchar ('i'); putchar ('M');
702 putchar ((char) (feed & 0x1f) | auto_cut_bit | mirror_bit);
703}
704
705/**
706 * Emit quality, roll fed media, and label size command codes.
707 * @param job_options Current job options
708 * @param page_options Current page options
709 * @param page_size_y Page size (height) in pt
710 * @param image_height_px Number of pixel lines in current page
711 */
712void
713emit_quality_rollfed_size (job_options_t* job_options,
714 page_options_t* page_options,
715 unsigned page_size_y,
716 unsigned image_height_px) {
717 bool roll_fed_media = page_options->roll_fed_media;
718 /* Determine print quality bit */
719 unsigned char print_quality_bit
720 = (job_options->print_quality_high == CUPS_TRUE) ? 0x40 : 0x00;
721 unsigned char roll_fed_media_bit = roll_fed_media ? 0x00 : 0x01;
722 /* Get tape width in mm */
723 int tape_width_mm = lrint (page_options->page_size [0] * MM_PER_PT);
724 if (tape_width_mm > 0xff) {
725 fprintf (stderr,
726 "ERROR: Page width (%umm) exceeds 255mm\n",
727 tape_width_mm);
728 tape_width_mm = 0xff;
729 }
730 /* Get tape height in mm */
731 unsigned tape_height_mm;
732 if (roll_fed_media)
733 tape_height_mm = 0;
734 else
735 tape_height_mm = lrint (page_size_y * MM_PER_PT);
736 if (tape_height_mm > 0xff) {
737 fprintf (stderr,
738 "ERROR: Page height (%umm) exceeds 255mm; use continuous tape (MediaType=roll)\n",
739 tape_height_mm);
740 tape_height_mm = 0xff;
741 }
742 /* Combine & emit printer command code */
743 putchar (ESC); putchar ('i'); putchar ('z');
744 putchar (print_quality_bit); putchar (roll_fed_media_bit);
745 putchar (tape_width_mm & 0xff); putchar (tape_height_mm & 0xff);
746 putchar (image_height_px & 0xff);
747 putchar ((image_height_px >> 8) & 0xff);
748 putchar (0x00); putchar (0x00); putchar (0x00); putchar (0x00);
749}
750/**
751 * Emit printer command codes at start of page for options that have
752 * changed.
753 * @param job_options Job options
754 * @param old_page_options Page options for preceding page
755 * @param new_page_options Page options for page to be printed
756 * @param force Ignore old_page_options and emit commands
757 * for selecting all options in new_page_options
758 */
759void
760emit_page_cmds (job_options_t* job_options,
761 page_options_t* old_page_options,
762 page_options_t* new_page_options,
763 bool force) {
764 int tape_width_mm = -1;
765
766 /* Set width and resolution */
767 unsigned hres = new_page_options->resolution [0];
768 unsigned vres = new_page_options->resolution [1];
769 unsigned old_page_size_x = old_page_options->page_size [0];
770 unsigned new_page_size_x = new_page_options->page_size [0];
771 if (force
772 || hres != old_page_options->resolution [0]
773 || vres != old_page_options->resolution [1]
774 || new_page_size_x != old_page_size_x)
775 /* We only know how to select 360x360DPI or 360x720DPI */
776 if (hres == 360 && (vres == 360 || vres == 720)) {
777 /* Get tape width in mm */
778 tape_width_mm = lrint (new_page_size_x * MM_PER_PT);
779 if (tape_width_mm > 0xff) {
780 fprintf (stderr,
781 "ERROR: Page width (%umm) exceeds 255mm\n",
782 tape_width_mm);
783 tape_width_mm = 0xff;
784 }
785 /* Emit printer commands */
786 putchar (ESC); putchar ('i'); putchar ('c');
787 if (vres == 360) {
788 putchar (0x84); putchar (0x00); putchar (tape_width_mm & 0xff);
789 putchar (0x00); putchar (0x00);
790 } else {
791 putchar (0x86); putchar (0x09); putchar (tape_width_mm & 0xff);
792 putchar (0x00); putchar (0x01);
793 }
794 }
795
796 /* Set feed, auto cut and mirror print */
797 unsigned feed = new_page_options->feed;
798 cups_adv_t perform_feed = new_page_options->perform_feed;
799 cups_cut_t cut_media = new_page_options->cut_media;
800 cups_bool_t mirror = new_page_options->mirror;
801 if (force
802 || feed != old_page_options->feed
803 || perform_feed != old_page_options->perform_feed
804 || cut_media != old_page_options->cut_media
805 || mirror != old_page_options->mirror)
806 /* We only know how to feed after each page */
807 emit_feed_cut_mirror (perform_feed == CUPS_ADVANCE_PAGE, feed,
808 cut_media == CUPS_CUT_PAGE,
809 mirror == CUPS_TRUE);
810 /* Set media and quality if label preamble is requested */
811 unsigned page_size_y = new_page_options->page_size [1];
812 unsigned image_height_px = lrint (page_size_y * vres / 72.0);
813 if (job_options->label_preamble && !job_options->concat_pages
814 && (force
815 || (new_page_options->roll_fed_media
816 != old_page_options->roll_fed_media)
817 || new_page_size_x != old_page_size_x
818 || page_size_y != old_page_options->page_size [1]))
819 emit_quality_rollfed_size (job_options, new_page_options,
820 page_size_y, image_height_px);
821
822 /* WHY DON'T WE SET MARGIN (ESC i d ...)? */
823
824 /* Set pixel data transfer compression */
825 if (force) {
826 if (job_options->pixel_xfer == RLE) {
827 putchar ('M'); putchar (0x02);
828 }
829 }
830 /* Emit number of raster lines to follow if using BIP */
831 if (job_options->pixel_xfer == BIP) {
832 unsigned image_height_px = lrint (page_size_y * vres / 72.0);
833 putchar (ESC); putchar (0x2a); putchar (0x27);
834 putchar (image_height_px & 0xff);
835 putchar ((image_height_px >> 8) & 0xff);
836 }
837}
838
839/** mirror [i] = bit mirror image of i.
840 * I.e., (mirror [i] >> j) & 1 == (i >> (7 - j)) & 1 for 0 <= j <= 7
841 */
842const unsigned char mirror [0x100] = {
843 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
844 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
845 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
846 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
847 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
848 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
849 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
850 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
851 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
852 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
853 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
854 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
855 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
856 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
857 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
858 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
859 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
860 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
861 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
862 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
863 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
864 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
865 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
866 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
867 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
868 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
869 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
870 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
871 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
872 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
873 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
874 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
875};
876
877/**
878 * Generate a buffer of pixel data ready to emit.
879 * Requirement: buflen + right_padding_bytes
880 * + (shift > 0 ? 1 : 0) <= bytes_per_line
881 * @param in_buffer Buffer containing raster data in
882 * left-to-right order
883 * @param out_buffer Buffer for returning generated line in
884 * right-to-left order; must be
885 * bytes_per_line long
886 * @param buflen in_buffer length
887 * @param bytes_per_line Number of pixel bytes to generate
888 * @param right_padding_bytes Number of zero bytes to pad
889 * with to the right of pixels
890 * @param shift Number of bits to shift left
891 * If do_mirror is false and shift < 0
892 * Then shift right -shift bits
893 * @param do_mirror Mirror in_buffer pixel data
894 * @param xormask The XOR mask for negative printing
895 * @return 0 if entire line is empty (zeros)
896 * nonzero if line contains nonzero pixels
897 */
898inline int
899generate_emit_line (unsigned char* in_buffer,
900 unsigned char* out_buffer,
901 int buflen,
902 unsigned char bytes_per_line,
903 int right_padding_bytes,
904 int shift,
905 int do_mirror,
906 unsigned char xormask) {
907#ifdef DEBUG
908 if (debug)
909 fprintf (stderr, "DEBUG: generate_emit_line "
910 "(in_buffer=%0x, out_buffer=%0x, "
911 "buflen=%d, bytes_per_line=%d, right_padding_bytes=%d, "
912 "shift=%d, do_mirror=%d, xormask=%0x)\n",
913 in_buffer, out_buffer, buflen, bytes_per_line,
914 right_padding_bytes, shift, do_mirror, xormask);
915#endif
916 /* Generate right padding zero bytes */
917 memset (out_buffer, xormask, right_padding_bytes);
918 unsigned int nonzero = 0;
919 int j = right_padding_bytes;
920 /* Copy pixel data from in_buffer to out_buffer, */
921 /* shifted and mirrored if required */
922 unsigned int box = 0; /* Box for shifting pixel data left */
923 int i;
924 if (do_mirror)
925 if (shift) {
926 for (i = 0; i < buflen; i++) {
927 unsigned int data = in_buffer [i]; nonzero |= data;
928 box |= data << shift;
929 out_buffer [j++] = (box & 0xff) ^ xormask;
930 box >>= 8;
931 }
932 out_buffer [j++] = box & 0xff;
933 } else
934 for (i = 0; i < buflen; i++) {
935 unsigned char data = in_buffer [i]; nonzero |= data;
936 out_buffer [j++] = data ^ xormask;
937 }
938 else
939 if (shift) {
940 if (buflen > 0) {
941 if (shift < 0) {
942 box = in_buffer [buflen - 1] >> -shift; nonzero |= box;
943 shift += 8;
944 } else {
945 box = in_buffer [buflen - 1] << shift; nonzero |= box;
946 out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
947 box >>= 8;
948 }
949 for (i = buflen - 2; i >= 0; i--) {
950 unsigned data = in_buffer [i]; nonzero |= data;
951 box |= data << shift;
952 out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
953 box >>= 8;
954 }
955 out_buffer [j++] = (mirror [box & 0xff]) ^ xormask;
956 }
957 } else
958 for (i = buflen - 1; i >= 0; i--) {
959 unsigned char data = in_buffer [i]; nonzero |= data;
960 out_buffer [j++] = (mirror [data]) ^ xormask;
961 }
962 /* Generate left padding bytes */
963 memset (out_buffer + j, xormask, bytes_per_line - j);
964 return nonzero != 0;
965}
966
967/**
968 * Emit lines waiting in RLE buffer.
969 * Resets global variable rle_buffer_next to rle_buffer,
970 * and lines_waiting to zero.
971 * @param job_options Job options
972 * @param page_options Page options
973 */
974inline void
975flush_rle_buffer (job_options_t* job_options,
976 page_options_t* page_options) {
977#ifdef DEBUG
978 if (debug)
979 fprintf (stderr, "DEBUG: flush_rle_buffer (): "
980 "lines_waiting = %d\n",
981 lines_waiting);
982#endif
983 if (lines_waiting > 0) {
984 if (job_options->label_preamble)
985 emit_quality_rollfed_size (job_options, page_options,
986 page_options->page_size [1],
987 lines_waiting);
988 xfer_t pixel_xfer = job_options->pixel_xfer;
989 int bytes_per_line = job_options->bytes_per_line;
990 switch (pixel_xfer) {
991 case RLE: {
992 size_t dummy
993 = fwrite (rle_buffer, sizeof (char), rle_buffer_next - rle_buffer, stdout);
994 break;
995 }
996 case ULP:
997 case BIP: {
998 unsigned char* p = rle_buffer;
999 unsigned emitted_lines = 0;
1000 while (rle_buffer_next - p > 0) {
1001 if (pixel_xfer == ULP) {
1002 putchar ('g'); putchar (0x00); putchar (bytes_per_line);
1003 }
1004 int emitted = 0;
1005 int linelen;
1006 switch (*p++) {
1007 case 'G':
1008 linelen = *p++;
1009 linelen += ((int)(*p++)) << 8;
1010 while (linelen > 0) {
1011 signed char l = *p++; linelen--;
1012 if (l < 0) { /* emit repeated data */
1013 char data = *p++; linelen--;
1014 emitted -= l; emitted++;
1015 for (; l <= 0; l++) putchar (data);
1016 } else { /* emit the l + 1 following bytes of data */
1017 size_t dummy = fwrite (p, sizeof (char), l + 1, stdout);
1018 p += l; p++;
1019 linelen -= l; linelen--;
1020 emitted += l; emitted++;
1021 }
1022 }
1023 if (emitted > bytes_per_line)
1024 fprintf (stderr,
1025 "ERROR: Emitted %d > %d bytes for one pixel line!\n",
1026 emitted, bytes_per_line);
1027 /* No break; fall through to next case: */
1028 case 'Z':
1029 for (; emitted < bytes_per_line; emitted++) putchar (0x00);
1030 break;
1031 default:
1032 fprintf (stderr, "ERROR: Unknown RLE flag at %p: '0x%02x'\n",
1033 p - 1, (int)*(p - 1));
1034 }
1035 emitted_lines++;
1036 }
1037#ifdef DEBUG
1038 if (debug)
1039 fprintf (stderr, "DEBUG: emitted %d lines\n", emitted_lines);
1040#endif
1041 break;
1042 }
1043 default:
1044 fprintf (stderr, "ERROR: Unknown pixel transfer mode: '%d'\n",
1045 pixel_xfer);
1046 }
1047 rle_buffer_next = rle_buffer;
1048 lines_waiting = 0;
1049 }
1050}
1051
1052/**
1053 * Ensure sufficient memory available in rle buffer.
1054 * If rle buffer needs to be extended, global variables rle_buffer and
1055 * rle_buffer_next might be altered.
1056 * @param job_options Job options
1057 * @param page_options Page options
1058 * @param bytes Number of bytes required.
1059 */
1060inline void
1061ensure_rle_buf_space (job_options_t* job_options,
1062 page_options_t* page_options,
1063 unsigned bytes) {
1064 unsigned long nextpos = rle_buffer_next - rle_buffer;
1065 if (nextpos + bytes > rle_alloced) {
1066 /* Exponential size increase avoids too frequent reallocation */
1067 unsigned long new_alloced = rle_alloced * 2 + 0x4000;
1068#ifdef DEBUG
1069 if (debug)
1070 fprintf (stderr, "DEBUG: ensure_rle_buf_space (bytes=%d): "
1071 "increasing rle_buffer from %d to %d\n",
1072 bytes,
1073 rle_alloced * sizeof (char),
1074 new_alloced * sizeof (char));
1075#endif
1076 void* p = NULL;
1077 if (new_alloced <= job_options->rle_alloc_max) {
1078 if (rle_buffer)
1079 p = (unsigned char*) realloc (rle_buffer, new_alloced * sizeof (char));
1080 else
1081 p = (unsigned char*) malloc (new_alloced * sizeof (char));
1082 }
1083 if (p) {
1084 rle_buffer = p;
1085 rle_buffer_next = rle_buffer + nextpos;
1086 rle_alloced = new_alloced;
1087 } else { /* Gain memory by flushing buffer to printer */
1088 flush_rle_buffer (job_options, page_options);
1089 if (rle_buffer_next - rle_buffer + bytes > rle_alloced) {
1090 fprintf (stderr,
1091 "ERROR: Out of memory when attempting to increase RLE "
1092 "buffer from %ld to %ld bytes\n",
1093 rle_alloced * sizeof (char),
1094 new_alloced * sizeof (char));
1095 exit (-1);
1096 }
1097 }
1098 }
1099}
1100
1101/** @def APPEND_MIXED_BYTES
1102 * Macro for appending mixed-bytes run to rle_buffer */
1103/** @def APPEND_REPEATED_BYTE
1104 * Macro for appending repeated-byte run to rle_buffer */
1105/**
1106 * Store buffer data in rle buffer using run-length encoding.
1107 * @param job_options Job options
1108 * @param page_options Page options
1109 * @param buf Buffer containing data to store
1110 * @param buf_len Length of buffer
1111 *
1112 * Global variable rle_buffer_next is a pointer into buffer for holding RLE data.
1113 * Must have room for at least 3 + buf_len + buf_len/128 + 1
1114 * bytes (ensured by reallocation).
1115 * On return, rle_buffer_next points to first unused buffer byte.
1116 *
1117 * This implementation enjoys the property that
1118 * the resulting RLE is at most buf_len + buf_len/128 + 1 bytes
1119 * long, because:
1120 * # a repeated-byte run has a repeat factor of at least 3
1121 * # two mixed-bytes runs never follow directly after each other,
1122 * unless the first one is 128 bytes long
1123 * The first property ensures that a repeated-run output sequence is
1124 * always at least 1 byte shorter than the input sequence it
1125 * represents. This combined with the second property means that only
1126 * - a terminating mixed-bytes run, and
1127 * - a mixed-bytes run of 128 bytes
1128 * can cause the RLE representation to be longer (by 1 byte) than the
1129 * corresponding input sequence in buf.
1130 */
1131inline void
1132RLE_store_line (job_options_t* job_options,
1133 page_options_t* page_options,
1134 const unsigned char* buf, unsigned buf_len) {
1135 ensure_rle_buf_space (job_options, page_options,
1136 4 + buf_len + buf_len / 128);
1137 unsigned char* rle_next = rle_buffer_next + 3;
1138 /* Make room for 3 initial meta data bytes, */
1139 /* written when actual length is known */
1140 const unsigned char* buf_end = buf + buf_len; /* Buffer end */
1141 const unsigned char* mix_start; /* Start of mixed bytes run */
1142
1143 const unsigned char* rep_start; /* End + 1 of mixed bytes run,
1144 and start of repeated byte run */
1145 const unsigned char* next; /* Next byte pointer,
1146 and end + 1 of repeated byte run */
1147 unsigned char next_val; /* Next byte value to consider */
1148 unsigned char rep_val; /* Repeated byte value */
1149 unsigned char nonzero = 0; /* OR of all buffer bytes */
1150
1151#define APPEND_MIXED_BYTES \
1152 if (mix_len > 128) mix_len = 128; \
1153 *rle_next++ = mix_len - 1; \
1154 memcpy (rle_next, mix_start, mix_len); \
1155 rle_next += mix_len;
1156#define APPEND_REPEATED_BYTE \
1157 unsigned rep_len = next - rep_start; \
1158 *rle_next++ = (signed char)(1 - rep_len); \
1159 *rle_next++ = rep_val;
1160
1161 for (mix_start = rep_start = next = buf, rep_val = next_val = *next;
1162 next != buf_end;
1163 next++, next_val = *next) {
1164 /* Loop invariants at this point:
1165 * 1) [mix_start..rep_start - 1] contains mixed bytes waiting
1166 * to be appended to rle_buffer,
1167 * 2) [rep_start..next - 1] contains repeats of rep_val
1168 * waiting to be appended to rle_buffer
1169 * 3) If next - rep_start > 2 then mix_start == rep_start
1170 * 4) next - rep_start <= 129
1171 * 5) rep_start - mix_start < 128
1172 * 6) [rle_buffer_next..rle_next - 1] = RLE ([buf..mix_start - 1])
1173 * 7) rep_val = *rep_start
1174 * 8) next_val = *next
1175 */
1176 nonzero |= next_val;
1177 if (next - rep_start >= 129) {
1178 /* RLE cannot represent repeated runs longer than 129 bytes */
1179 APPEND_REPEATED_BYTE;
1180 rep_start += rep_len;
1181 rep_val = *rep_start;
1182 mix_start = rep_start;
1183 }
1184 if (next_val == rep_val) { /* Run of repeated byte values */
1185 if (next - rep_start == 2) {
1186 unsigned mix_len = rep_start - mix_start;
1187 if (mix_len > 0) {
1188 APPEND_MIXED_BYTES;
1189 mix_start = rep_start;
1190 }
1191 }
1192 } else {
1193 if (next - rep_start > 2) { /* End of repeated run found */
1194 APPEND_REPEATED_BYTE;
1195 mix_start = next;
1196 }
1197 rep_start = next;
1198 rep_val = next_val;
1199 unsigned mix_len = rep_start - mix_start;
1200 if (mix_len >= 128) {
1201 /* RLE cannot represent mixed runs longer than 128 bytes */
1202 APPEND_MIXED_BYTES;
1203 mix_start += mix_len;
1204 }
1205 }
1206 }
1207 /* Handle final bytes */
1208 if (next - rep_start > 2) { /* Handle final repeated byte run */
1209 APPEND_REPEATED_BYTE;
1210 mix_start = next;
1211 }
1212 rep_start = next;
1213 unsigned mix_len = rep_start - mix_start;
1214 if (mix_len > 0) { /* Handle any remaining final mixed run */
1215 APPEND_MIXED_BYTES;
1216 mix_start += mix_len;
1217 }
1218 mix_len = rep_start - mix_start;
1219 if (mix_len > 0) { /* Case where final mixed run is 129 bytes */
1220 APPEND_MIXED_BYTES;
1221 }
1222 unsigned rle_len = rle_next - rle_buffer_next - 3;
1223 /* Store rle line meta data (length and (non)zero status) */
1224 if (nonzero) { /* Check for nonempty (no black pixels) line */
1225 rle_buffer_next [0] = 'G';
1226 rle_buffer_next [1] = rle_len & 0xff;
1227 rle_buffer_next [2] = (rle_len >> 8) & 0xff;
1228 rle_buffer_next = rle_next;
1229 } else {
1230 rle_buffer_next [0] = 'Z';
1231 rle_buffer_next++;
1232 }
1233 lines_waiting++;
1234 if (lines_waiting >= max_lines_waiting)
1235 flush_rle_buffer (job_options, page_options);
1236}
1237
1238/**
1239 * Store a number of empty lines in rle_buffer using RLE.
1240 * @param job_options Job options
1241 * @param page_options Page options
1242 * @param empty_lines Number of empty lines to store
1243 * @param xormask The XOR mask for negative printing
1244 */
1245inline void
1246RLE_store_empty_lines (job_options_t* job_options,
1247 page_options_t* page_options,
1248 int empty_lines,
1249 unsigned char xormask) {
1250 int bytes_per_line = job_options->bytes_per_line;
1251#ifdef DEBUG
1252 if (debug)
1253 fprintf (stderr, "DEBUG: RLE_store_empty_lines (empty_lines=%d, "
1254 "bytes_per_line=%d): lines_waiting = %d\n",
1255 empty_lines, bytes_per_line, lines_waiting);
1256#endif
1257 lines_waiting += empty_lines;
1258 if (xormask) {
1259 int blocks = (bytes_per_line + 127) / 128;
1260 ensure_rle_buf_space (job_options, page_options,
1261 empty_lines * blocks);
1262 for (; empty_lines--; ) {
1263 *(rle_buffer_next++) = 'G';
1264 *(rle_buffer_next++) = 0x02;
1265 *(rle_buffer_next++) = 0x00;
1266 int rep_len;
1267 for (; bytes_per_line > 0; bytes_per_line -= rep_len) {
1268 rep_len = bytes_per_line;
1269 if (rep_len > 128) rep_len = 128;
1270 *(rle_buffer_next++) = (signed char) (1 - rep_len);
1271 *(rle_buffer_next++) = xormask;
1272 }
1273 }
1274 } else {
1275 ensure_rle_buf_space (job_options, page_options, empty_lines);
1276 for (; empty_lines--; ) *(rle_buffer_next++) = 'Z';
1277 }
1278}
1279
1280/**
1281 * Emit raster lines for current page.
1282 * @param page Page number of page to be emitted
1283 * @param job_options Job options
1284 * @param page_options Page options
1285 * @param ras Raster data stream
1286 * @param header Current page header
1287 * @return 0 on success, nonzero otherwise
1288 */
1289int
1290emit_raster_lines (int page,
1291 job_options_t* job_options,
1292 page_options_t* page_options,
1293 cups_raster_t* ras,
1294 cups_page_header_t* header) {
1295 unsigned char xormask = (header->NegativePrint ? ~0 : 0);
1296 /* Determine whether we need to mirror the pixel data */
1297 int do_mirror = job_options->software_mirror && page_options->mirror;
1298
1299 unsigned cupsBytesPerLine = header->cupsBytesPerLine;
1300 unsigned cupsHeight = header->cupsHeight;
1301 unsigned cupsWidth = header->cupsWidth;
1302 int bytes_per_line = job_options->bytes_per_line;
1303 unsigned buflen = cupsBytesPerLine;
1304 /* Make sure buflen can be written as a byte */
1305 if (buflen > 0xff) buflen = 0xff;
1306 /* Truncate buflen if greater than bytes_per_line */
1307 if (buflen >= bytes_per_line) buflen = bytes_per_line;
1308 /* Calculate extra horizontal spacing pixels if the right side of */
1309 /* ImagingBoundingBox doesn't touch the PageSize box */
1310 double scale_pt2xpixels = header->HWResolution [0] / 72.0;
1311 unsigned right_spacing_px = 0;
1312 if (header->ImagingBoundingBox [2] != 0) {
1313 unsigned right_distance_pt
1314 = header->PageSize [0] - header->ImagingBoundingBox [2];
1315 if (right_distance_pt != 0)
1316 right_spacing_px = right_distance_pt * scale_pt2xpixels;
1317 }
1318 /* Calculate right_padding_bytes and shift */
1319 int right_padding_bits;
1320 if (job_options->align == CENTER) {
1321 unsigned left_spacing_px = 0;
1322 if (header->ImagingBoundingBox [0] != 0)
1323 left_spacing_px
1324 = header->ImagingBoundingBox [0] * scale_pt2xpixels;
1325 right_padding_bits
1326 = (bytes_per_line * 8
1327 - (left_spacing_px + cupsWidth + right_spacing_px)) / 2
1328 + right_spacing_px;
1329 if (right_padding_bits < 0) right_padding_bits = 0;
1330 } else
1331 right_padding_bits = right_spacing_px;
1332 int right_padding_bytes = right_padding_bits / 8;
1333 int shift = right_padding_bits % 8;
1334 /* If width is not an integral number of bytes, we must shift */
1335 /* right if we don't mirror, to ensure printing starts leftmost */
1336 if (!do_mirror) shift -= (8 - cupsWidth % 8) % 8;
1337 int shift_positive = (shift > 0 ? 1 : 0);
1338 /* We cannot allow buffer+padding to exceed device width */
1339 if (buflen + right_padding_bytes + shift_positive > bytes_per_line) {
1340#ifdef DEBUG
1341 if (debug) {
1342 fprintf (stderr, "DEBUG: Warning: buflen = %d, right_padding_bytes = %d, "
1343 "shift = %d, bytes_per_line = %d\n",
1344 buflen, right_padding_bytes, shift, bytes_per_line);
1345 }
1346#endif
1347 /* We cannot allow padding to exceed device width */
1348 if (right_padding_bytes + shift_positive > bytes_per_line)
1349 right_padding_bytes = bytes_per_line - shift_positive;
1350 /* Truncate buffer to fit device width */
1351 buflen = bytes_per_line - right_padding_bytes - shift_positive;
1352 }
1353 /* Percentage of page emitted */
1354 int completed = -1;
1355 /* Generate and store empty lines if the top of ImagingBoundingBox */
1356 /* doesn't touch the PageSize box */
1357 double scale_pt2ypixels = header->HWResolution [1] / 72.0;
1358 unsigned top_empty_lines = 0;
1359 unsigned page_size_y = header->PageSize [1];
1360 if (header->ImagingBoundingBox [3] != 0
1361 && (!job_options->concat_pages || page == 1)) {
1362 unsigned top_distance_pt
1363 = page_size_y - header->ImagingBoundingBox [3];
1364 if (top_distance_pt != 0) {
1365 top_empty_lines = lrint (top_distance_pt * scale_pt2ypixels);
1366 empty_lines += top_empty_lines;
1367 }
1368 }
1369 /* Generate and store actual page data */
1370 int y;
1371 for (y = 0; y < cupsHeight; y++) {
1372 /* Feedback to the user */
1373 if ((y & 0x1f) == 0) {
1374 int now_completed = 100 * y / cupsHeight;
1375 if (now_completed > completed) {
1376 completed = now_completed;
1377 fprintf (stderr,
1378 "INFO: Printing page %d, %d%% complete...\n",
1379 page, completed);
1380 fflush (stderr);
1381 }
1382 }
1383 /* Read one line of pixels */
1384 if (cupsRasterReadPixels (ras, buffer, cupsBytesPerLine) < 1)
1385 break; /* Escape if no pixels read */
1386 bool nonempty_line =
1387 generate_emit_line (buffer, emit_line_buffer, buflen, bytes_per_line,
1388 right_padding_bytes, shift, do_mirror, xormask);
1389 if (nonempty_line) {
1390 if (empty_lines) {
1391 RLE_store_empty_lines
1392 (job_options, page_options, empty_lines, xormask);
1393 empty_lines = 0;
1394 }
1395 RLE_store_line (job_options, page_options,
1396 emit_line_buffer, bytes_per_line);
1397 } else
1398 empty_lines++;
1399 }
1400
1401 unsigned image_height_px = lrint (page_size_y * scale_pt2ypixels);
1402 unsigned bot_empty_lines;
1403 if (image_height_px >= top_empty_lines + y)
1404 bot_empty_lines = image_height_px - top_empty_lines - y;
1405 else
1406 bot_empty_lines = 0;
1407 if (bot_empty_lines != 0 && !job_options->concat_pages)
1408 empty_lines += bot_empty_lines;
1409 fprintf (stderr,
1410 "INFO: Printing page %d, 100%% complete.\n",
1411 page);
1412 fflush (stderr);
1413 return 0;
1414}
1415/**
1416 * Process CUPS raster data from input file, emitting printer data on
1417 * stdout.
1418 * @param fd File descriptor for input file
1419 * @param job_options Pointer to print options
1420 * @return 0 on success, nonzero otherwise
1421 */
1422int
1423process_rasterdata (int fd, job_options_t* job_options) {
1424 int page = 1; /* Page number */
1425 cups_raster_t* ras; /* Raster stream for printing */
1426 cups_page_header_t header; /* Current page header */
1427 int first_page = true; /* Is this the first page? */
1428 int more_pages; /* Are there more pages left? */
1429 int bytes_per_line = job_options->bytes_per_line;
1430 page_options_t page_options [2] = {{
1431 CUT_MEDIA_DEFAULT,
1432 MIRROR_DEFAULT,
1433 ROLL_FED_MEDIA_DEFAULT,
1434 RESOLUTION_DEFAULT,
1435 PAGE_SIZE_DEFAULT,
1436 IMAGE_HEIGHT_DEFAULT,
1437 FEED_DEFAULT,
1438 PERFORM_FEED_DEFAULT,}
1439 }; /* Current & preceding page opts */
1440 page_options_t* new_page_options
1441 = page_options + 0; /* Options for current page */
1442 page_options_t* old_page_options
1443 = page_options + 1; /* Options for preceding page */
1444 page_options_t* tmp_page_options;/* Temp variable for swapping */
1445 ras = cupsRasterOpen (fd, CUPS_RASTER_READ);
1446 for (more_pages = cupsRasterReadHeader (ras, &header);
1447 more_pages;
1448 tmp_page_options = old_page_options,
1449 old_page_options = new_page_options,
1450 new_page_options = tmp_page_options,
1451 first_page = false) {
1452 update_page_options (&header, new_page_options);
1453#ifdef DEBUG
1454 if (debug) {
1455 fprintf (stderr, "DEBUG: pixel_xfer = %d\n", job_options->pixel_xfer);
1456 fprintf (stderr, "DEBUG: print_quality_high = %d\n", job_options->print_quality_high);
1457 fprintf (stderr, "DEBUG: half_cut = %d\n", job_options->half_cut);
1458 fprintf (stderr, "DEBUG: bytes_per_line = %d\n", job_options->bytes_per_line);
1459 fprintf (stderr, "DEBUG: align = %d\n", job_options->align);
1460 fprintf (stderr, "DEBUG: software_mirror = %d\n", job_options->software_mirror);
1461 fprintf (stderr, "DEBUG: label_preamble = %d\n", job_options->label_preamble);
1462 fprintf (stderr, "DEBUG: print_density = %d\n", job_options->print_density);
1463 fprintf (stderr, "DEBUG: xfer_mode = %d\n", job_options->xfer_mode);
1464 fprintf (stderr, "DEBUG: concat_pages = %d\n", job_options->concat_pages);
1465 fprintf (stderr, "DEBUG: cut_media = %d\n", new_page_options->cut_media);
1466 fprintf (stderr, "DEBUG: mirror = %d\n", new_page_options->mirror);
1467 fprintf (stderr, "DEBUG: roll_fed_media = %d\n", new_page_options->roll_fed_media);
1468 fprintf (stderr, "DEBUG: resolution = %d x %d\n", new_page_options->resolution [0], new_page_options->resolution [1]);
1469 fprintf (stderr, "DEBUG: page_size = %d x %d\n", new_page_options->page_size [0], new_page_options->page_size [1]);
1470 fprintf (stderr, "DEBUG: image_height = %d\n", new_page_options->image_height);
1471 fprintf (stderr, "DEBUG: feed = %d\n", new_page_options->feed);
1472 fprintf (stderr, "DEBUG: perform_feed = %d\n", new_page_options->perform_feed);
1473 fprintf (stderr, "DEBUG: header->ImagingBoundingBox = [%u, %u, %u, %u]\n",
1474 header.ImagingBoundingBox [0], header.ImagingBoundingBox [1],
1475 header.ImagingBoundingBox [2], header.ImagingBoundingBox [3]);
1476 fprintf (stderr, "DEBUG: header.Margins = [%u, %u]\n",
1477 header.Margins [0], header.Margins [1]);
1478 }
1479#endif
1480 page_prepare (header.cupsBytesPerLine, bytes_per_line);
1481 if (first_page) {
1482 emit_job_cmds (job_options);
1483 emit_page_cmds (job_options, old_page_options,
1484 new_page_options, first_page);
1485 }
1486 emit_raster_lines (page, job_options, new_page_options, ras, &header);
1487 unsigned char xormask = (header.NegativePrint ? ~0 : 0);
1488 /* Determine whether this is the last page (fetch next) */
1489 more_pages = cupsRasterReadHeader (ras, &header);
1490 /* Do feeding or ejecting at the end of each page. */
1491 cups_adv_t perform_feed = new_page_options->perform_feed;
1492 if (more_pages) {
1493 if (!job_options->concat_pages) {
1494 RLE_store_empty_lines
1495 (job_options, page_options, empty_lines, xormask);
1496 empty_lines = 0;
1497 flush_rle_buffer (job_options, page_options);
1498 if (perform_feed == CUPS_ADVANCE_PAGE)
1499 putchar (PTC_EJECT); /* Emit eject marker to force feed */
1500 else
1501 putchar (PTC_FORMFEED); /* Emit page end marker without feed */
1502 }
1503 } else {
1504 if (!job_options->concat_pages) {
1505 RLE_store_empty_lines
1506 (job_options, page_options, empty_lines, xormask);
1507 empty_lines = 0;
1508 flush_rle_buffer (job_options, page_options);
1509 putchar (PTC_FORMFEED);
1510 } else {
1511 double scale_pt2ypixels = header.HWResolution [1] / 72.0;
1512 unsigned bot_empty_lines
1513 = lrint (header.ImagingBoundingBox [1] * scale_pt2ypixels);
1514 empty_lines = bot_empty_lines;
1515 RLE_store_empty_lines
1516 (job_options, page_options, empty_lines, xormask);
1517 empty_lines = 0;
1518 flush_rle_buffer (job_options, page_options);
1519 }
1520
1521 /* If special feed or cut at job end, emit commands to that effect */
1522 cups_cut_t cut_media = new_page_options->cut_media;
1523 if (perform_feed == CUPS_ADVANCE_JOB || cut_media == CUPS_CUT_JOB) {
1524 emit_feed_cut_mirror
1525 (perform_feed == CUPS_ADVANCE_PAGE ||
1526 perform_feed == CUPS_ADVANCE_JOB,
1527 new_page_options->feed,
1528 cut_media == CUPS_CUT_PAGE || cut_media == CUPS_CUT_JOB,
1529 new_page_options->mirror == CUPS_TRUE);
1530 /* Emit eject marker */
1531 putchar (PTC_EJECT);
1532 }
1533 }
1534 page_end ();
1535 /* Emit page count according to CUPS requirements */
1536 fprintf (stderr, "PAGE: %d 1\n", page);
1537 page++;
1538 }
1539 return 0;
1540}
1541/**
1542 * Main entry function.
1543 * @param argc number of command line arguments plus one
1544 * @param argv command line arguments
1545 * @return 0 if success, nonzero otherwise
1546 */
1547int
1548main (int argc, const char* argv []) {
1549 error_occurred = 0;
1550#ifdef DEBUG
1551 int i;
1552 if (argc > 5)
1553 if (strcasestr (argv [5], "debug") == argv [5]
1554 || strcasestr (argv [5], " debug") != NULL)
1555 debug = true;
1556 struct tms time_start, time_end;
1557 if (debug) {
1558 fprintf (stderr, "DEBUG: args = ");
1559 for (i = 0; i < argc; i++) fprintf (stderr, "%d:'%s' ", i, argv [i]);
1560 fprintf (stderr, "\nDEBUG: environment =\n");
1561 char** envvarbind;
1562 for (envvarbind = environ; *envvarbind; envvarbind++)
1563 fprintf (stderr, "DEBUG: %s\n", *envvarbind);
1564 times (&time_start);
1565 }
1566#endif
1567
1568 job_options_t job_options = parse_options (argc, argv);
1569
1570 int fd = open_input_file (argc, argv);
1571
1572 int rv = process_rasterdata (fd, &job_options);
1573
1574#ifdef DEBUG
1575 if (debug) {
1576 times (&time_end);
1577 fprintf (stderr, "DEBUG: User time System time (usec)\n");
1578 fprintf (stderr, "DEBUG: %9.3g %9.3g\n",
1579 (time_end.tms_utime - time_start.tms_utime)
1580 * 1000000.0 / CLOCKS_PER_SEC,
1581 (time_end.tms_stime - time_start.tms_stime)
1582 * 1000000.0 / CLOCKS_PER_SEC);
1583 fprintf (stderr, "DEBUG: Emitted lines: %u\n", emitted_lines);
1584 }
1585#endif
1586
1587 if (fd != 0) close (fd);
1588
1589 if (error_occurred) return error_occurred; else return rv;
1590}
15910
=== modified file 'Makefile.am'
--- Makefile.am 2009-11-11 17:14:44 +0000
+++ Makefile.am 2015-04-10 21:18:54 +0000
@@ -47,7 +47,6 @@
47 printer/Brother-PT-9500PC.xml \47 printer/Brother-PT-9500PC.xml \
48 printer/Brother-PT-9600.xml \48 printer/Brother-PT-9600.xml \
49 opt/Brother-Ptouch-AdvanceDistance.xml \49 opt/Brother-Ptouch-AdvanceDistance.xml \
50 opt/Brother-Ptouch-AdvanceMedia.xml \
51 opt/Brother-Ptouch-Align.xml \50 opt/Brother-Ptouch-Align.xml \
52 opt/Brother-Ptouch-BytesPerLine.xml \51 opt/Brother-Ptouch-BytesPerLine.xml \
53 opt/Brother-Ptouch-ConcatPages.xml \52 opt/Brother-Ptouch-ConcatPages.xml \
5453
=== modified file 'debian/changelog'
--- debian/changelog 2014-03-06 16:23:54 +0000
+++ debian/changelog 2015-04-10 21:18:54 +0000
@@ -1,3 +1,10 @@
1ptouch-driver (1.3-8ubuntu1) unstable; urgency=medium
2
3 * Fix the "ESC i A" (enable cutter) command patch to correctly send only on
4 printers which support it. (LP: #1342979)
5
6 -- Philip Pemberton <philpem@philpem.me.uk> Fri, 03 Apr 2015 09:49:33 +0100
7
1ptouch-driver (1.3-8) unstable; urgency=medium8ptouch-driver (1.3-8) unstable; urgency=medium
29
3 [ Philip Pemberton ]10 [ Philip Pemberton ]
411
=== modified file 'debian/patches/foomatic-data-fixes.patch'
--- debian/patches/foomatic-data-fixes.patch 2011-08-29 12:27:35 +0000
+++ debian/patches/foomatic-data-fixes.patch 2015-04-10 21:18:54 +0000
@@ -22,14 +22,3 @@
22 </execution>22 </execution>
23 <comments>23 <comments>
24 <en>24 <en>
25--- a/printer/Brother-QL-550.xml
26+++ b/printer/Brother-QL-550.xml
27@@ -28,7 +28,7 @@
28 <resolution>
29 <dpi>
30 <x>300</x>
31- <y>300</y>
32+ <y>275</y>
33 </dpi>
34 </resolution>
35 <consumables>
3625
=== added file 'debian/patches/philpem-ptouch-fixes'
--- debian/patches/philpem-ptouch-fixes 1970-01-01 00:00:00 +0000
+++ debian/patches/philpem-ptouch-fixes 2015-04-10 21:18:54 +0000
@@ -0,0 +1,622 @@
1This patch fixes a number of issues with the ptouch-driver printer driver:
2
3 * Update the driver to use current CUPS APIs (not the older deprecated ones)
4 and fix some compile-time warnings
5 * Use the PPD API to get the value of the MediaType flag, which is used to
6 pass the "Roll-fed media" flag into the driver
7 * Correct the margins for QL-series P-Touch paper-label printers - these
8 have a fixed 3mm margin (see the command spec) while the PT-series
9 laminated plastic label printers have no appreciable margins.
10 * Correct the format of the "ESC i z" (Print Information) command to match
11 what is specified in the P-touch 500 raster command spec. Notably set the
12 "passed parameter valid" bits, and send valid values for die-cut labels
13 and continuous paper rolls.
14 * Send the "ESC i d" (Set Margin) command for QL series printers. This is
15 required by the command spec. The margin is set to 3mm for continuous
16 paper and zero for die-cut (see the command spec)
17 * Fix an issue with margins in the driver (disable blank-line padding). This
18 was partly responsible for the "excess paper feed" issue.
19 * Suppress the spurious "ESC i z" which was sent with incorrect contents at
20 the start of the job.
21 * Fix the Enable Cutter command.
22 * Send 350 bytes of NULL/no-op commands at the start of the job. This allows
23 the driver to recover the printer into a known state if communication was
24 interrupted mid-transfer. This is recommended in the command spec.
25 * Remove the "determined by page size" option from "Roll-fed media" as this
26 no longer works.
27 * Remove the "Advance Media" option, as this allowed users to configure the
28 driver to generate print control codes which are illegal per the Brother
29 documentation. This is now fixed at "Advance at end of job" (send a Form
30 Feed at the end of every page, except the last which has an Eject
31 command instead).
32 * Merge in the changes formerly provided by send-esc-i-A-for-QL-only.patch.
33
34See also:
35 Brother QL Series Command Reference (QL-500/550/560/570/580N/650TD/700/1050/1060N)
36 <http://download.brother.com/welcome/docp000678/cv_qlseries_eng_raster_600.pdf>
37
38Author: Philip Pemberton <philpem@philpem.me.uk>
39--- a/rastertoptch.c
40+++ b/rastertoptch.c
41@@ -297,8 +297,6 @@
42 #define IMAGE_HEIGHT_DEFAULT 0
43 /** Feed amount default */
44 #define FEED_DEFAULT 0
45-/** When to perform feed default */
46-#define PERFORM_FEED_DEFAULT CUPS_ADVANCE_NONE
47
48 #include <config.h>
49 #include <stdio.h>
50@@ -432,6 +430,7 @@
51 int label_preamble; /**< emit ESC i z ... */
52 bool concat_pages; /**< remove interlabel margins */
53 unsigned long rle_alloc_max; /**< max bytes used for rle_buffer */
54+ bool roll_fed_media; /**< continuous (not labels) roll media */
55 } job_options_t;
56
57 /**
58@@ -440,12 +439,10 @@
59 typedef struct {
60 cups_cut_t cut_media; /**< cut media mode */
61 cups_bool_t mirror; /**< mirror printing */
62- bool roll_fed_media; /**< continuous (not labels) roll media */
63 unsigned resolution [2]; /**< horiz & vertical resolution in DPI */
64 unsigned page_size [2]; /**< width & height of page in points */
65 unsigned image_height; /**< height of page image in pixels */
66 unsigned feed; /**< feed size in points */
67- cups_adv_t perform_feed; /**< When to feed */
68 } page_options_t;
69
70 /**
71@@ -469,12 +466,40 @@
72 LABEL_PREAMBLE_DEFAULT,
73 CONCAT_PAGES_DEFAULT,
74 RLE_ALLOC_MAX_DEFAULT,
75+ ROLL_FED_MEDIA_DEFAULT,
76 };
77 if (argc < 6) return options;
78 int num_options = 0;
79 cups_option_t* cups_options = NULL;
80+ ppd_file_t *ppd; /* PPD file */
81 num_options
82 = cupsParseOptions (argv [5], num_options, &cups_options);
83+
84+ // Load job options from the PPD file
85+ ppd = ppdOpenFile(getenv("PPD"));
86+ if (!ppd) {
87+ ppd_status_t status; /* PPD error */
88+ int linenum; /* Line number */
89+
90+ fprintf(stderr, "ERROR: The PPD file could not be opened.");
91+
92+ status = ppdLastError(&linenum);
93+
94+ fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
95+
96+ exit(EXIT_FAILURE);
97+ }
98+ ppdMarkDefaults(ppd);
99+ cupsMarkOptions(ppd, num_options, cups_options);
100+
101+ // Use PPD API to decode RollFedMedia choice
102+ ppd_choice_t *choice = ppdFindMarkedChoice(ppd, "RollFedMedia");
103+ fprintf(stderr, "DEBUG: Markedchoice for roll fed media is '%s', text '%s'\n", choice->choice, choice->text);
104+ options.roll_fed_media /* Default is continuous roll */
105+ = (strcasecmp ("Labels", choice->choice) != 0);
106+
107+
108+ // FIXME use PPD API
109 const char* cups_option
110 = cupsGetOption ("PixelXfer", num_options, cups_options);
111 if (cups_option) {
112@@ -526,8 +551,12 @@
113 OBTAIN_INT_OPTION ("TransferMode", xfer_mode, 0, 255);
114 OBTAIN_BOOL_OPTION ("SoftwareMirror", software_mirror);
115 OBTAIN_BOOL_OPTION ("LabelPreamble", label_preamble);
116- /* Release memory allocated for CUPS options struct */
117+
118+ /* Close the PPD file and
119+ * Release memory allocated for CUPS options struct */
120+ ppdClose(ppd);
121 cupsFreeOptions (num_options, cups_options);
122+
123 return options;
124 }
125
126@@ -559,20 +588,25 @@
127 * @param page_options page options to be updated
128 */
129 void
130-update_page_options (cups_page_header_t* header,
131+update_page_options (cups_page_header2_t* header,
132 page_options_t* page_options) {
133 page_options->cut_media = header->CutMedia;
134 page_options->mirror = header->MirrorPrint;
135 const char* media_type = header->MediaType;
136- page_options->roll_fed_media /* Default is continuous roll */
137- = (strcasecmp ("Labels", media_type) != 0);
138 page_options->resolution [0] = header->HWResolution [0];
139 page_options->resolution [1] = header->HWResolution [1];
140 page_options->page_size [0] = header->PageSize [0];
141 page_options->page_size [1] = header->PageSize [1];
142 page_options->image_height = header->cupsHeight;
143 page_options->feed = header->AdvanceDistance;
144- page_options->perform_feed = header->AdvanceMedia;
145+
146+ fprintf(stderr, "DEBUG: ==== PAGE OPTIONS ====\n");
147+ fprintf(stderr, "DEBUG: Cut Media = %d\n", header->CutMedia);
148+ fprintf(stderr, "DEBUG: Media Type = [%s]\n", header->MediaType);
149+ fprintf(stderr, "DEBUG: Resolution = [%d %d]\n", header->HWResolution[0], header->HWResolution[1]);
150+ fprintf(stderr, "DEBUG: PageSize = [%d %d]\n", header->PageSize[0], header->PageSize[1]);
151+ fprintf(stderr, "DEBUG: ImageHeight (header->cupsHeight) = %d\n", header->cupsHeight);
152+ fprintf(stderr, "DEBUG: Advance Distance = %d\n", header->AdvanceDistance);
153 }
154
155 void cancel_job (int signal);
156@@ -654,6 +688,13 @@
157 */
158 void
159 emit_job_cmds (job_options_t* job_options) {
160+ /* Send 350 bytes of NULL to clear print buffer in case an error occurred
161+ * previously. The printer ignores 0x00 bytes if it's waiting for a command.
162+ */
163+ int i;
164+ for (i=0; i<350; i++) {
165+ putchar(0x00);
166+ }
167 /* Initialise printer */
168 putchar (ESC); putchar ('@');
169 /* Emit print density selection command if required */
170@@ -685,7 +726,8 @@
171 inline void
172 emit_feed_cut_mirror (bool do_feed, unsigned feed,
173 bool do_cut,
174- bool do_mirror) {
175+ bool do_mirror,
176+ xfer_t xfer_mode) {
177 /* Determine feed nibble */
178 unsigned feed_nibble;
179 if (do_feed) {
180@@ -698,6 +740,14 @@
181 /* Determine mirror print bit*/
182 unsigned char mirror_bit = do_mirror ? 0x80 : 0x00;
183 /* Combine & emit printer command code */
184+ if (xfer_mode == ULP) {
185+ /* ESC i A is Enable Cutter -- used for QL-560 only, according to
186+ * <http://www.undocprint.org/formats/page_description_languages/brother_p-touch>
187+ * The QL-560 (actually the whole QL series) uses ULP mode, so we check for that.
188+ * The PT2450DX uses RLE and throw an INTERFACE ERROR if it sees this command.
189+ */
190+ putchar (ESC); putchar ('i'); putchar ('A'); putchar ((char) (do_cut ? 0x01 : 0x00));
191+ }
192 putchar (ESC); putchar ('i'); putchar ('M');
193 putchar ((char) (feed & 0x1f) | auto_cut_bit | mirror_bit);
194 }
195@@ -714,11 +764,19 @@
196 page_options_t* page_options,
197 unsigned page_size_y,
198 unsigned image_height_px) {
199- bool roll_fed_media = page_options->roll_fed_media;
200+
201+ static bool first_page = true; // True if this is the first page
202+ // (this function is only called once per page)
203+
204+ const unsigned char PI_KIND = 0x02; // Paper type (roll fed media bit) is valid
205+ const unsigned char PI_WIDTH = 0x04; // Paper width is valid
206+ const unsigned char PI_LENGTH = 0x08; // Paper length is valid
207+
208+ bool roll_fed_media = job_options->roll_fed_media;
209 /* Determine print quality bit */
210 unsigned char print_quality_bit
211 = (job_options->print_quality_high == CUPS_TRUE) ? 0x40 : 0x00;
212- unsigned char roll_fed_media_bit = roll_fed_media ? 0x00 : 0x01;
213+ unsigned char paper_type_id = roll_fed_media ? 0x0A : 0x0B;
214 /* Get tape width in mm */
215 int tape_width_mm = lrint (page_options->page_size [0] * MM_PER_PT);
216 if (tape_width_mm > 0xff) {
217@@ -741,11 +799,28 @@
218 }
219 /* Combine & emit printer command code */
220 putchar (ESC); putchar ('i'); putchar ('z');
221- putchar (print_quality_bit); putchar (roll_fed_media_bit);
222- putchar (tape_width_mm & 0xff); putchar (tape_height_mm & 0xff);
223+ putchar (print_quality_bit | PI_KIND | PI_WIDTH | PI_LENGTH);
224+ putchar (paper_type_id);
225+ putchar (tape_width_mm & 0xff);
226+ putchar (tape_height_mm & 0xff);
227 putchar (image_height_px & 0xff);
228 putchar ((image_height_px >> 8) & 0xff);
229- putchar (0x00); putchar (0x00); putchar (0x00); putchar (0x00);
230+ putchar ((image_height_px >> 16) & 0xff);
231+ putchar ((image_height_px >> 24) & 0xff);
232+ putchar (first_page ? 0x00 : 0x01); // n9: 0 for first page, 1 for other pages
233+ putchar (0x00); // n10, always 0
234+
235+ first_page = false;
236+
237+ /* Send a SET MARGIN command */
238+ putchar(ESC); putchar('i'); putchar('d');
239+ if (roll_fed_media) {
240+ /* Continuous tape, specify 35 dots (3mm) */
241+ putchar(35); putchar(0);
242+ } else {
243+ /* Die-cut labels, specify no margin */
244+ putchar(0); putchar(0);
245+ }
246 }
247 /**
248 * Emit printer command codes at start of page for options that have
249@@ -795,31 +870,20 @@
250
251 /* Set feed, auto cut and mirror print */
252 unsigned feed = new_page_options->feed;
253- cups_adv_t perform_feed = new_page_options->perform_feed;
254 cups_cut_t cut_media = new_page_options->cut_media;
255 cups_bool_t mirror = new_page_options->mirror;
256 if (force
257 || feed != old_page_options->feed
258- || perform_feed != old_page_options->perform_feed
259 || cut_media != old_page_options->cut_media
260 || mirror != old_page_options->mirror)
261 /* We only know how to feed after each page */
262- emit_feed_cut_mirror (perform_feed == CUPS_ADVANCE_PAGE, feed,
263+ emit_feed_cut_mirror (false, feed,
264 cut_media == CUPS_CUT_PAGE,
265- mirror == CUPS_TRUE);
266- /* Set media and quality if label preamble is requested */
267+ mirror == CUPS_TRUE,
268+ job_options->pixel_xfer);
269+
270 unsigned page_size_y = new_page_options->page_size [1];
271 unsigned image_height_px = lrint (page_size_y * vres / 72.0);
272- if (job_options->label_preamble && !job_options->concat_pages
273- && (force
274- || (new_page_options->roll_fed_media
275- != old_page_options->roll_fed_media)
276- || new_page_size_x != old_page_size_x
277- || page_size_y != old_page_options->page_size [1]))
278- emit_quality_rollfed_size (job_options, new_page_options,
279- page_size_y, image_height_px);
280-
281- /* WHY DON'T WE SET MARGIN (ESC i d ...)? */
282
283 /* Set pixel data transfer compression */
284 if (force) {
285@@ -907,7 +971,7 @@
286 #ifdef DEBUG
287 if (debug)
288 fprintf (stderr, "DEBUG: generate_emit_line "
289- "(in_buffer=%0x, out_buffer=%0x, "
290+ "(in_buffer=%p, out_buffer=%p, "
291 "buflen=%d, bytes_per_line=%d, right_padding_bytes=%d, "
292 "shift=%d, do_mirror=%d, xormask=%0x)\n",
293 in_buffer, out_buffer, buflen, bytes_per_line,
294@@ -1068,7 +1132,7 @@
295 #ifdef DEBUG
296 if (debug)
297 fprintf (stderr, "DEBUG: ensure_rle_buf_space (bytes=%d): "
298- "increasing rle_buffer from %d to %d\n",
299+ "increasing rle_buffer from %zu to %zu\n",
300 bytes,
301 rle_alloced * sizeof (char),
302 new_alloced * sizeof (char));
303@@ -1291,7 +1355,7 @@
304 job_options_t* job_options,
305 page_options_t* page_options,
306 cups_raster_t* ras,
307- cups_page_header_t* header) {
308+ cups_page_header2_t* header) {
309 unsigned char xormask = (header->NegativePrint ? ~0 : 0);
310 /* Determine whether we need to mirror the pixel data */
311 int do_mirror = job_options->software_mirror && page_options->mirror;
312@@ -1362,8 +1426,10 @@
313 unsigned top_distance_pt
314 = page_size_y - header->ImagingBoundingBox [3];
315 if (top_distance_pt != 0) {
316+ fprintf(stderr, "DEBUG: philpem -- Top distance pt nonzero, %d\n", top_distance_pt);
317 top_empty_lines = lrint (top_distance_pt * scale_pt2ypixels);
318- empty_lines += top_empty_lines;
319+ fprintf(stderr, "DEBUG: philpem -- Top empty lines %d\n", top_empty_lines);
320+ //empty_lines += top_empty_lines;
321 }
322 }
323 /* Generate and store actual page data */
324@@ -1404,6 +1470,11 @@
325 bot_empty_lines = image_height_px - top_empty_lines - y;
326 else
327 bot_empty_lines = 0;
328+
329+
330+ fprintf(stderr, "DEBUG: philpem -- Bottom empty lines %d\n", bot_empty_lines);
331+ bot_empty_lines = 0;
332+
333 if (bot_empty_lines != 0 && !job_options->concat_pages)
334 empty_lines += bot_empty_lines;
335 fprintf (stderr,
336@@ -1423,19 +1494,17 @@
337 process_rasterdata (int fd, job_options_t* job_options) {
338 int page = 1; /* Page number */
339 cups_raster_t* ras; /* Raster stream for printing */
340- cups_page_header_t header; /* Current page header */
341+ cups_page_header2_t header; /* Current page header */
342 int first_page = true; /* Is this the first page? */
343 int more_pages; /* Are there more pages left? */
344 int bytes_per_line = job_options->bytes_per_line;
345 page_options_t page_options [2] = {{
346 CUT_MEDIA_DEFAULT,
347 MIRROR_DEFAULT,
348- ROLL_FED_MEDIA_DEFAULT,
349 RESOLUTION_DEFAULT,
350 PAGE_SIZE_DEFAULT,
351 IMAGE_HEIGHT_DEFAULT,
352- FEED_DEFAULT,
353- PERFORM_FEED_DEFAULT,}
354+ FEED_DEFAULT,}
355 }; /* Current & preceding page opts */
356 page_options_t* new_page_options
357 = page_options + 0; /* Options for current page */
358@@ -1443,7 +1512,7 @@
359 = page_options + 1; /* Options for preceding page */
360 page_options_t* tmp_page_options;/* Temp variable for swapping */
361 ras = cupsRasterOpen (fd, CUPS_RASTER_READ);
362- for (more_pages = cupsRasterReadHeader (ras, &header);
363+ for (more_pages = cupsRasterReadHeader2 (ras, &header);
364 more_pages;
365 tmp_page_options = old_page_options,
366 old_page_options = new_page_options,
367@@ -1452,6 +1521,7 @@
368 update_page_options (&header, new_page_options);
369 #ifdef DEBUG
370 if (debug) {
371+ fprintf (stderr, "DEBUG: MediaType = %s\n", header.MediaType);
372 fprintf (stderr, "DEBUG: pixel_xfer = %d\n", job_options->pixel_xfer);
373 fprintf (stderr, "DEBUG: print_quality_high = %d\n", job_options->print_quality_high);
374 fprintf (stderr, "DEBUG: half_cut = %d\n", job_options->half_cut);
375@@ -1464,12 +1534,11 @@
376 fprintf (stderr, "DEBUG: concat_pages = %d\n", job_options->concat_pages);
377 fprintf (stderr, "DEBUG: cut_media = %d\n", new_page_options->cut_media);
378 fprintf (stderr, "DEBUG: mirror = %d\n", new_page_options->mirror);
379- fprintf (stderr, "DEBUG: roll_fed_media = %d\n", new_page_options->roll_fed_media);
380+ fprintf (stderr, "DEBUG: roll_fed_media = %d\n", job_options->roll_fed_media);
381 fprintf (stderr, "DEBUG: resolution = %d x %d\n", new_page_options->resolution [0], new_page_options->resolution [1]);
382 fprintf (stderr, "DEBUG: page_size = %d x %d\n", new_page_options->page_size [0], new_page_options->page_size [1]);
383 fprintf (stderr, "DEBUG: image_height = %d\n", new_page_options->image_height);
384 fprintf (stderr, "DEBUG: feed = %d\n", new_page_options->feed);
385- fprintf (stderr, "DEBUG: perform_feed = %d\n", new_page_options->perform_feed);
386 fprintf (stderr, "DEBUG: header->ImagingBoundingBox = [%u, %u, %u, %u]\n",
387 header.ImagingBoundingBox [0], header.ImagingBoundingBox [1],
388 header.ImagingBoundingBox [2], header.ImagingBoundingBox [3]);
389@@ -1486,19 +1555,15 @@
390 emit_raster_lines (page, job_options, new_page_options, ras, &header);
391 unsigned char xormask = (header.NegativePrint ? ~0 : 0);
392 /* Determine whether this is the last page (fetch next) */
393- more_pages = cupsRasterReadHeader (ras, &header);
394+ more_pages = cupsRasterReadHeader2 (ras, &header);
395 /* Do feeding or ejecting at the end of each page. */
396- cups_adv_t perform_feed = new_page_options->perform_feed;
397 if (more_pages) {
398 if (!job_options->concat_pages) {
399 RLE_store_empty_lines
400 (job_options, page_options, empty_lines, xormask);
401 empty_lines = 0;
402 flush_rle_buffer (job_options, page_options);
403- if (perform_feed == CUPS_ADVANCE_PAGE)
404- putchar (PTC_EJECT); /* Emit eject marker to force feed */
405- else
406- putchar (PTC_FORMFEED); /* Emit page end marker without feed */
407+ putchar (PTC_FORMFEED); /* Emit page end marker without feed */
408 }
409 } else {
410 if (!job_options->concat_pages) {
411@@ -1506,7 +1571,6 @@
412 (job_options, page_options, empty_lines, xormask);
413 empty_lines = 0;
414 flush_rle_buffer (job_options, page_options);
415- putchar (PTC_FORMFEED);
416 } else {
417 double scale_pt2ypixels = header.HWResolution [1] / 72.0;
418 unsigned bot_empty_lines
419@@ -1518,18 +1582,8 @@
420 flush_rle_buffer (job_options, page_options);
421 }
422
423- /* If special feed or cut at job end, emit commands to that effect */
424- cups_cut_t cut_media = new_page_options->cut_media;
425- if (perform_feed == CUPS_ADVANCE_JOB || cut_media == CUPS_CUT_JOB) {
426- emit_feed_cut_mirror
427- (perform_feed == CUPS_ADVANCE_PAGE ||
428- perform_feed == CUPS_ADVANCE_JOB,
429- new_page_options->feed,
430- cut_media == CUPS_CUT_PAGE || cut_media == CUPS_CUT_JOB,
431- new_page_options->mirror == CUPS_TRUE);
432- /* Emit eject marker */
433- putchar (PTC_EJECT);
434- }
435+ /* End of last page, send Eject command */
436+ putchar (PTC_EJECT);
437 }
438 page_end ();
439 /* Emit page count according to CUPS requirements */
440--- a/printer/Brother-QL-500.xml
441+++ b/printer/Brother-QL-500.xml
442@@ -31,6 +31,15 @@
443 <y>300</y>
444 </dpi>
445 </resolution>
446+ <margins>
447+ <general>
448+ <unit>mm</unit>
449+ <top>3</top>
450+ <bottom>3</bottom>
451+ <left>1.5</left>
452+ <right>1.5</right>
453+ </general>
454+ </margins>
455 <consumables>
456 <comments>
457 <en>
458--- a/printer/Brother-QL-550.xml
459+++ b/printer/Brother-QL-550.xml
460@@ -31,6 +31,15 @@
461 <y>300</y>
462 </dpi>
463 </resolution>
464+ <margins>
465+ <general>
466+ <unit>mm</unit>
467+ <top>3</top>
468+ <bottom>3</bottom>
469+ <left>1.5</left>
470+ <right>1.5</right>
471+ </general>
472+ </margins>
473 <consumables>
474 <comments>
475 <en>
476--- a/printer/Brother-QL-650TD.xml
477+++ b/printer/Brother-QL-650TD.xml
478@@ -31,6 +31,15 @@
479 <y>300</y>
480 </dpi>
481 </resolution>
482+ <margins>
483+ <general>
484+ <unit>mm</unit>
485+ <top>3</top>
486+ <bottom>3</bottom>
487+ <left>1.5</left>
488+ <right>1.5</right>
489+ </general>
490+ </margins>
491 <consumables>
492 <comments>
493 <en>
494--- a/opt/Brother-Ptouch-RollFedMedia.xml
495+++ b/opt/Brother-Ptouch-RollFedMedia.xml
496@@ -41,19 +41,6 @@
497 </constraint>
498 </constraints>
499 <enum_vals>
500- <enum_val id="ev/Auto">
501- <ev_longname>
502- <en>Automatically determined by page size</en>
503- </ev_longname>
504- <!-- A multilingual <comments> block can appear here, too;
505- it should be treated as documentation for the user. -->
506- <ev_shortname>
507- <en>Auto</en>
508- <!-- Until someone tells me how to learn the user locale in
509- backends, the shortname must be monolingual in <en>! -->
510- </ev_shortname>
511- <ev_driverval></ev_driverval>
512- </enum_val>
513 <enum_val id="ev/Roll">
514 <ev_longname>
515 <en>Continuous roll</en>
516--- a/opt/Brother-Ptouch-AdvanceMedia.xml
517+++ /dev/null
518@@ -1,84 +0,0 @@
519-<!--
520-Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
521-
522-This file is part of ptouch-driver.
523-
524-ptouch-driver is free software; you can redistribute it and/or modify
525-it under the terms of the GNU General Public License as published by
526-the Free Software Foundation; either version 2 of the License, or (at
527-your option) any later version.
528-
529-ptouch-driver is distributed in the hope that it will be useful, but
530-WITHOUT ANY WARRANTY; without even the implied warranty of
531-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
532-General Public License for more details.
533-
534-You should have received a copy of the GNU General Public License
535-along with ptouch-driver; if not, write to the Free Software
536-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
537-USA
538--->
539-<option type='enum' id='Brother-Ptouch-AdvanceMedia'>
540- <!-- A multilingual <comments> block can appear here, too;
541- it should be treated as documentation for the user. -->
542- <arg_longname>
543- <en>Advance Media</en>
544- </arg_longname>
545- <arg_shortname>
546- <en>AdvanceMedia</en><!-- backends only know <en> shortnames! -->
547- </arg_shortname>
548- <arg_execution>
549- <arg_group>Finishing</arg_group>
550- <arg_order>110</arg_order>
551- <arg_spot>A</arg_spot>
552- <arg_postscript />
553- <arg_proto>&lt;&lt;/AdvanceMedia %s&gt;&gt;setpagedevice</arg_proto>
554- </arg_execution>
555- <constraints>
556- <constraint sense='true'>
557- <driver>ptouch</driver>
558- <arg_defval>ev/Off</arg_defval>
559- </constraint>
560- </constraints>
561- <enum_vals>
562- <enum_val id="ev/Off">
563- <ev_longname>
564- <en>Do not advance the tape</en>
565- </ev_longname>
566- <!-- A multilingual <comments> block can appear here, too;
567- it should be treated as documentation for the user. -->
568- <ev_shortname>
569- <en>Off</en>
570- <!-- Until someone tells me how to learn the user locale in
571- backends, the shortname must be monolingual in <en>! -->
572- </ev_shortname>
573- <ev_driverval>0</ev_driverval>
574- </enum_val>
575- <enum_val id="ev/LabelEnd">
576- <ev_longname>
577- <en>Advance the tape after each label</en>
578- </ev_longname>
579- <!-- A multilingual <comments> block can appear here, too;
580- it should be treated as documentation for the user. -->
581- <ev_shortname>
582- <en>LabelEnd</en>
583- <!-- Until someone tells me how to learn the user locale in
584- backends, the shortname must be monolingual in <en>! -->
585- </ev_shortname>
586- <ev_driverval>4</ev_driverval>
587- </enum_val>
588- <enum_val id="ev/JobEnd">
589- <ev_longname>
590- <en>Advance the tape at the end of the job</en>
591- </ev_longname>
592- <!-- A multilingual <comments> block can appear here, too;
593- it should be treated as documentation for the user. -->
594- <ev_shortname>
595- <en>JobEnd</en>
596- <!-- Until someone tells me how to learn the user locale in
597- backends, the shortname must be monolingual in <en>! -->
598- </ev_shortname>
599- <ev_driverval>2</ev_driverval>
600- </enum_val>
601- </enum_vals>
602-</option>
603--- a/Makefile.am
604+++ b/Makefile.am
605@@ -47,7 +47,6 @@
606 printer/Brother-PT-9500PC.xml \
607 printer/Brother-PT-9600.xml \
608 opt/Brother-Ptouch-AdvanceDistance.xml \
609- opt/Brother-Ptouch-AdvanceMedia.xml \
610 opt/Brother-Ptouch-Align.xml \
611 opt/Brother-Ptouch-BytesPerLine.xml \
612 opt/Brother-Ptouch-ConcatPages.xml \
613--- a/ptouch-driver-foomatic.spec.in
614+++ b/ptouch-driver-foomatic.spec.in
615@@ -76,7 +76,6 @@
616 /usr/share/foomatic/db/source/printer/Brother-QL-550.xml
617 /usr/share/foomatic/db/source/printer/Brother-QL-650TD.xml
618 /usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceDistance.xml
619-/usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceMedia.xml
620 /usr/share/foomatic/db/source/opt/Brother-Ptouch-Align.xml
621 /usr/share/foomatic/db/source/opt/Brother-Ptouch-BytesPerLine.xml
622 /usr/share/foomatic/db/source/opt/Brother-Ptouch-ConcatPages.xml
0623
=== modified file 'debian/patches/send-esc-i-A-for-QL-only.patch'
--- debian/patches/send-esc-i-A-for-QL-only.patch 2014-03-06 16:23:54 +0000
+++ debian/patches/send-esc-i-A-for-QL-only.patch 2015-04-10 21:18:54 +0000
@@ -40,7 +40,7 @@
40 cut_media == CUPS_CUT_PAGE,40 cut_media == CUPS_CUT_PAGE,
41- mirror == CUPS_TRUE);41- mirror == CUPS_TRUE);
42+ mirror == CUPS_TRUE,42+ mirror == CUPS_TRUE,
43+ job_options->pixel_xfer == ULP);43+ job_options->pixel_xfer);
44 /* Set media and quality if label preamble is requested */44 /* Set media and quality if label preamble is requested */
45 unsigned page_size_y = new_page_options->page_size [1];45 unsigned page_size_y = new_page_options->page_size [1];
46 unsigned image_height_px = lrint (page_size_y * vres / 72.0);46 unsigned image_height_px = lrint (page_size_y * vres / 72.0);
4747
=== modified file 'debian/patches/series'
--- debian/patches/series 2014-03-06 16:23:54 +0000
+++ debian/patches/series 2015-04-10 21:18:54 +0000
@@ -1,2 +1,2 @@
1foomatic-data-fixes.patch1foomatic-data-fixes.patch
2send-esc-i-A-for-QL-only.patch2philpem-ptouch-fixes
33
=== removed file 'opt/Brother-Ptouch-AdvanceMedia.xml'
--- opt/Brother-Ptouch-AdvanceMedia.xml 2009-11-11 17:14:44 +0000
+++ opt/Brother-Ptouch-AdvanceMedia.xml 1970-01-01 00:00:00 +0000
@@ -1,84 +0,0 @@
1<!--
2Copyright (c) 2006 Arne John Glenstrup <panic@itu.dk>
3
4This file is part of ptouch-driver.
5
6ptouch-driver is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or (at
9your option) any later version.
10
11ptouch-driver is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with ptouch-driver; if not, write to the Free Software
18Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19USA
20-->
21<option type='enum' id='Brother-Ptouch-AdvanceMedia'>
22 <!-- A multilingual <comments> block can appear here, too;
23 it should be treated as documentation for the user. -->
24 <arg_longname>
25 <en>Advance Media</en>
26 </arg_longname>
27 <arg_shortname>
28 <en>AdvanceMedia</en><!-- backends only know <en> shortnames! -->
29 </arg_shortname>
30 <arg_execution>
31 <arg_group>Finishing</arg_group>
32 <arg_order>110</arg_order>
33 <arg_spot>A</arg_spot>
34 <arg_postscript />
35 <arg_proto>&lt;&lt;/AdvanceMedia %s&gt;&gt;setpagedevice</arg_proto>
36 </arg_execution>
37 <constraints>
38 <constraint sense='true'>
39 <driver>ptouch</driver>
40 <arg_defval>ev/Off</arg_defval>
41 </constraint>
42 </constraints>
43 <enum_vals>
44 <enum_val id="ev/Off">
45 <ev_longname>
46 <en>Do not advance the tape</en>
47 </ev_longname>
48 <!-- A multilingual <comments> block can appear here, too;
49 it should be treated as documentation for the user. -->
50 <ev_shortname>
51 <en>Off</en>
52 <!-- Until someone tells me how to learn the user locale in
53 backends, the shortname must be monolingual in <en>! -->
54 </ev_shortname>
55 <ev_driverval>0</ev_driverval>
56 </enum_val>
57 <enum_val id="ev/LabelEnd">
58 <ev_longname>
59 <en>Advance the tape after each label</en>
60 </ev_longname>
61 <!-- A multilingual <comments> block can appear here, too;
62 it should be treated as documentation for the user. -->
63 <ev_shortname>
64 <en>LabelEnd</en>
65 <!-- Until someone tells me how to learn the user locale in
66 backends, the shortname must be monolingual in <en>! -->
67 </ev_shortname>
68 <ev_driverval>4</ev_driverval>
69 </enum_val>
70 <enum_val id="ev/JobEnd">
71 <ev_longname>
72 <en>Advance the tape at the end of the job</en>
73 </ev_longname>
74 <!-- A multilingual <comments> block can appear here, too;
75 it should be treated as documentation for the user. -->
76 <ev_shortname>
77 <en>JobEnd</en>
78 <!-- Until someone tells me how to learn the user locale in
79 backends, the shortname must be monolingual in <en>! -->
80 </ev_shortname>
81 <ev_driverval>2</ev_driverval>
82 </enum_val>
83 </enum_vals>
84</option>
850
=== modified file 'opt/Brother-Ptouch-RollFedMedia.xml'
--- opt/Brother-Ptouch-RollFedMedia.xml 2009-11-11 17:14:44 +0000
+++ opt/Brother-Ptouch-RollFedMedia.xml 2015-04-10 21:18:54 +0000
@@ -41,19 +41,6 @@
41 </constraint>41 </constraint>
42 </constraints>42 </constraints>
43 <enum_vals>43 <enum_vals>
44 <enum_val id="ev/Auto">
45 <ev_longname>
46 <en>Automatically determined by page size</en>
47 </ev_longname>
48 <!-- A multilingual <comments> block can appear here, too;
49 it should be treated as documentation for the user. -->
50 <ev_shortname>
51 <en>Auto</en>
52 <!-- Until someone tells me how to learn the user locale in
53 backends, the shortname must be monolingual in <en>! -->
54 </ev_shortname>
55 <ev_driverval></ev_driverval>
56 </enum_val>
57 <enum_val id="ev/Roll">44 <enum_val id="ev/Roll">
58 <ev_longname>45 <ev_longname>
59 <en>Continuous roll</en>46 <en>Continuous roll</en>
6047
=== modified file 'printer/Brother-QL-500.xml'
--- printer/Brother-QL-500.xml 2009-11-11 17:14:44 +0000
+++ printer/Brother-QL-500.xml 2015-04-10 21:18:54 +0000
@@ -31,6 +31,15 @@
31 <y>300</y>31 <y>300</y>
32 </dpi>32 </dpi>
33 </resolution>33 </resolution>
34 <margins>
35 <general>
36 <unit>mm</unit>
37 <top>3</top>
38 <bottom>3</bottom>
39 <left>1.5</left>
40 <right>1.5</right>
41 </general>
42 </margins>
34 <consumables>43 <consumables>
35 <comments>44 <comments>
36 <en>45 <en>
3746
=== modified file 'printer/Brother-QL-550.xml'
--- printer/Brother-QL-550.xml 2011-08-29 12:27:35 +0000
+++ printer/Brother-QL-550.xml 2015-04-10 21:18:54 +0000
@@ -28,9 +28,18 @@
28 <resolution>28 <resolution>
29 <dpi>29 <dpi>
30 <x>300</x>30 <x>300</x>
31 <y>275</y>31 <y>300</y>
32 </dpi>32 </dpi>
33 </resolution>33 </resolution>
34 <margins>
35 <general>
36 <unit>mm</unit>
37 <top>3</top>
38 <bottom>3</bottom>
39 <left>1.5</left>
40 <right>1.5</right>
41 </general>
42 </margins>
34 <consumables>43 <consumables>
35 <comments>44 <comments>
36 <en>45 <en>
3746
=== modified file 'printer/Brother-QL-650TD.xml'
--- printer/Brother-QL-650TD.xml 2009-11-11 17:14:44 +0000
+++ printer/Brother-QL-650TD.xml 2015-04-10 21:18:54 +0000
@@ -31,6 +31,15 @@
31 <y>300</y>31 <y>300</y>
32 </dpi>32 </dpi>
33 </resolution>33 </resolution>
34 <margins>
35 <general>
36 <unit>mm</unit>
37 <top>3</top>
38 <bottom>3</bottom>
39 <left>1.5</left>
40 <right>1.5</right>
41 </general>
42 </margins>
34 <consumables>43 <consumables>
35 <comments>44 <comments>
36 <en>45 <en>
3746
=== modified file 'ptouch-driver-foomatic.spec.in'
--- ptouch-driver-foomatic.spec.in 2009-11-11 17:14:44 +0000
+++ ptouch-driver-foomatic.spec.in 2015-04-10 21:18:54 +0000
@@ -76,7 +76,6 @@
76/usr/share/foomatic/db/source/printer/Brother-QL-550.xml76/usr/share/foomatic/db/source/printer/Brother-QL-550.xml
77/usr/share/foomatic/db/source/printer/Brother-QL-650TD.xml77/usr/share/foomatic/db/source/printer/Brother-QL-650TD.xml
78/usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceDistance.xml78/usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceDistance.xml
79/usr/share/foomatic/db/source/opt/Brother-Ptouch-AdvanceMedia.xml
80/usr/share/foomatic/db/source/opt/Brother-Ptouch-Align.xml79/usr/share/foomatic/db/source/opt/Brother-Ptouch-Align.xml
81/usr/share/foomatic/db/source/opt/Brother-Ptouch-BytesPerLine.xml80/usr/share/foomatic/db/source/opt/Brother-Ptouch-BytesPerLine.xml
82/usr/share/foomatic/db/source/opt/Brother-Ptouch-ConcatPages.xml81/usr/share/foomatic/db/source/opt/Brother-Ptouch-ConcatPages.xml
8382
=== modified file 'rastertoptch.c'
--- rastertoptch.c 2014-03-06 16:23:54 +0000
+++ rastertoptch.c 2015-04-10 21:18:54 +0000
@@ -297,8 +297,6 @@
297#define IMAGE_HEIGHT_DEFAULT 0297#define IMAGE_HEIGHT_DEFAULT 0
298/** Feed amount default */298/** Feed amount default */
299#define FEED_DEFAULT 0299#define FEED_DEFAULT 0
300/** When to perform feed default */
301#define PERFORM_FEED_DEFAULT CUPS_ADVANCE_NONE
302300
303#include <config.h>301#include <config.h>
304#include <stdio.h>302#include <stdio.h>
@@ -432,6 +430,7 @@
432 int label_preamble; /**< emit ESC i z ... */430 int label_preamble; /**< emit ESC i z ... */
433 bool concat_pages; /**< remove interlabel margins */431 bool concat_pages; /**< remove interlabel margins */
434 unsigned long rle_alloc_max; /**< max bytes used for rle_buffer */432 unsigned long rle_alloc_max; /**< max bytes used for rle_buffer */
433 bool roll_fed_media; /**< continuous (not labels) roll media */
435} job_options_t;434} job_options_t;
436435
437/**436/**
@@ -440,12 +439,10 @@
440typedef struct {439typedef struct {
441 cups_cut_t cut_media; /**< cut media mode */440 cups_cut_t cut_media; /**< cut media mode */
442 cups_bool_t mirror; /**< mirror printing */441 cups_bool_t mirror; /**< mirror printing */
443 bool roll_fed_media; /**< continuous (not labels) roll media */
444 unsigned resolution [2]; /**< horiz & vertical resolution in DPI */442 unsigned resolution [2]; /**< horiz & vertical resolution in DPI */
445 unsigned page_size [2]; /**< width & height of page in points */443 unsigned page_size [2]; /**< width & height of page in points */
446 unsigned image_height; /**< height of page image in pixels */444 unsigned image_height; /**< height of page image in pixels */
447 unsigned feed; /**< feed size in points */445 unsigned feed; /**< feed size in points */
448 cups_adv_t perform_feed; /**< When to feed */
449} page_options_t;446} page_options_t;
450447
451/**448/**
@@ -469,12 +466,40 @@
469 LABEL_PREAMBLE_DEFAULT,466 LABEL_PREAMBLE_DEFAULT,
470 CONCAT_PAGES_DEFAULT,467 CONCAT_PAGES_DEFAULT,
471 RLE_ALLOC_MAX_DEFAULT,468 RLE_ALLOC_MAX_DEFAULT,
469 ROLL_FED_MEDIA_DEFAULT,
472 };470 };
473 if (argc < 6) return options;471 if (argc < 6) return options;
474 int num_options = 0;472 int num_options = 0;
475 cups_option_t* cups_options = NULL;473 cups_option_t* cups_options = NULL;
474 ppd_file_t *ppd; /* PPD file */
476 num_options475 num_options
477 = cupsParseOptions (argv [5], num_options, &cups_options);476 = cupsParseOptions (argv [5], num_options, &cups_options);
477
478 // Load job options from the PPD file
479 ppd = ppdOpenFile(getenv("PPD"));
480 if (!ppd) {
481 ppd_status_t status; /* PPD error */
482 int linenum; /* Line number */
483
484 fprintf(stderr, "ERROR: The PPD file could not be opened.");
485
486 status = ppdLastError(&linenum);
487
488 fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
489
490 exit(EXIT_FAILURE);
491 }
492 ppdMarkDefaults(ppd);
493 cupsMarkOptions(ppd, num_options, cups_options);
494
495 // Use PPD API to decode RollFedMedia choice
496 ppd_choice_t *choice = ppdFindMarkedChoice(ppd, "RollFedMedia");
497 fprintf(stderr, "DEBUG: Markedchoice for roll fed media is '%s', text '%s'\n", choice->choice, choice->text);
498 options.roll_fed_media /* Default is continuous roll */
499 = (strcasecmp ("Labels", choice->choice) != 0);
500
501
502 // FIXME use PPD API
478 const char* cups_option503 const char* cups_option
479 = cupsGetOption ("PixelXfer", num_options, cups_options);504 = cupsGetOption ("PixelXfer", num_options, cups_options);
480 if (cups_option) {505 if (cups_option) {
@@ -526,8 +551,12 @@
526 OBTAIN_INT_OPTION ("TransferMode", xfer_mode, 0, 255);551 OBTAIN_INT_OPTION ("TransferMode", xfer_mode, 0, 255);
527 OBTAIN_BOOL_OPTION ("SoftwareMirror", software_mirror);552 OBTAIN_BOOL_OPTION ("SoftwareMirror", software_mirror);
528 OBTAIN_BOOL_OPTION ("LabelPreamble", label_preamble);553 OBTAIN_BOOL_OPTION ("LabelPreamble", label_preamble);
529 /* Release memory allocated for CUPS options struct */554
555 /* Close the PPD file and
556 * Release memory allocated for CUPS options struct */
557 ppdClose(ppd);
530 cupsFreeOptions (num_options, cups_options);558 cupsFreeOptions (num_options, cups_options);
559
531 return options;560 return options;
532}561}
533562
@@ -559,20 +588,25 @@
559 * @param page_options page options to be updated588 * @param page_options page options to be updated
560 */589 */
561void590void
562update_page_options (cups_page_header_t* header,591update_page_options (cups_page_header2_t* header,
563 page_options_t* page_options) {592 page_options_t* page_options) {
564 page_options->cut_media = header->CutMedia;593 page_options->cut_media = header->CutMedia;
565 page_options->mirror = header->MirrorPrint;594 page_options->mirror = header->MirrorPrint;
566 const char* media_type = header->MediaType;595 const char* media_type = header->MediaType;
567 page_options->roll_fed_media /* Default is continuous roll */
568 = (strcasecmp ("Labels", media_type) != 0);
569 page_options->resolution [0] = header->HWResolution [0];596 page_options->resolution [0] = header->HWResolution [0];
570 page_options->resolution [1] = header->HWResolution [1];597 page_options->resolution [1] = header->HWResolution [1];
571 page_options->page_size [0] = header->PageSize [0];598 page_options->page_size [0] = header->PageSize [0];
572 page_options->page_size [1] = header->PageSize [1];599 page_options->page_size [1] = header->PageSize [1];
573 page_options->image_height = header->cupsHeight;600 page_options->image_height = header->cupsHeight;
574 page_options->feed = header->AdvanceDistance;601 page_options->feed = header->AdvanceDistance;
575 page_options->perform_feed = header->AdvanceMedia;602
603 fprintf(stderr, "DEBUG: ==== PAGE OPTIONS ====\n");
604 fprintf(stderr, "DEBUG: Cut Media = %d\n", header->CutMedia);
605 fprintf(stderr, "DEBUG: Media Type = [%s]\n", header->MediaType);
606 fprintf(stderr, "DEBUG: Resolution = [%d %d]\n", header->HWResolution[0], header->HWResolution[1]);
607 fprintf(stderr, "DEBUG: PageSize = [%d %d]\n", header->PageSize[0], header->PageSize[1]);
608 fprintf(stderr, "DEBUG: ImageHeight (header->cupsHeight) = %d\n", header->cupsHeight);
609 fprintf(stderr, "DEBUG: Advance Distance = %d\n", header->AdvanceDistance);
576}610}
577611
578void cancel_job (int signal);612void cancel_job (int signal);
@@ -654,6 +688,13 @@
654 */688 */
655void689void
656emit_job_cmds (job_options_t* job_options) {690emit_job_cmds (job_options_t* job_options) {
691 /* Send 350 bytes of NULL to clear print buffer in case an error occurred
692 * previously. The printer ignores 0x00 bytes if it's waiting for a command.
693 */
694 int i;
695 for (i=0; i<350; i++) {
696 putchar(0x00);
697 }
657 /* Initialise printer */698 /* Initialise printer */
658 putchar (ESC); putchar ('@');699 putchar (ESC); putchar ('@');
659 /* Emit print density selection command if required */700 /* Emit print density selection command if required */
@@ -723,11 +764,19 @@
723 page_options_t* page_options,764 page_options_t* page_options,
724 unsigned page_size_y,765 unsigned page_size_y,
725 unsigned image_height_px) {766 unsigned image_height_px) {
726 bool roll_fed_media = page_options->roll_fed_media;767
768 static bool first_page = true; // True if this is the first page
769 // (this function is only called once per page)
770
771 const unsigned char PI_KIND = 0x02; // Paper type (roll fed media bit) is valid
772 const unsigned char PI_WIDTH = 0x04; // Paper width is valid
773 const unsigned char PI_LENGTH = 0x08; // Paper length is valid
774
775 bool roll_fed_media = job_options->roll_fed_media;
727 /* Determine print quality bit */776 /* Determine print quality bit */
728 unsigned char print_quality_bit777 unsigned char print_quality_bit
729 = (job_options->print_quality_high == CUPS_TRUE) ? 0x40 : 0x00;778 = (job_options->print_quality_high == CUPS_TRUE) ? 0x40 : 0x00;
730 unsigned char roll_fed_media_bit = roll_fed_media ? 0x00 : 0x01;779 unsigned char paper_type_id = roll_fed_media ? 0x0A : 0x0B;
731 /* Get tape width in mm */780 /* Get tape width in mm */
732 int tape_width_mm = lrint (page_options->page_size [0] * MM_PER_PT);781 int tape_width_mm = lrint (page_options->page_size [0] * MM_PER_PT);
733 if (tape_width_mm > 0xff) {782 if (tape_width_mm > 0xff) {
@@ -750,11 +799,28 @@
750 }799 }
751 /* Combine & emit printer command code */800 /* Combine & emit printer command code */
752 putchar (ESC); putchar ('i'); putchar ('z');801 putchar (ESC); putchar ('i'); putchar ('z');
753 putchar (print_quality_bit); putchar (roll_fed_media_bit);802 putchar (print_quality_bit | PI_KIND | PI_WIDTH | PI_LENGTH);
754 putchar (tape_width_mm & 0xff); putchar (tape_height_mm & 0xff);803 putchar (paper_type_id);
804 putchar (tape_width_mm & 0xff);
805 putchar (tape_height_mm & 0xff);
755 putchar (image_height_px & 0xff);806 putchar (image_height_px & 0xff);
756 putchar ((image_height_px >> 8) & 0xff);807 putchar ((image_height_px >> 8) & 0xff);
757 putchar (0x00); putchar (0x00); putchar (0x00); putchar (0x00);808 putchar ((image_height_px >> 16) & 0xff);
809 putchar ((image_height_px >> 24) & 0xff);
810 putchar (first_page ? 0x00 : 0x01); // n9: 0 for first page, 1 for other pages
811 putchar (0x00); // n10, always 0
812
813 first_page = false;
814
815 /* Send a SET MARGIN command */
816 putchar(ESC); putchar('i'); putchar('d');
817 if (roll_fed_media) {
818 /* Continuous tape, specify 35 dots (3mm) */
819 putchar(35); putchar(0);
820 } else {
821 /* Die-cut labels, specify no margin */
822 putchar(0); putchar(0);
823 }
758}824}
759/**825/**
760 * Emit printer command codes at start of page for options that have826 * Emit printer command codes at start of page for options that have
@@ -804,32 +870,20 @@
804870
805 /* Set feed, auto cut and mirror print */871 /* Set feed, auto cut and mirror print */
806 unsigned feed = new_page_options->feed;872 unsigned feed = new_page_options->feed;
807 cups_adv_t perform_feed = new_page_options->perform_feed;
808 cups_cut_t cut_media = new_page_options->cut_media;873 cups_cut_t cut_media = new_page_options->cut_media;
809 cups_bool_t mirror = new_page_options->mirror;874 cups_bool_t mirror = new_page_options->mirror;
810 if (force875 if (force
811 || feed != old_page_options->feed876 || feed != old_page_options->feed
812 || perform_feed != old_page_options->perform_feed
813 || cut_media != old_page_options->cut_media877 || cut_media != old_page_options->cut_media
814 || mirror != old_page_options->mirror)878 || mirror != old_page_options->mirror)
815 /* We only know how to feed after each page */879 /* We only know how to feed after each page */
816 emit_feed_cut_mirror (perform_feed == CUPS_ADVANCE_PAGE, feed,880 emit_feed_cut_mirror (false, feed,
817 cut_media == CUPS_CUT_PAGE,881 cut_media == CUPS_CUT_PAGE,
818 mirror == CUPS_TRUE,882 mirror == CUPS_TRUE,
819 job_options->pixel_xfer == ULP);883 job_options->pixel_xfer);
820 /* Set media and quality if label preamble is requested */884
821 unsigned page_size_y = new_page_options->page_size [1];885 unsigned page_size_y = new_page_options->page_size [1];
822 unsigned image_height_px = lrint (page_size_y * vres / 72.0);886 unsigned image_height_px = lrint (page_size_y * vres / 72.0);
823 if (job_options->label_preamble && !job_options->concat_pages
824 && (force
825 || (new_page_options->roll_fed_media
826 != old_page_options->roll_fed_media)
827 || new_page_size_x != old_page_size_x
828 || page_size_y != old_page_options->page_size [1]))
829 emit_quality_rollfed_size (job_options, new_page_options,
830 page_size_y, image_height_px);
831
832 /* WHY DON'T WE SET MARGIN (ESC i d ...)? */
833887
834 /* Set pixel data transfer compression */888 /* Set pixel data transfer compression */
835 if (force) {889 if (force) {
@@ -917,7 +971,7 @@
917#ifdef DEBUG971#ifdef DEBUG
918 if (debug)972 if (debug)
919 fprintf (stderr, "DEBUG: generate_emit_line "973 fprintf (stderr, "DEBUG: generate_emit_line "
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches