我不知道如何打乱切片图像的以下网格。如何在 (La)TeX 或 PostScript 级别执行此操作?
\documentclass[pstricks,border=12pt]{standalone}
\usepackage{multido}
\usepackage{graphicx}
\def\Columns{5}% columns
\def\Rows{5}% rows
\def\Filename{ParisHilton}
\def\Scale{1}
\newsavebox\IBox
\savebox\IBox{\includegraphics[scale=\Scale]{\Filename}}
\psset
{
xunit=\dimexpr\wd\IBox/\Columns,
yunit=\dimexpr\ht\IBox/\Rows,
}
\SpecialCoor
\begin{document}
\multido{\ny=\Rows+-1}{\Rows}
{
\multido{\nx=0+1}{\Columns}
{
\pspicture(\Columns,\Rows)
\psclip{\psframe[linestyle=none,linewidth=0pt](!\nx\space \ny\space 1 sub)(!\nx\space 1 add \ny)}
\rput[bl](0,0){\usebox\IBox}
\endpsclip
\endpspicture
}
}
\end{document}
这里是图片我在此答案中使用它作为演示图片。
答案1
\documentclass[pstricks]{standalone}
\usepackage{multido}
\usepackage{graphicx}
\def\txG{ true setglobal globaldict begin }
\def\etxG{ end false setglobal }
\def\Columns{4} \def\Rows{5}
\pstFPmul\MaxElements{\Columns}{\Rows}
\pstVerb{\txG
/u.n \Columns\space \Rows\space mul def
/Elements [ 0 1 u.n 1 sub { } for ] def
realtime srand
/GetElement {
rand u.n mod /Random ED
Random
Elements length mod Elements exch get dup
5 mod /u.Col ED % col
5 div cvi /u.Row ED % row
Elements aload length dup 1 sub /u.n ED
Random sub -1 roll pop u.n array astore /Elements ED
} def
\etxG }
\newsavebox\IBox
\savebox\IBox{\includegraphics{dante22}}
\psset{xunit=\dimexpr\wd\IBox/\Columns, yunit=\dimexpr\ht\IBox/\Rows}
\SpecialCoor
\begin{document}
\multido{\iA=1+1}{\MaxElements}{%
\begin{pspicture}(\Columns,\Rows)
\rput[lb](!0 0){%
\psclip{\psframe[linestyle=none]%
(! \txG GetElement u.Row u.Col \etxG)
(! \txG u.Row 1 add u.Col 1 add \etxG)} \usebox\IBox
\endpsclip}
\end{pspicture}}%
\end{document}
答案2
这是一个基于 LuaTeX/ConTeXt 的简单解决方案。
\shuffle[nx=..., ny=...]{<box>}
其中,nx
是您想要的水平切片数,而 my 是您想要的垂直切片数。该宏基于\setupclipping
并执行实际的裁剪图像的艰苦工作。此宏有效生成:
\clip[nx=...,ny=...,x=...,y=...]{<box>}
通过随机改变所有可能值的x
和y
。为了生成这样的x
和y
,我只需生成所有可能值并打乱结果即可。据我所知,Lua 没有打乱函数,因此我基于标准 Fisher Yates 算法实现了一个。
这是结果\shuffle[nx=3,ny=2]{\externalfigure[hacker]}
(黑客是随 ConTeXt 分发的示例图像之一)。
最后,宏:
\startluacode
local random = math.random
local insert = table.insert
local format = string.format
-- Note that ConTeXt stores the value of the random seed
-- in the tuc file to ensure that you get the random numbers
-- don't change across runs. If you want a different set of random
-- numbers just delete the tuc file and compile again
-- A function to shuffle the contents of a table
local function shuffle_table(data)
-- implementation of Fisher Yates shuffle
local t
for i=#data,1,-1 do
local j = random(1,i)
-- Swap i and j location
t = data[i]
data[i] = data[j]
data[j] = t
end
return data
end
local function shuffle_box(nx, ny, box)
-- Generate table of all possible indices
local indices = {}
for i=1,nx do
for j=1,ny do
insert(indices, {i,j})
end
end
indices = shuffle_table(indices)
-- table.print(indices)
local x, y, settings
context("\\vbox\\bgroup")
context("\\baselineskip\\zeropoint \\lineskip\\zeropoint")
for i = 1,nx do
context("\\hbox\\bgroup") -- This can be frame for more control
for j=1,ny do
x, y = indices[(i-1)*nx+j][2], indices[(i-1)*nx+j][2]
settings = format("nx=%d, ny=%d, x=%d, y=%d", nx, ny, x, y)
-- print(settings)
context.clip({settings}, box)
end
context("\\egroup")
end
context("\\egroup")
end
commands.shuffle = shuffle_box
\stopluacode
\unprotect
\unexpanded\def\shuffle
{\dosingleargument\shuffle_indeed}
\def\????shuffle{@@@@shuffle}
\def\shuffle_indeed[#1]#2% #2 should be some boxed material
{\getparameters[\????shuffle][\c!nx=4,\c!ny=4,#1]%
\ctxcommand{shuffle(\@@@@shufflenx, \@@@@shuffleny, \!!bs #2 \!!es)}}
\starttext
\shuffle[nx=3,ny=3]{\externalfigure[cow]}
\stoptext
答案3
这是另一个。代码有点乱,所以我将输出分开:
首先我需要获取一个随机列表,我首先声明一个常规递增数字列表。然后我从中挑选一个数字并将其放入新列表中。同时,我从旧列表中删除该数字并重复此操作,直到用完所有数字。
所以输出看起来像这样
拾取的号码切换到我们右侧的新列表(然后我们删除初始逗号)。
然后(计为 11-> 8+3 第二行,第三列)我们从列表中获取随机数,转换为单元格坐标,并根据我们著名的 Paulo Cereda 在关于 Sprite Sheet 的博客文章。我选择了 4 x 4 网格,但可以更改。另请注意,底层坐标系已缩放以匹配图像的宽度和高度。
我使用过巴黎希尔顿酒店,图片来自他们的网站,因为我受不了那些名人。所以输出是
代码
(正如 Peter Grill 所做的那样)
\documentclass{article}
\usepackage{tikz,xstring}
% Declare the image
\pgfdeclareimage[interpolate=true,width=8cm,height=5cm]{hotel}{hiltonparis.jpg}
\def\mylist{}
\def\myrandlist{}
\foreach \x in {1,...,16}{ %Generate list
\xdef\mylist{\mylist\noexpand{\x\noexpand}}
}
\begin{document}
\pgfmathdeclarerandomlist{mynum}{\mylist} %Define the list
\foreach \x in {1,...,16}{
\pgfmathrandomitem{\mynum}{mynum} % Pick one from that list
\xdef\myrandlist{\myrandlist,\mynum} % place in the new list
\StrSubstitute{\mylist}{{\mynum}}{}[\sublist] % Delete that entry from the list
\global\let\mylist\sublist % Update the main list
\pgfmathdeclarerandomlist{mynum}{\mylist} % Redefine the list
\mylist\hfill \myrandlist%Let's see if we succeeded removing duplicates. Remove later
}
% Remove the first comma
\StrGobbleLeft{\myrandlist}{1}[\myrandlist]
\xdef\myrandlist{{\myrandlist}} % After all, it's a stupid shuffle
\pgfuseimage{hotel}
\vspace{1cm}
\begin{tikzpicture}[xscale=2,yscale=1.25, %Scaling according to the image
path image/.style args={#1 shifted #2 and #3}{%
path picture={
\node[anchor=north west,outer sep=0]
at ([shift={(-#2,#3)}]path picture bounding box.north west) {\pgfuseimage{#1}};
}
}]
\foreach \x in {0,...,3}{
\foreach \y in {0,...,3}{
\pgfmathtruncatemacro{\yy}{4*\x+\y}
\pgfmathtruncatemacro{\xx}{\myrandlist[\yy]}
\pgfmathtruncatemacro{\curry}{Mod(\xx,4)}
\pgfmathtruncatemacro{\currx}{(\xx)/4} % Integer part
\path[path image=hotel shifted \currx cm and \curry cm] %Shifts the image
(\x cm,-\y cm) rectangle +(1cm,1cm); %The size is the unit shift size
}
}
\end{tikzpicture}
\end{document}
答案4
由于对这个问题的第一条评论,我不会打乱网格位置。而是打乱用于组成动画帧的单元格的顺序。本质保持不变。
使用 C# 的混合解决方案如下。此代码已由专家。
/*===================================*
* Compile it to produce Shuffle.exe *
* ==================================*/
using System;
using System.Collections.Generic;
using System.IO;
namespace Shuffle
{
class Program
{
static void Main(string[] args)
{
int columns = int.Parse(args[0]);
int rows = int.Parse(args[1]);
int seed = int.Parse(args[2]);
string outputFilename = args[3];
string[] elements = new string[columns * rows];
for (int column = 0; column < columns; column++)
for (int row = 0; row < rows; row++)
elements[column * rows + row] = string.Format("{{{0},{1}}}", column, row);
Random random = new Random(seed);
for (int i = elements.Length - 1; i >= 0; i--)
{
int swapIndex = random.Next(i + 1);
string tmp = elements[i];
elements[i] = elements[swapIndex];
elements[swapIndex] = tmp;
}
File.WriteAllLines(outputFilename, elements);
}
}
}
\documentclass[pstricks,border=12pt]{standalone}
\usepackage{multido}
\usepackage{graphicx}
\def\Columns{10}% columns
\def\Rows{10}% rows
\def\Filename{parishilton}
\def\Scale{1}
\newsavebox\IBox
\savebox\IBox{\includegraphics[scale=\Scale]{\Filename}}
\psset
{
xunit=\dimexpr\wd\IBox/\Columns,
yunit=\dimexpr\ht\IBox/\Rows,
}
\SpecialCoor
\newread\myfile
\def\tempii#1,#2{%
\pspicture(\Columns,\Rows)
\psclip{\psframe[linestyle=none,linewidth=0pt](!#1 #2)(!#1 1 add #2 1 add)}
\rput[bl](0,0){\usebox\IBox}
\endpsclip
\endpspicture}
\def\tempi#1{\expandafter\tempii#1\relax}
\begin{document}
\immediate\write18{cmd /C del data.txt}
\immediate\write18{Shuffle.exe \Columns\space \Rows\space 1 data.txt}
\openin\myfile=data.txt\relax
\loop
\read\myfile to \dd
\unless\ifeof\myfile
\expandafter\tempi\dd\relax
\repeat
\closein\myfile
\end{document}