Custom Matrix product

You can also achieve your ultimate (or ulterior) goal with ImageResize:

imgdata = Array[0.2 #1 + 0.1 #2 - 0.2 + 0.01 #3 &, {2, 2, 3}]
(* {{{0.11, 0.12, 0.13}, {0.21, 0.22, 0.23}}, {{0.31, 0.32, 0.33}, {0.41, 0.42, 0.43}}} *)

img = Image @ imgdata;
img2 = ImageResize[img, Scaled[2]];

ImageData[img2] // MatrixForm

Mathematica graphics

P.S. There are various Resampling algorithms built into Mathematica.


One of the most direct ways hasn't been shown yet, which is to expand each element at level 2 with e.g. ConstantArray and then ArrayFlatten the entire result. Edit: Actually Nasser did this manually, without Map and using the less efficient Table, but the idea is identical.

ArrayFlatten @ Map[ConstantArray[#, {2, 4}] &, list1, {2}]

enter image description here

Slightly more complicated but significantly faster is to expand the entire array and then Flatten as necessary:

ConstantArray[#, {2, 4}] ~Flatten~ {{3, 1}, {4, 2}} & @ list1

On my system this tests faster than any other code I have tried, including ImageResize (see below).


Timings

Timings for all methods posted so far, in version 7.

Edit: Michael's ouput does not match the question or other answers. The code should be ImageResize[img, {Scaled[4], Scaled[2]}] which I will use below.

SetAttributes[timeAvg, HoldFirst]
timeAvg[func_] := Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]

list1 = RandomInteger[99, {500, 500, 3}];

ArrayFlatten @ Map[ConstantArray[#, {2, 4}] &, list1, {2}]    // timeAvg
ConstantArray[#, {2, 4}] ~Flatten~ {{3, 1}, {4, 2}} & @ list1 // timeAvg

ArrayFlatten[
  Transpose[Outer[Times, {{1, 1, 1, 1}, {1, 1, 1, 1}}, list1], {3, 4, 1, 2}]] // timeAvg

ImageData@ImageResize[Image@list1, {Scaled[4], Scaled[2]}] // timeAvg

Module[{f},
  f[x_] := ArrayFlatten@Table[x, {2}, {4}];
  ArrayFlatten@Map[f, list1, {2}]
] // timeAvg

With[{
   grid = ArrayFlatten[Table[ConstantArray[Slot@n, {2, 4}], {n, 4}]~Partition~2]
   },
  grid & @@ Flatten[list1, 1]
] // timeAvg

With[{exp = {2, 4}},
  Array[
   Extract[list1, Ceiling[{#1, #2}/exp]] &,
   exp Most@Dimensions[list1]
  ]
] // timeAvg

0.2714

0.03684

1.373

0.0512

1.529

0.0686

6.209

My second function takes first place, Michael's takes second, and rm-rf's takes third. Note that Michael's is less general, applying only to data that is handled by Image.


Observing the pattern in the desired output, you can construct something like this (extensible to larger grids):

With[{grid = ArrayFlatten[Table[ConstantArray[Slot@n, {2, 4}], {n, 4}] ~Partition~ 2]},
    grid & @@ Flatten[list, 1] 
] // MatrixForm

grid here is a pure function (well, only the slots) that looks like this, mimicking the structure of your output:

to which we pass the individual sublists as arguments.