创建“年鉴风格”的多页照片布局

创建“年鉴风格”的多页照片布局

我想用 LaTeX 创建“年鉴风格”的照片布局。每张照片都会有一个标题,目标是自动布局不同大小的矩形照片,以尽量减少页面上的空白(每张照片和标题周围都有强制性边距)。如果我也可以用浏览器做到这一点,那也会很有帮助,但这是另一个论坛的问题。我原本以为这个问题可以通过某种开源软件包得到解决,但我没有找到。

在此处输入图片描述

二维包装算法综述

答案1

这不是对这个问题的完整回答,而是我对生成布局的想法的展示luatex。我认为以下任何示例都没有用,但也许可以作为未来更有趣的解决方案的基础,也许是这样的

我的想法如下:我们有 LaTeX 命令,将其内容存储在一个盒子中,然后将列表 ID 和尺寸添加到列表中。

\ProvidesPackage{generativelayout}
\RequirePackage{luacode}

\luaexec{%
generators = require('generativelayout')
genboxes = {}
curr_box_id =  2222
function findFreeBox(id)
  if type(tex.box[id]) == 'nil' then
    return id
  else
    return findFreeBox(id + 1)
  end
end
gen = generators.getGenerator("default")
}

\newcommand\gensavebox[1]{%
\setbox0=\hbox{\fbox{#1}}
\luaexec{%
local box = tex.box[0] 
curr_box_id= findFreeBox(curr_box_id)
tex.setbox('global',curr_box_id, node.copy_list(box))
table.insert(genboxes,{width=box.width / 65536 ,height=(box.height / 65536 + box.depth / 65536),box=curr_box_id})
curr_box_id = curr_box_id + 1
}
%\box0
}

接下来我们有genlayout选择布局算法的环境并在框列表上运行它:

\newenvironment{genlayout}[1][]{%
\luaexec{%
local gen_name = "\luatexluaescapestring{#1}" 
if gen_name == "" then gen_name = "default" end
gen = generators.getGenerator(gen_name)
gen:init()
}
}{%
\luaexec{%
gen:run(genboxes)
}
}

这个包可以这样使用:

\documentclass{article}
\usepackage{lmodern,generativelayout}
\begin{document}
\pagestyle{empty}
\begin{genlayout}[]
\gensavebox{%
Hello world
}
\gensavebox{%
\begin{tabular}{l l}
hello & world\\
second & line\\
\end{tabular}
}
\gensavebox{%
\begin{minipage}{.3\textwidth}
\begin{itemize}
\item First
\item Second
\end{itemize}
\end{minipage}
}
\gensavebox{%
little bit smaller box
}
\gensavebox{totaly small box}
\gensavebox{azsvm}
\end{genlayout}

\end{document}

现在lua库generativelayout.lua

module(...,package.seeall)

generators = {}
empty_generator = {init = function() end, run = function() end}

function getGenerator(name)
  return generators[name] or empty_generator
end

printBox = function(self,box_number)
  tex.print('\\fbox{\\copy'..box_number.."}")
end    

generators.default = {
  init = empty_generator.init,
  printer = printBox,
  run = function(self,boxes)
    for k, v in pairs(boxes) do
       self:printer(v.box)
    end
  end 
}

每个生成器都以对象的形式添加,并带有方法 run 和 init,这两个方法由genlayout环境调用。生成器可以使用可选参数 进行选择genlayout,如果为空,则default选择 。输出如下:

在此处输入图片描述

我们可以对这些框进行排序:

generators.bigToSmall = {
  init = generators.default.init,
  printer = printBox,
  run = function(self,boxes)
    table.sort(boxes,function(a, b) return a.height > b.height end)
    generators.default.run(self,boxes)
  end
}

您可以使用其他生成器的函数,例如generators.default.run(self,boxes) 在此处输入图片描述

将框放置在页面随机位置的更多有趣示例:

generators.randomize = {
  width = 150,
  height = 150,
  init = generators.default.init,
  printer = function(self,box,x,y) 
    tex.print("\\put(",x,",",y,"){\\copy",box,"}")
  end,
  run = function(self,boxes)
    tex.print("\\setlength\\unitlength{1pt}")
    tex.print("\\begin{picture}("..self.width..","..self.height..")")
    math.randomseed( os.time() )
    for k,v in pairs(boxes) do
      local x = math.random(self.width - v.width) 
      local y = math.random(self.height - v.height)
      self:printer(v.box,x,y)
    end  
    tex.print("\\end{picture}")
  end
}

在这里我们使用picture环境技巧将事物放置在页面上的准确位置 在此处输入图片描述

最后,我的端口http://codeincomplete.com/posts/2011/5/7/bin_packing/到 lua:

generators.binPack = {
  root = {},
  init = function(self) self.root = {x=0,y=0,w=280,h=250} end,
  printer = generators.randomize.printer,
  fit = function(self,boxes)
    local node
    for _,block in ipairs(boxes) do
        print("Velikost boxu",block.width,block.height)
        node = self:findNode(self.root, block.width,block.height)
        if node then
          block.fit = self:splitNode(node, block.width, block.height)
          end
    end
  end,
  findNode = function(self,root,w,h)
     if root.used then
       local right = self:findNode(root.right,w,h)
       if right then 
         return right 
       else 
         return  self:findNode(root.down,w,h)
      end
     elseif w <= root.w and h <= root.h then
       return root 
     else 
       return nil
     end  
  end,
  splitNode = function (self,node,w,h)
     print("Split box: ",node.x,node.y,node.w,node.h,w,h)
     node.used = true
     node.down  = { x= node.x,     y= node.y + h, w= node.w,     h= node.h - h }
     node.right = { x= node.x + w, y= node.y,     w= node.w - w, h= h}
     return node
  end,
  run = function(self,boxes)
    --generators.randomize.run(self,boxes)
    table.sort(boxes,function(a, b) return a.height > b.height end)
    tex.print("\\setlength\\unitlength{1pt}")
    tex.print("\\begin{picture}("..self.root.w..","..self.root.h..")")
    self:fit(boxes)
    for _,v in ipairs(boxes) do
      if v.fit then
        x= v.fit.x  
        y= self.root.h-v.fit.y  
        self:printer(v.box,x,y)
      end
    end
    tex.print("\\end{picture}")
  end
}

我认为结果并不是很好,并且我认为将盒子放置在其准确位置存在一些错误,但也许有人会喜欢它:

在此处输入图片描述

相关内容