30

I'd like to create a bitmap (black and white) from within LuaTeX (or pdfTeX) and rescale it afterwards. For example (a 4x4 bitmap) could be made by

\makebitmap{0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0}

I don't really care about the interface. More important for me is the overall approach.

I would like to use it in LuaTeX, thus img.stream could be useful for me. But a PDFTeX approach with \pdf... commands would be fine, too.

Important restrictions: I must not create any intermediate file and it must work offline.

To make things clear: I am only interested in how to generate a bitmap graphics (png, bmp, whatever) within pdf/LuaTeX.

Background: I've developed a qrcode encoding lua library and I'd like make a LuaLaTeX package for it. I see three possible approaches:

  1. Use pdf instructions (0 0 10 10 re f for example)
  2. Use \rule commands to make the black parts
  3. Create a bitmap "file" and scale it.

I still experiment about the best approach.

I have tried with pdf instructions (item 1 above), and the result is ugly in some pdf viewer applications:

sample qrcode

The black boxes are divided by some small white lines in some zoom settings. I want to avoid them. That is why I want to create bitmaps instead of pdf instructions.

22
  • Perhaps you could be a bit more specific about a 'bitmap file'. Your suggested approaches seem to target a PDF file that looks like a bitmap, rather than a .bmp (or .png or ...): exactly what format do you require?
    – Joseph Wright
    Dec 30, 2012 at 12:48
  • 1
    @JosephWright I don't care about the exact format. I just want to have black & white pixels instead of pdf instructions. I'll enhance my question on why this important to me.
    – topskip
    Dec 30, 2012 at 14:55
  • 1
    @toskip Fine, Lua is the hammer. Please remember that tthere are some well-known disadvantages to using bitmap files. LaTeX has many packages that can create vector graphics on the fly.
    – user10274
    Dec 31, 2012 at 3:03
  • 2
    See tex.stackexchange.com/questions/85620/…. If you catcode 0 and 1 to draw white and black rectangles, and catcode some character of your choice to stack things vertically, I think that should work?
    – Mohan
    Jan 2, 2013 at 17:22
  • 2
    MetaPost recently grown the ability to output PNG (besides the existing EPS and SVG), so you probably would be able to use embedded mplib in LuaTeX to generate bitmaps with next TeX Live release :) Jan 3, 2013 at 15:41

3 Answers 3

13
+500

For this you need to create and add a PDF object (using \pdfobj I guess; see the pdftex manual) into the PDF which holds the (binary?) representation of the image and then reference this object where you like the image being shown. This is what \includegraphics does for PDF output.

Accroding to he PDF reference (31MB!), section 3.3.6 JBIG2Decode Filter the JBIG2 format was especially created for monochrome images like this. The best thing here is that it object stream can be given in ASCII, avoiding the need to handle binary material in TeX.

The following example is given there. I don't think there should be an issue adding this to a PDF using \pdfobj. You "only" need to produce the JBIG2 encoding of your image, which should be possible using Lua.

5 0 obj
<< /Type /XObject
/Subtype /Image
/Width 52
/Height 66
/ColorSpace /DeviceGray
/BitsPerComponent 1
/Length 224
/Filter [ /ASCIIHexDecode /JBIG2Decode ]
/DecodeParms [ null << /JBIG2Globals 6 0 R >> ]
>>
stream
000000013000010000001300000034000000420000000000
00000040000000000002062000010000001e000000340000
004200000000000000000200100000000231db51ce51ffac >
endstream
endobj
6 0 obj
<< /Length 126
/Filter /ASCIIHexDecode
>>
stream
0000000000010000000032000003fffdff02fefefe000000
01000000012ae225aea9a5a538b4d9999c5c8e56ef0f872
7f2b53d4e37ef795cc5506dffac >
endstream
endobj

I will try to create a LaTeX example file showing the principle.

So far I only figured out how to create the objects, but not how to display the image in the document.

\documentclass{article}

\pdfcompresslevel=0
\pdfobjcompresslevel=0

\begin{document}

\leavevmode\fbox{%

\pdfobj stream attr 
{
/Filter /ASCIIHexDecode
} {
0000000000010000000032000003fffdff02fefefe000000
01000000012ae225aea9a5a538b4d9999c5c8e56ef0f872
7f2b53d4e37ef795cc5506dffac
}%
%\pdfrefobj\pdflastobj
\pdfobj stream attr {
    /Type /XObject
/Subtype /Image
/Width 52
/Height 66
/ColorSpace /DeviceGray
/BitsPerComponent 1
%/Length 224
/Filter [ /ASCIIHexDecode /JBIG2Decode ]
/DecodeParms [ null << /JBIG2Globals \the\pdflastobj\space 0 R >> ]
} {
000000013000010000001300000034000000420000000000
00000040000000000002062000010000001e000000340000
004200000000000000000200100000000231db51ce51ffac
}%
\pdfrefobj\pdflastobj
}

\end{document}
1
  • It would be very cool if this can be handled via de pgf interface. For example it comes to my mind that pgfplots could use this to generate colormap plots, which usually produces very large vector graphics PDFs.
    – alfC
    Jan 7, 2013 at 21:57
24

I created simple visualizer module for luaqrcode:

module(...,package.seeall)
qrcodelib = dofile("qrencode.lua")
local function black_box(w,h)
  return "\\vrule width "..w.." height "..h
end
local function white_box(w,h)
  return "\\hskip "..w
end
function generate_matrix2(s,w,h)
  local ok, tab_or_message = qrcodelib.qrcode(s)
  local buffer = {}
  local write_nl = function(text)
    table.insert(buffer,text)
  end
  if not ok then
    print(tab_or_message)
  else
    write_nl("\\bgroup")
    --write_nl("\\vbox\\bgroup%")
    write_nl("\\baselineskip="..h)
    local x = #tab_or_message[1]
    local y = #tab_or_message
    for i = 1, x, 1 do
      local boxes = {}
      for n = 1, y, 1 do
        local p = tab_or_message[n][i] > 0  and black_box(w,h) or white_box(w,h)
        table.insert(boxes,p)
      end
      write_nl("\\hbox{"..table.concat(boxes).."}")
    end
    write_nl("\\egroup")
  end
  return table.concat(buffer,"")
end

And simple LaTeX interface and sample document:

\documentclass{article}
\usepackage{luacode}
\luaexec{qrcode = require("sample")}
\newcommand\qrcode[1]{%
  \vbox{
  \directlua{%
    tex.print(qrcode.generate_matrix2("\luatexluaescapestring{#1}","3pt","3pt"))
  }
  }
}
\begin{document}
Now generate some qrcodes:\\
\qrcode{Prilis zlutoucky kun upel dabelske ody}
\qrcode{Příliš žluťoučký kůň úpěl ďábelské ódy}
\qrcode{Helloworld}        
\end{document}

With this result: enter image description here

3
  • While I really like your approach (+1), it does not answer my question...
    – topskip
    Dec 30, 2012 at 20:11
  • 1
    I see small lines between adjoining squares (a bit depending on the zoom in the pdf viewer) which I don't see if I create qrcodes with pst-barcode. Do you have an idea how to avoid them? Aug 23, 2013 at 11:39
  • @UlrikeFischer You found out what triggers those lines? May 27, 2022 at 11:55
8

I don't know if this is what you want:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\makebitmap}{O{4} m}
 {
  \topskip_make_bitmap:nn { #1 } { #2 }
 }

\cs_new_protected:Npn \topskip_make_bitmap:nn #1 #2
 {
  \tl_set:Nn \l__topskip_input_tl { #2 }
  \tl_remove_all:Nn \l__topskip_input_tl { ~ }
  \int_zero:N \l__topskip_cycle_int
  \tl_clear:N \l__topskip_bitmap_tl
  \tl_map_inline:Nn \l__topskip_input_tl
   {
    \int_incr:N \l__topskip_cycle_int
    \tl_put_right:Nx \l__topskip_bitmap_tl
     {
      \str_case:nnn { ##1 }
       {
        { 0 } { \topskip_zero: }
        { 1 } { \topskip_one:  }
       }
       { \topskip_error: }
      \int_compare:nTF { \l__topskip_cycle_int = #1 } { \cr } { & }
     }
    \int_compare:nT { \l__topskip_cycle_int = #1 } { \int_zero:N \l__topskip_cycle_int }
   }
  \vbox
   {
    \offinterlineskip
    \halign{&##\cr\l__topskip_bitmap_tl\crcr}}
 }
\cs_new_protected:Npn \topskip_zero:
 { \vrule height 3pt width 0pt\kern 3pt }
\cs_new_protected:Npn \topskip_one:
 { \vrule height 3pt width 3pt depth 0pt }

\int_new:N \l__topskip_cycle_int
\seq_new:N \l__topskip_bitmap_seq
\tl_new:N \l__topskip_bitmap_tl

\ExplSyntaxOff
\begin{document}
\fbox{\makebitmap{0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0}}
\fbox{\makebitmap{1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1}}
\fbox{\makebitmap[16]{
  1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1
  0 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0
  1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1
  0 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0
}}
\end{document}

enter image description here

4
  • I need to have a closer look, but AFAICS this also creates pdf instructions and not a bitmap file.
    – topskip
    Jan 1, 2013 at 18:21
  • @topskip I don't understand what you mean by "creating a bitmap file".
    – egreg
    Jan 1, 2013 at 18:27
  • 1
    I want to do the same as \includegraphics{foo.png} just without a file on the disk. That is: I have a byte stream and I want to put this into the PDF so that the PDF viewer interprets this as a png file.
    – topskip
    Jan 1, 2013 at 19:16
  • 3
    @topskip: Ah. Then you will have to somehow create a bitmap of an image (say a jpeg or png) in the right byte format for PDF and create a PDF object out of that on the fly. It's probably easier to use lua to create a bitmap file and let LuaTeX include that. Using the already compiled-in libpng for bitmap creation will probably need an extension of LuaTeX as the needed functions are most likely not exposed. Jan 1, 2013 at 19:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .