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.

topskip
  • 37,020
  • 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 '12 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 '12 at 14:55
  • You could also consider using TikZ. This approach would have the advantage that the package can also be used by non-LuaTeX users. –  Dec 30 '12 at 18:49
  • @MarcvanDongen this package would be based on a Lua function, so its Lua(La)TeX only. – topskip Dec 30 '12 at 19:09
  • PStricks provides pst-barcode that creates a whole host of bar-code families. – Werner Dec 30 '12 at 19:38
  • This question is not about generating barcodes! – topskip Dec 30 '12 at 20:01
  • 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. –  Dec 31 '12 at 03:03
  • @MarcvanDongen I don't see any disadvantage on using a bitmap file for the given purpose!?!?! – topskip Dec 31 '12 at 11:35
  • I would make a 21x21 (for the version 1 qr code) pixel bitmap and scale it to the requested size. – topskip Dec 31 '12 at 11:43
  • @topskip Even though the graphic consists of squares only, it may not render nicely after scaling. –  Dec 31 '12 at 13:13
  • Maybe relevant: http://stackoverflow.com/questions/11004868/creating-a-bmp-file-bitmap-in-c – Scott H. Jan 01 '13 at 19:02
  • 2
    See http://tex.stackexchange.com/questions/85620/whats-the-best-way-to-draw-a-square-or-rectangle-with-specified-dimensions. 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 02 '13 at 17:22
  • @Mohan The interface is not important to me. The linked answer creates PDF instructions/operators (re, s, ..) and I want to avoid these. – topskip Jan 03 '13 at 06:33
  • Ah, sorry. In the picture you've attached, I can only see vertical white lines, not horizontal white lines. If that's the case, you can get round it by drawing 1 box of width three rather than three boxes of width 1? (So, every time you see a '1', increment a counter w; then when you see a '0', immediately draw a box of width w and set w=0.) – Mohan Jan 03 '13 at 08:49
  • 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 03 '13 at 15:41
  • Would this http://tex.stackexchange.com/questions/86488/create-square-and-custom-size-cells-in-a-table-using-pgfplotstable/86849#86849 be helpful? It uses a pgfplotstable to define the pixel gray shade. – guillem Jan 07 '13 at 10:23
  • Just to be sure: You want a bitmap file (like one included with \includegraphics{image.png}) inside a LaTeX PDF document. You don't want to create an external image file, right? Because PDF only supports JPEG and PNG but not BMP I think you might need to go with internal produced PNG, which might be very difficult for TeX. – Martin Scharrer Jan 07 '13 at 16:37
  • @MartinScharrer Yes, png would be fine. Otherwise its exactly what I would like to have. – topskip Jan 07 '13 at 16:46
  • @topskip: It might be possible to create a binary PNG stream and place it into PDF as an PDF object. However doing so solely in TeX without any external file is overkill! It would be easier to generate an ASCII image file (like XPM) and convert it to PNG using an external tool, then include it as normal in your LaTeX document. – Martin Scharrer Jan 07 '13 at 16:56
  • @MartinScharrer in my case it would not be overkill at all :) Assume that I already have the byte string for the PNG, now I'd like to display that byte string/png. – topskip Jan 07 '13 at 17:06
  • For the concrete issue, the package qrcode was created. Source: https://tex.stackexchange.com/q/89649/9075 – koppor Jan 28 '18 at 22:05
  • See also https://tex.stackexchange.com/questions/157080/can-tikz-create-pixel-art-images for Pixel Art images – Steven B. Segletes Apr 30 '18 at 17:16

3 Answers3

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

David Carlisle
  • 757,742
michal.h21
  • 50,697
13

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}
Martin Scharrer
  • 262,582
  • 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 07 '13 at 21:57
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

egreg
  • 1,121,712
  • I need to have a closer look, but AFAICS this also creates pdf instructions and not a bitmap file. – topskip Jan 01 '13 at 18:21
  • @topskip I don't understand what you mean by "creating a bitmap file". – egreg Jan 01 '13 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 01 '13 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. – Martin Schröder Jan 01 '13 at 19:26