Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have no idea to shuffle the following grids of a sliced image. How to do this in (La)TeX or PostScript level?

enter image description here

\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}

Here is the picture that I used in this answer as a demo picture.

share|improve this question
1  
@PauloCereda made a blog post about selecting parts of an image which is here: tex.blogoverflow.com/2012/05/using-sprite-sheets-with-latex . So the remaining part is to randomize the parts and Bob's your uncle and Paris is family anyway. –  percusse Sep 6 '12 at 17:27
3  
I added now random-numbers. This lead me to the following related question which looks promising: tex.stackexchange.com/questions/63357/… –  Martin Scharrer Sep 6 '12 at 17:39
1  
I'm surprised that you accepted Herbert's answer instead of Aditya's or percusse's: I had understood that you wanted the position of the slides to be shuffled, not the order of appearance. Maybe it would be a good idea to edit your question to be more explicit about this point. –  Jake Sep 7 '12 at 13:47
    
@Jake: Because I prefer the cryptic PostScript language (even though I don't understand well what Herbert wrote). :-) Other answers are good of course. Shuffling for either the position of slides or the order of appearance is almost identical, so it was not taken under my consideration. –  I am who I say I am Sep 7 '12 at 13:49
    
Btw, where is the fist comment? –  I am who I say I am Sep 7 '12 at 15:44
show 7 more comments

4 Answers

up vote 7 down vote accepted
+100
\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}

enter image description here

share|improve this answer
    
One glitch found. You need to specify the clipping frame with either linewidth=0pt or dimen=middle to remove the inter-cell space. –  I am who I say I am Sep 7 '12 at 15:38
add comment

Because of the first comment given to the question, I don't shuffle the grid position. I shuffle the order of cells taken to compose the animation frames instead. The essence remains unchanged.

A hybrid solution with C# is as follows. This code has been reviewed and optimized by an expert.

/*===================================*
 * 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);
        }
    }
}

enter image description here

\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}
share|improve this answer
    
Oops then I completely misunderstood the question. –  percusse Sep 6 '12 at 21:59
    
@percusse: No. You understood the question well. –  I am who I say I am Sep 6 '12 at 22:00
    
Your algorithm does not produce good shuffles... Look at Aditya's answer with the Fisher Yates shuffle. –  Paul Gaborit Sep 6 '12 at 22:15
2  
Fisher Yates algorithm is O(n) and is truly random (as far as the pseudo-random generator) and all permutations are equiprobable. Your method requires many more iterations to tend towards the same result. –  Paul Gaborit Sep 6 '12 at 22:23
    
@PaulGaborit: Now I used the best algorithm. –  I am who I say I am Sep 10 '12 at 4:33
add comment

Here is another one. The code is a little messy so I'll divide the output:

First of all I needed to get a random list, I did it via first declaring a regular increasing numbers list. Then I picked up one from it and put it into a new one. At the same time, I've deleted that number from the old list and repeated this until we run out of numbers.

So the output looks like this

enter image description here

The picked up number switches to our new list on the right (then we remove the initial comma).

Then (counting as 11-> 8+3 second row, third column) We get the random number from our list, convert to the cell coordinate and shift the image behind the node according to the idea that our famous Paulo Cereda has given in the blog post about sprite sheets. I've chosen 4 by 4 grid but can be changed. Also note that the underlying coordinate system is scaled to match the width and height of the image.

I've used the Hilton Hotel in Paris and the image is from their website because I can't stand those celebrities. So the output is

enter image description here

The Code

(as Peter Grill would do)

\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}
share|improve this answer
    
Why can't you stand? :-) –  I am who I say I am Sep 10 '12 at 4:23
1  
@GarbageCollector Do you know the slang phrase waste of space? –  percusse Sep 10 '12 at 11:55
    
I understood after reading and watching this video. –  I am who I say I am Sep 11 '12 at 4:30
    
@GarbageCollector :) Nice. –  percusse Sep 11 '12 at 7:51
add comment

Here is a simple LuaTeX/ConTeXt based solution.

\shuffle[nx=..., ny=...]{<box>}

where nx is the number of horizontal slices that you want, and my is the number of vertical slices that you want. The macro is based on \setupclipping and which does the actual hard work of clipping the image. This macro effective generates:

\clip[nx=...,ny=...,x=...,y=...]{<box>}

by randomly varying x and y over all possible values. To generate such x and y, I simply generate all possible values and shuffle the result. AFAIK, Lua does not have a shuffle function, so I implemented one based on the standard Fisher Yates algorithm.

Here is the result of \shuffle[nx=3,ny=2]{\externalfigure[hacker]} (hacker is one of the sample images distributed with ConTeXt).

enter image description here

And finally, the macro:

\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
share|improve this answer
1  
random(1,i) can be simplified as random(i). –  I am who I say I am Apr 2 '13 at 11:29
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.