     )
   end
 
-  defp make_rescale_command(project, rescale_x, rescale_y) do
-    {"convert",
+  defp make_rescale_commands(project, image_id, rescale) do
+    {
+      "mkdir",
       [
-        @imageroot <> project <> "/6c5f936b-dba9-bf57-b681-5fc292e00e0b.jpg",
+        "-p", "#{@imageroot}#{project}/#{image_id}"
+      ],
+      "convert",
+      [
+        "#{@imageroot}#{project}/#{image_id}.jpg", # todo make param for suffix
         "-resize",
-        "#{rescale_x}x#{rescale_y}",
-        @imageroot <> project <> "/6c5f936b-dba9-bf57-b681-5fc292e00e0b.#{rescale_x}.jpg" # todo rescale_y
+        "#{rescale}x#{rescale}",
+        "#{@imageroot}#{project}/#{image_id}/#{image_id}.#{rescale}.#{@intermediate_format_suffix}"
       ]
     }
   end

    nil
  end

  def calc_tiles(project, image_id, image_size = {size_x, size_y}) do

    template = create_template(image_size, @tile_size)

    # todo: build all commands, then flatten, then execute them
    commands = Enum.map(template, fn {{rescale, entries}, z} ->
      rescale = floor(rescale)
      {cmd, args} = make_rescale_command(project, rescale, rescale)
      System.cmd(cmd, args)
      Enum.map(entries,
        fn entry ->
           {cmd_a, args_a, cmd_b, args_b} = make_crop_commands(
             project, @tile_size, "#{image_id}.#{rescale}.jpg", image_id, z, entry)
           System.cmd(cmd_a, args_a)
           System.cmd(cmd_b, args_b)
           nil
        end)
    end)
    nil
  end

  defp create_template(image_size = {size_x, size_y}, tile_size) do
    Stream.unfold({:continue, image_size}, fn {run, current_size = {current_size_x, current_size_y}} ->
      if run != :continue do
        nil
      else
        {
          {
            current_size,
            List.flatten(calc_template(current_size, tile_size))
          },
          {
            if current_size_x < tile_size do :halt else :continue end,
            {current_size_x / 2, current_size_y / 2}
          }
        }
      end
    end) |> Enum.to_list() |> Enum.reverse() |> Enum.with_index()
  end


  @tile_size 256
  @required_imagemagick_version [6, 9]
  @required_delegates ["jp2", "png", "jpeg"]
  @intermediate_format_suffix "jpg"

  def required_version_matches(version, [required_major, required_minor]) do
    [major, minor, _] = String.split(version, ".")
