%-------------------------------------------- % $Header: /cvsroot/pgfplots/pgfplots/generic/pgfplots/util/pgfplotsbinary.code.tex,v 1.13 2009/07/21 18:18:48 ludewich Exp $ % % Package pgfplots % % Provides a user-friendly interface to create function plots (normal % plots, semi-logplots and double-logplots). % % It is based on Till Tantau's PGF package. % % Copyright 2007/2008 by Christian Feuersänger. % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation, either version 3 of the License, or % (at your option) any later version. % % This program is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this program. If not, see . % %-------------------------------------------- % This file provides a self-contained package which does only need % pgfkeys. % % It provides a method to convert TeX numbers (integers and % dimensions) into binary format (macros with catcode 11 or 12). % \edef\pgfplotsbinaryatcode{\the\catcode`\@ } \catcode`\@=11 % Returns a single character, which has the % binary ASCII code '#1', with catcode 11. % % #1 (expands to) a number between 0 and 255 (inclusive). % % @see \pgfplotsgetchar Note that \pgfplotsgetchar is more powerful, % but can't be used inside of \edef (it is not expandable) whereas % \pgfplotscharno is. \def\pgfplotscharno#1{\csname pgfp@bin@#1\endcsname}% \let\pgfplotscharno@bincatcode=\pgfplotscharno \def\pgfplotscharno@lualatex#1{#1,} \input pgfplotsbinary.data.code.tex % Defines the LUA (!) value pgfplotsretval to be a binary string % containing the pgfplots binary value #1. % % #1 a pgfplots binary value collected with \pgfplotscharno. % More precisely, it should be a comma-separated sequence of numbers % of the form '0,255,2,128,' (can be terminated by comma). It will be % converted to the respective binary numbers 0x0, 0xff, 0x02,.. % % example: % \pgfplotsbinarytoluabinary{0, 255,2,128} % \directlua{ % pdf.immediateobj{"stream", pgfplotsretval,"/DataWithBinaryStream"} % } \def\pgfplotsbinarytoluabinary#1{% % lualatex does not support binary chars as pdftex does - so we have to resort to LUA % methods. The idea is to use % string.char(1,2,3) which results in a binary string with chars 0x01, 0x02, 0x03 etc. % I only need to get the integer numbers. To this end, I patch \pgfplotscharno % and create the binary string here: \pgfplotsutil@directlua{% pgfplotsretval = pgfplotsGetLuaBinaryStringFromCharIndices({#1}); }% }% % Defines \pgfplotsretval to be the ASCII character for #1, with % catcode 11. % % #1: either a number between 0 and 255 (inclusive) or a description % of the character. % % Examples: % \pgfplotsgetchar{35} % \pgfplotsgetchar{`\#} % code for '#' % \pgfplotsgetchar{`\^^M} % Newline % \pgfplotsgetchar{`\^^ff}% 255 % % @see \pgfplotscharno \def\pgfplotsgetchar#1{% \begingroup \count0=#1\relax \edef\pgfplotsretval{\pgfplotscharno{\the\count0 }}% \pgfmath@smuggleone\pgfplotsretval \endgroup }% \def\pgfplotsbinary@apphighorderbytes@BIGENDIAN#1{\xdef\pgfplotsbinaryresult{#1\pgfplotsbinaryresult}}% \def\pgfplotsbinary@apphighorderbytes@LITTLEENDIAN#1{\xdef\pgfplotsbinaryresult{\pgfplotsbinaryresult#1}}% \def\pgfplotsbinaryencode@badic@unsigned@PAD@LITTLEENDIAN{% % pad with zeros: \ifcase\c@pgfplotsbin@byteno % ok. \or % one byte missing. \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO@HIGHEST}% \or % two bytes missing. \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO@HIGHEST}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO@HIGHEST}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO@HIGHEST}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO@HIGHEST}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO@HIGHEST}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO@HIGHEST}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO@HIGHEST}% \else \pgfplots@error{Sorry, I can't process byte no \the\c@pgfplotsbin@byteno... you may need to change bytes=\pgfplotsbinary@bytes.}% \fi }% \def\pgfplotsbinaryencode@badic@unsigned@PAD@BIGENDIAN{% % pad with zeros: \ifcase\c@pgfplotsbin@byteno % ok. \or % one byte missing. \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO@HIGHEST}% \or % two bytes missing. \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO@HIGHEST\pgfplotsbinary@ZERO}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO@HIGHEST\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO@HIGHEST\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO@HIGHEST\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO@HIGHEST\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO@HIGHEST\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO}% \or \pgfplotsbinary@apphighorderbytes{\pgfplotsbinary@ZERO@HIGHEST\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO}% \else \pgfplots@error{Sorry, I can't process byte no \the\c@pgfplotsbin@byteno... you may need to change bytes=\pgfplotsbinary@bytes.}% \fi }% \expandafter\def\csname pgfplotsbinarysetbytes@1\endcsname{% \def\pgfplotsbinary@add@signed@largest@absolute{\advance\c@pgfplotsbin@input by 127 }% \def\pgfplotsbinaryencodesignedmaplinearly@prepare{% % warning: \pgfplotsbinary@bytes is NOT necessarily 1 (ASCII % encoding features) \c@pgfplotsbin@byteno=\pgfplotsbinary@bytes\relax \c@pgfplotsbin@basis=\pgfplotsbinary@basis\relax \divide\c@pgfplotsbin@input by16909320 % ~= (2^31-1) / (2^(8*1-1) -1) }% }% \expandafter\def\csname pgfplotsbinarysetbytes@2\endcsname{% \def\pgfplotsbinary@add@signed@largest@absolute{\advance\c@pgfplotsbin@input by 32767 }% \def\pgfplotsbinaryencodesignedmaplinearly@prepare{% \c@pgfplotsbin@byteno=\pgfplotsbinary@bytes\relax \c@pgfplotsbin@basis=\pgfplotsbinary@basis\relax \divide\c@pgfplotsbin@input by65538 % ~= (2^31-1) / (2^(8*2-1) -1) }% }% \expandafter\def\csname pgfplotsbinarysetbytes@3\endcsname{% \def\pgfplotsbinary@add@signed@largest@absolute{\advance\c@pgfplotsbin@input by 8388607 }% \def\pgfplotsbinaryencodesignedmaplinearly@prepare{% \c@pgfplotsbin@byteno=\pgfplotsbinary@bytes\relax \c@pgfplotsbin@basis=\pgfplotsbinary@basis\relax \divide\c@pgfplotsbin@input by256 % ~= (2^31-1) / (2^(8*3-1) -1) }% }% \expandafter\def\csname pgfplotsbinarysetbytes@4\endcsname{% \def\pgfplotsbinary@add@signed@largest@absolute{% \advance\c@pgfplotsbin@input by 2147483647 % this is the *absolute* largest int that TeX can handle. }% \def\pgfplotsbinaryencodesignedmaplinearly@prepare{% \c@pgfplotsbin@byteno=\pgfplotsbinary@bytes\relax \c@pgfplotsbin@basis=\pgfplotsbinary@basis\relax }% }% \def\pgfplotsbinarysetbytes@@{% \def\pgfplotsbinaryencodesignedmaplinearly@prepare{% \c@pgfplotsbin@byteno=\pgfplotsbinary@bytes\relax \c@pgfplotsbin@basis=\pgfplotsbinary@basis\relax \pgfplots@error{Sorry, but I can't perform \string\pgfplotsbinaryencodesignedmaplinearly\space for bytes=\pgfplotsbinary@bytes\space yet... bytes=4 is the maximum.}% }% \def\pgfplotsbinary@add@signed@largest@absolute{ \advance\c@pgfplotsbin@input by 2147483647 }% }% \expandafter\let\csname pgfplotsbinary@bytes@5\endcsname=\pgfplotsbinarysetbytes@@ \expandafter\let\csname pgfplotsbinary@bytes@6\endcsname=\pgfplotsbinarysetbytes@@ \expandafter\let\csname pgfplotsbinary@bytes@7\endcsname=\pgfplotsbinarysetbytes@@ \expandafter\let\csname pgfplotsbinary@bytes@8\endcsname=\pgfplotsbinarysetbytes@@ \pgfqkeys{/pgfplots/bin}{% % ordering not yet implemented; uses always BIG ENDIAN. ordering/.is choice,% ordering/big endian/.code={% \def\pgfplotsbinary@byteorder{0}% \let\pgfplotsbinary@apphighorderbytes=\pgfplotsbinary@apphighorderbytes@BIGENDIAN \let\pgfplotsbinaryencode@badic@unsigned@PAD=\pgfplotsbinaryencode@badic@unsigned@PAD@BIGENDIAN },% ordering/net/.style={/pgfplots/bin/ordering/big endian},% ordering/little endian/.code={% \def\pgfplotsbinary@byteorder{1}% \let\pgfplotsbinary@apphighorderbytes=\pgfplotsbinary@apphighorderbytes@LITTLEENDIAN \let\pgfplotsbinaryencode@badic@unsigned@PAD=\pgfplotsbinaryencode@badic@unsigned@PAD@LITTLEENDIAN }, ordering/big endian,% % % The standard method - it results in binary encoded numbers. binary encoding/.code={% \pgfutil@IfUndefined{directlua}{% \let\pgfplotscharno=\pgfplotscharno@bincatcode }{% % Ah - we use LuaTeX! % At the time of this writing, LUA does not allow binary output which has been % created by means of catcode modifications & TeX string concatenation. % binary output in LUA needs to be (re)implemented in LUA (see inline code % comments below). % % There are two possible work-arounds: % (a) Base64 encoding % (b) binary encoding using special LUA handling. % This is what I do. Set the 'encode filter' such that it reinitializes the encoder: % we patch \pgfplotscharno with a special routine which collects % only the integer indices: \let\pgfplotscharno=\pgfplotscharno@lualatex % later, the user has to convert this list into a binary lua % string before he can use it. See \pgfplotsbinarytoluabinary }% \edef\pgfplotsbinary@ZERO{\pgfplotscharno0}% \edef\pgfplotsbinary@ZERO@LINEARMAP{\pgfplotscharno{128}}% \let\pgfplotsbinary@ZERO@HIGHEST=\pgfplotsbinary@ZERO \def\pgfplotsbinary@basis{256}% \let\pgfplotsbinary@hook=\relax \def\pgfplotsbinary@hook@signed@linearmap{% \ifnum\c@pgfplotsbin@byteno=0 \advance\c@pgfplotsbin@input by128 \ifnum\c@pgfplotsbin@input>255 \pgfplotsbinary@hook@signed@linearmap@error \fi \fi }% \def\pgfplotsbinarysetbytes##1{% \pgfutil@ifundefined{pgfplotsbinarysetbytes@##1}{% \pgfplots@error{Sorry, I can't write binary output with '##1' bytes yet...}% }{% \edef\pgfplotsbinary@bytes{##1}% \csname pgfplotsbinarysetbytes@##1\endcsname }% }% },% % % This applies 'binary encoding' and encodes the resulting bytes % in Hex. It corresponds to the ASCIIHexEncode in postscript or % pdf. % Please note that 'bytes' sets the number of binary bytes - the % actual encoding length is exactly twice as large. ASCIIHexEncode/.code={% \let\pgfplotscharno=\pgfplotscharno@bincatcode \edef\pgfplotsbinary@ZERO{\pgfplotscharno{48}}% \edef\pgfplotsbinary@ZERO@LINEARMAP{\pgfplotscharno{56}}% \let\pgfplotsbinary@ZERO@HIGHEST=\pgfplotsbinary@ZERO \pgfkeysalso{/pgfplots/bin/ordering/big endian}% \def\pgfplotsbinary@basis{16}% \def\pgfplotsbinary@hook@hex{% \ifnum\c@pgfplotsbin@input<10 \advance\c@pgfplotsbin@input by48 \else \advance\c@pgfplotsbin@input by55 \fi }% \let\pgfplotsbinary@hook=\pgfplotsbinary@hook@hex \def\pgfplotsbinary@hook@signed@linearmap{% \ifnum\c@pgfplotsbin@byteno=0 \advance\c@pgfplotsbin@input by8 \ifnum\c@pgfplotsbin@input>16 \pgfplotsbinary@hook@signed@linearmap@error \fi \fi \pgfplotsbinary@hook@hex }% \def\pgfplotsbinarysetbytes##1{% \pgfutil@ifundefined{pgfplotsbinarysetbytes@##1}{% \pgfplots@error{Sorry, I can't write binary output with '##1' bytes yet...}% }{% \csname pgfplotsbinarysetbytes@##1\endcsname \begingroup \count0=##1\relax \multiply\count0 by2 \xdef\pgfplotsbinary@glob@TMP{\the\count0 }% \endgroup \let\pgfplotsbinary@bytes=\pgfplotsbinary@glob@TMP }% }% },% % % % This applies 'binary encoding' and encodes the resulting bytes % using a base 85 encoding. It corresponds to the ASCII85Encode in postscript or % pdf. % Handle this method with care - it works just for ONE number, not for a stream of % numbers as in pdf. Therefore, it might not be useful at all. % Please note that 'bytes' will be ignored; ASCII85Encode assumes % 4 binary bytes and uses 5 bytes to encode them. % % @ATTENTION bytes is ALWAYS 4, regardless of the setting of % 'bytes'! ASCII85Encode/.code={% \let\pgfplotscharno=\pgfplotscharno@bincatcode \edef\pgfplotsbinary@ZERO{\pgfplotscharno{33}}% \edef\pgfplotsbinary@ZERO@LINEARMAP{\pgfplotscharno{42}}% \let\pgfplotsbinary@ZERO@HIGHEST=\pgfplotsbinary@ZERO \pgfkeysalso{/pgfplots/bin/ordering/big endian}% \edef\pgfplotsbinary@ASCII@specialzero{\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO\pgfplotsbinary@ZERO}% \expandafter\def\expandafter\pgfplotsbinaryencode@badic@unsigned@PAD\expandafter{% \pgfplotsbinaryencode@badic@unsigned@PAD \ifx\pgfplotsbinaryresult\pgfplotsbinary@ASCII@specialzero % PDF standard: 0 is encoded as 'z': \gdef\pgfplotsbinaryresult{z}% \fi }% \def\pgfplotsbinary@basis{85}% \def\pgfplotsbinary@hook{% \advance\c@pgfplotsbin@input by33 }% \def\pgfplotsbinary@hook@signed@linearmap{% \advance\c@pgfplotsbin@input by33 \ifnum\c@pgfplotsbin@byteno=0 \advance\c@pgfplotsbin@input by42 \ifnum\c@pgfplotsbin@input>85 \pgfplotsbinary@hook@signed@linearmap@error \fi \fi }% % I know, that does only work efficiently if bytes=4 for every % encoded number. \def\pgfplotsbinarysetbytes##1{% \def\pgfplotsbinary@bytes{5}% \csname pgfplotsbinarysetbytes@4\endcsname }% \pgfplotsbinarysetbytes4% },% binary encoding,% % bytes/.code={\pgfplotsbinarysetbytes{#1}},% bytes=4, % % Irreversibly change to VERBATIM output for debugging: debug mode/.code={% \let\pgfplotsbinary@apphighorderbytes@ORIG=\pgfplotsbinary@apphighorderbytes \def\pgfplotsbinary@ZERO{[Pad-0]}% \let\pgfplotsbinary@ZERO@HIGHEST=\pgfplotsbinary@ZERO \def\pgfplotsbinary@ZERO@LINEARMAP{[Pad-128]}% \def\pgfplotsbinary@apphighorderbytes##1{% \pgfutil@ifnextchar\pgfplotscharno{% \pgfplotsbinary@apphighorderbytes@DEBUG@csname }{% \pgfplotsbinary@apphighorderbytes@DEBUG@normal }% ##1\relax }% },% % Write pdf objects in binary form. This does only work with % pdftex, and its output is only useful in conjunction with % \pdfcompresslevel=0 % and a text editor. % Usage: % \pgfkeys{/pgfplots/bin/debug to pdf={\pgfplotsbinaryencodeunsigned}{1,2,3,...,16}} % % works only with pdftex debug to pdf/.code 2 args={% \foreach \num in {#2} {% #1{\num}% \immediate \pdfobj stream attr { /Decimal \num\space /Routine (\string#1) } {% \pgfplotsbinaryresult }% }% },% } \def\pgfplotsbinary@hook@signed@linearmap@error{% \pgfplots@error{Sorry, there are not enough bytes to store the current number. I tried to write \the\c@pgfplotsbin@input...}% }% \def\pgfplotsbinary@apphighorderbytes@DEBUG@csname\pgfplotscharno#1\relax{% \pgfplotsbinary@apphighorderbytes@ORIG{[#1]}% }% \def\pgfplotsbinary@apphighorderbytes@DEBUG@normal#1\relax{% \pgfplotsbinary@apphighorderbytes@ORIG{#1}% }% %\pgfkeys{/pgfplots/bin/debug mode} \countdef\c@pgfplotsbin@input=0 \countdef\c@pgfplotsbin@tmpa=1 \countdef\c@pgfplotsbin@tmpb=2 \countdef\c@pgfplotsbin@byteno=3 \countdef\c@pgfplotsbin@basis=4 \def\pgfplotsbinaryempty{} %-------------------------------------------------- % input: unsigned int x, b, n; % output: unsigned int y[n]; % for (i=0; i 0) % { y[i] = x % b; /* entspricht x mod b */ % x = x / b; /* ganzzahlige Division */ % i++; % } %-------------------------------------------------- % with x = #1 % b = basis % will store stuff into \pgfplotsbinaryresult in binary format % % PRECONDITION: % - \pgfplotsbinaryresult= empty! % - \c@pgfplotsbin@byteno=\pgfplotsbinary@bytes \def\pgfplotsbinaryencode@badic@unsigned@{% \ifnum\c@pgfplotsbin@input>0 \c@pgfplotsbin@tmpa=\c@pgfplotsbin@input \divide\c@pgfplotsbin@tmpa by\c@pgfplotsbin@basis\relax \c@pgfplotsbin@tmpb=\c@pgfplotsbin@tmpa\relax \multiply\c@pgfplotsbin@tmpa by\c@pgfplotsbin@basis\relax \advance\c@pgfplotsbin@input by -\c@pgfplotsbin@tmpa\relax \advance\c@pgfplotsbin@byteno by-1 \pgfplotsbinary@hook% hooks for modifications. \pgfplotsbinary@apphighorderbytes{\pgfplotscharno{\the\c@pgfplotsbin@input}}% \c@pgfplotsbin@input=\c@pgfplotsbin@tmpb %\message{RESULT SO FAR byte no \the\c@pgfplotsbin@byteno: \pgfplotsbinaryresult}% \expandafter\pgfplotsbinaryencode@badic@unsigned@ \else \pgfplotsbinaryencode@badic@unsigned@PAD %\message{RESULT SO FAR byte no \the\c@pgfplotsbin@byteno: \pgfplotsbinaryresult}% \fi }% % Defines \pgfplotsbinaryresult to be the binary representation of an % unsigned integer. % % The representation will use unsigned dual number representation. % % The assignment to \pgfplotsbinaryresult will be globally. % #1: an unsigned integer. It won't be transformed in any way, so make % sure it fits into the configured number of bytes. It is an error if % the number is too large or too small. Please note that only unsigned % numbers are supported with this method. % % FIXME : fix > 2^30 \def\pgfplotsbinaryencodeunsigned#1{% \begingroup \global\let\pgfplotsbinaryresult=\pgfplotsbinaryempty \c@pgfplotsbin@input=#1 % \c@pgfplotsbin@byteno=\pgfplotsbinary@bytes\relax \c@pgfplotsbin@basis=\pgfplotsbinary@basis\relax \pgfplotsbinaryencode@badic@unsigned@% \endgroup }% % An implementation for signed integers which maps the signed integer linearly into % the unsigned data range before it proceeds. % % The idea is thus, to first introduce a linear mapping % % phi : [- smallest_possible, +largest_possible ] -> [0, 256^bytes-1 ] % % A signed integer in TeX is in [ - (2^31-1), 2^31-1 ]. % Thus, we should map % % phi : [ -(2^31-1), 2^31-1 ] -> [ 0, 2^32-1 ]. % % A simpler case is to employ the symmetry in TeX's registers and % leave one out, i.e. to map to 2^32-2: % % phi : [ -(2^31-1), 2^31-1 ] -> [ 0, 2^32-2 ]. % % Then, % % phi(x) = ( x + 2^31 -1 ) / (2^31-1 + 2^31-1) * (2^32-2) = x+ 2^31-1. % % The same map phi(x) = x + 2^31 -1 with target space [0, 2^32-1 ] % could be realized with the input space [- (2^31-1), 2^31 ]. % % I am using this encoding procedure, phi(x) = x + 2^31 -1. % % As a consequence, the binary pattern FF FF FF FF does never occur as % result of the mapping. % % To invert the mapping (i.e. to decode the result), set up the unique % linear map % % psi : [ 0, 2^32-1 ] -> [ -(2^31-1), 2^31 ]. % % Then, psi( phi(x) ) = x and the decoding procedure is correct. % % This doesn't need TeX register arithmetics on the whole range. % % REMARK: the whole operation does also work if bytes<4 (i.e. we have % less than 32 bits in the target range). In this case, the mapping is % phi : [ -(2^31-1), 2^31-1 ] -> [ 0, 2^{8*bytes}-1 ] % and a further, *lossy* quantization still will be applied. The % quantization step is an integer division performed in signed number % arithmetics (i.e. it is symmetric around 0). \def\pgfplotsbinaryencodesignedmaplinearly#1{% \begingroup \global\let\pgfplotsbinaryresult=\pgfplotsbinaryempty \c@pgfplotsbin@input=#1\relax% \pgfplotsbinaryencodesignedmaplinearly@prepare \ifnum\c@pgfplotsbin@input<0 % % compute + 2^31 - 1 \pgfplotsbinary@add@signed@largest@absolute \else % change zero padding such that positive numbers % get the EFFECT of + 2^31. \let\pgfplotsbinary@ZERO@HIGHEST=\pgfplotsbinary@ZERO@LINEARMAP \let\pgfplotsbinary@hook=\pgfplotsbinary@hook@signed@linearmap % and compute the -1 explicitly here: \advance\c@pgfplotsbin@input by-1 % \fi \pgfplotsbinaryencode@badic@unsigned@% \endgroup }% % Encodes a dimen (like 1pt or \dimen0) in binary form. % % The encoding works by mapping #1 linearly into the allowed integer % range using a quantization technique to respect the (possibly) % restricted number of bytes. % % The implementation is fast and uses only integer arithmetics. % It relies on \pgfplotsbinaryencodesignedmaplinearly and a scale. % % So, what we do is to setup a linear map into binary range with k % bytes. The range of a TeX dimen is precisely (in units of pt) % [ -(2^30-1) / 2^16, (2^30 -1) / 2^16 ] = [-16383.99998, 16383.99998] % % Thus, for an input dimen x, we set up the mapping % phi(x) = 2^16 * x * 2 % which maps % phi: [ -(2^30-1) / 2^16, (2^30-1) / 2^16 ] -> [-(2^31 -2), 2^31-2]. % % I simply use the \pgfplotsbinaryencodesignedmaplinearly to process % this further. To simplify the computation, I simply compute % phi_signed( phi(x) ), % where phi_signed denotes an application of % \pgfplotsbinaryencodesignedmaplinearly: % phi_signed( y ) = y +2^31 -1, % phi_signed( phi(x) ) = 2^16 * 2 * x + 2^31 - 1. % This is NOT a linear map to [0,2^32-1] as promised. % But, we can setup an inverse transformation PHI (which is linear) anyway % such that % PHI( phi_signed(phi(x)) ) = x % and that's all I want. Do do that, we use the unique linear decoder map % PHI : [ 0,2^32-1 ] -> [ -16383.999992, 16384 ]. % % This is not exacty the input range of before, but using it results % in a proper decoder. The difference is due to the non-unique zero % representation in TeX's arithmetics. % % % REMARK: the whole operation does also work if bytes<4 (i.e. we have % less than 32 bits in the target range). In this case, a further % *lossy* quantization step is applied in phi_signed. The inverse % transformations are the same, however. See % \pgfplotsbinaryencodesignedmaplinearly for details about the % quantization step (or try it out). % % %% DEBUG NOTE: This mapping appears to work correctly according to %% my tests. %% For bc -l test codes: %% ibase=16; %% -4000 + 809658FA. / (2^20) * 8000 \def\pgfplotsbinaryencodedimenmaplinearly#1{% \begingroup \dimen0=#1\relax \c@pgfplotsbin@input=\dimen0 \multiply\c@pgfplotsbin@input by2 %\message{LOWLEVEL ENCODING '\the\c@pgfplotsbin@input' with linear map}% \pgfplotsbinaryencodesignedmaplinearly\c@pgfplotsbin@input \endgroup }% \catcode`\@=\pgfplotsbinaryatcode \endinput