diff --git a/Codec/Picture/Repa.hs b/Codec/Picture/Repa.hs
--- a/Codec/Picture/Repa.hs
+++ b/Codec/Picture/Repa.hs
@@ -11,15 +11,17 @@
        -- * Image Representations (Phantom Types)
        , RGBA, RGB, R, G, B
        -- * Helper Functions (useful for OpenGL etc.) 
-       , toVector
        , toForeignPtr
+       , onImg
        , reverseColorChannel
        , flipHorizontally, flipVertically
+       , vConcat, hConcat
        -- * Internal Functionallity (exported for advanced uses)
        , ToRGBAChannels(..)
        ) where
 import qualified Data.Array.Repa as R
-import qualified Data.Array.Repa.Repr.Unboxed as RU
+import qualified Data.Array.Repa.Repr.ForeignPtr as RF
+import Data.Array.Repa.Repr.ForeignPtr (F)
 import Data.Array.Repa ((:.), Array, (:.)(..), Z(..), DIM3, backpermute, extent)
 import qualified Codec.Picture as P
 import Codec.Picture hiding (readImage, decodeImage)
@@ -55,15 +57,18 @@
 --
 -- All images are held in a three dimensional 'repa' array.  If the image
 -- format is only two dimensional (ex: R, G, or B) then the shape is @Z :. y :. x :. 1@.
-data Img a = Img { imgData :: Array RU.U DIM3 Word8 }
+data Img a = Img { imgData :: Array F DIM3 Word8 }
 
+onImg :: (Array F DIM3 Word8 -> Array F DIM3 Word8) -> Img a -> Img a
+onImg f (Img a) = Img (f a)
+
 -- |By default, the color channel for 'RGBA' indexes 0 -> R, 1 -> G, 2
 -- -> B, 3 -> A.  This is the AGBR byte ordering in OpenGL.  For
 -- rendering with OpenGL's RGBA PixelFormat be sure to call
 -- reverseColorChannel before converting to a Vector (or directly to
 -- bytestring via 'repa-bytestring').
 reverseColorChannel :: Img a -> Img a
-reverseColorChannel (Img r) = Img (R.computeUnboxedS $ R.backpermute e order r)
+reverseColorChannel (Img r) = Img (R.computeS $ R.backpermute e order r)
   where
   e@(Z :. row :. col :. z)  = R.extent r
   order (Z :. r :. c :. z') = Z :. r :. c :. z - z' - 1
@@ -127,13 +132,9 @@
 
 -- | O(n)  returning (pointer, length, offset)
 toForeignPtr :: Img RGBA -> (ForeignPtr Word8, Int, Int)
-toForeignPtr = S.unsafeToForeignPtr . S.convert . RU.toUnboxed . imgData
-
--- |Convert an 'Img' to a storable 'Vector', often useful for OpenGL
--- and other C interfaces.  Notice the format of the data depends on
--- the type of the 'Img a'. O(n)
-toVector :: Img a -> S.Vector Word8
-toVector (Img a) = S.convert . RU.toUnboxed $ a
+toForeignPtr r = (RF.toForeignPtr . imgData $ r, row * col * d, 0)
+ where
+ (Z :. row :. col :. d) = extent (imgData r)
 
 -- Helper functions --
 getChannel :: Int -> PixelRGBA8 -> Word8
@@ -225,41 +226,72 @@
 instance (ToRGBAChannels a, Pixel a) => ConvertImage (Image a) RGBA where
   convertImage p@(Image w h dat) =
     let z = 4
-    in Img $ R.computeUnboxedS $ R.fromFunction (Z :. h :. w :. z) 
+    in Img $ R.computeS $ R.fromFunction (Z :. h :. w :. z) 
                                     (\(Z :. y :. x :. z') -> getPixel x y (z - z' - 1) p)
   
 instance (ToRGBAChannels a, Pixel a) => ConvertImage (Image a) RGB where
   convertImage p@(Image w h dat) =
     let z = 3
-    in Img $ R.computeUnboxedS $ R.fromFunction (Z :. h :. w :. z)
+    in Img $ R.computeS $ R.fromFunction (Z :. h :. w :. z)
                             (\(Z :. y :. x :. z') -> getPixel x y (z' - z -1) p)
 
 instance (ToRGBAChannels a, Pixel a) => ConvertImage (Image a) R where
   convertImage p@(Image w h dat) =
     let z = 1
-    in Img $ R.computeUnboxedS $ R.fromFunction (Z :. h :. w :. z)
+    in Img $ R.computeS $ R.fromFunction (Z :. h :. w :. z)
                             (\(Z :. y :. x :. z) -> getPixel x y 0 p)
        
 instance (ToRGBAChannels a, Pixel a) => ConvertImage (Image a) G where
   convertImage p@(Image w h dat) =
     let z = 1
-    in Img $ R.computeUnboxedS $ R.fromFunction (Z :. h :. w :. z)
+    in Img $ R.computeS $ R.fromFunction (Z :. h :. w :. z)
                             (\(Z :. y :. x :. z) -> getPixel x y 1 p)
        
 instance (ToRGBAChannels a, Pixel a) => ConvertImage (Image a) B where
   convertImage p@(Image w h dat) =
     let z = 1
-    in Img $ R.computeUnboxedS $ R.fromFunction (Z :. h :. w :. z)
+    in Img $ R.computeS $ R.fromFunction (Z :. h :. w :. z)
                             (\(Z :. y :. x :. z) -> getPixel x y 2 p)
 
-flipVertically :: Img a -> Img a
-flipVertically (Img rp) = Img (R.computeUnboxedS $ backpermute e order rp)
+flipVertically :: Array F DIM3 Word8 -> Array F DIM3 Word8
+flipVertically rp = (R.computeS $ backpermute e order rp)
  where
  e@(Z :. row :. col :. z) = extent rp
  order (Z :. oldRow :. oldCol :. oldChan) = Z :. row - oldRow - 1 :. oldCol :. oldChan
 
-flipHorizontally :: Img a -> Img b
-flipHorizontally (Img rp) = Img (R.computeUnboxedS $ backpermute e order rp)
+flipHorizontally :: Array F DIM3 Word8 -> Array F DIM3 Word8
+flipHorizontally rp = (R.computeS $ backpermute e order rp)
  where
  e@(Z :. row :. col :. z) = extent rp
  order (Z :. oldRow :. oldCol :. oldChan) = Z :. oldRow :. col - oldCol - 1 :. oldChan
+
+-- |Stack the images vertically, placing the first image on top of the second.
+vStack :: Array R.D DIM3 Word8 -> Array R.D DIM3 Word8 -> Array R.D DIM3 Word8
+vStack a b = R.traverse2 a b combExtent stack
+  where
+  combExtent (Z :. h1 :. w1 :. d1) (Z :. h2 :. w2 :. d2)
+    = Z :. (h1 + h2)  :. min w1 w2 :. min d1 d2
+  (Z :. ha :. _ :. _) = R.extent a
+  (Z :. hb :. _ :. _) = R.extent b
+  stack fa fb (Z :. h :. w :. d)
+	| h < hb    = fb (Z :. h :. w :. d)
+        | otherwise = fa (Z :. h - hb :. w :. d)
+
+vConcat :: [Array F DIM3 Word8] -> Array F DIM3 Word8
+vConcat [] = error "vConcat: Can not concat an empty list into a Repa array"
+vConcat xs = R.computeS $ Prelude.foldl1 vStack (Prelude.map R.delay xs)
+
+hConcat :: [Array F DIM3 Word8] -> Array F DIM3 Word8
+hConcat [] = error "hConcat: Can not concat an empty list into a Repa array"
+hConcat xs = R.computeS $ Prelude.foldl1 hStack (Prelude.map R.delay xs)
+
+-- |Stack the images horozontally, placing the first image on the left of the second.
+hStack :: Array R.D DIM3 Word8 -> Array R.D DIM3 Word8 -> Array R.D DIM3 Word8
+hStack a b = R.traverse2 a b combExtent stack
+  where
+  combExtent (Z :. r1 :. c1 :. d1) ( Z :. r2 :. c2 :. d2)
+    = Z :. min r1 r2 :. c1 + c2 :. min d1 d2
+  (Z :. _ :. ca :. _) = R.extent a
+  stack fa fb (Z :. r :. c :. d)
+	| c < ca    = fa (Z :. r :. c :. d)
+	| otherwise = fb (Z :. r :. c - ca :. d)
diff --git a/JuicyPixels-repa.cabal b/JuicyPixels-repa.cabal
--- a/JuicyPixels-repa.cabal
+++ b/JuicyPixels-repa.cabal
@@ -1,5 +1,5 @@
 Name:                JuicyPixels-repa
-Version:             0.3.1
+Version:             0.4
 Synopsis:            Convenience functions to obtain array representations of images.
 Description:         This wraps the Juicy.Pixels library to convert into 'Repa' and 
                      'Data.Vector.Storable' formats.
@@ -18,8 +18,8 @@
 
 Library
   Exposed-modules:     Codec.Picture.Repa
-  Build-depends:       base >= 4.0 && < 5, repa >= 3.0 && < 3.1
-                    , JuicyPixels >= 1.1 && < 1.3
+  Build-depends:       base >= 4.0 && < 5, repa >= 3.0 && < 3.3
+                    , JuicyPixels >= 1.1 && < 1.4
                     , vector >= 0.9 && < 0.10
                     , bytestring >= 0.9 && < 0.10
   -- Other-modules:       
