diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+1.5.6.0
+=======
+
+* Addition of Bicubic interpolation (Thanks to @kirisaki)
+
 1.5.5.0
 =======
 
diff --git a/hip.cabal b/hip.cabal
--- a/hip.cabal
+++ b/hip.cabal
@@ -1,5 +1,5 @@
 Name:              hip
-Version:           1.5.5.0
+Version:           1.5.6.0
 License:           BSD3
 License-File:      LICENSE
 Author:            Alexey Kuleshevich
diff --git a/src/Graphics/Image/Processing/Interpolation.hs b/src/Graphics/Image/Processing/Interpolation.hs
--- a/src/Graphics/Image/Processing/Interpolation.hs
+++ b/src/Graphics/Image/Processing/Interpolation.hs
@@ -10,7 +10,7 @@
 -- Portability : non-portable
 --
 module Graphics.Image.Processing.Interpolation (
-  Interpolation(..), Nearest(..), Bilinear(..)
+  Interpolation(..), Nearest(..), Bilinear(..), Bicubic(..)
   ) where
 
 import Graphics.Image.Interface
@@ -38,16 +38,21 @@
 data Bilinear = Bilinear deriving Show
 
 
+-- | Bicubic interpolation method.
+--   The parameter is usually set from -0.5 to -1.0.
+newtype Bicubic = Bicubic Double deriving Show
+
+
 instance Interpolation Nearest where
 
-  interpolate Nearest border !sz getPx !(i, j) =
+  interpolate Nearest border !sz getPx (i, j) =
     handleBorderIndex border sz getPx (round i, round j)
   {-# INLINE interpolate #-}
 
 
 instance Interpolation Bilinear where
 
-  interpolate Bilinear border !sz getPx !(i, j) = fi0 + jPx*(fi1-fi0) where
+  interpolate Bilinear border !sz getPx (i, j) = fi0 + jPx*(fi1-fi0) where
     getPx' = handleBorderIndex border sz getPx
     {-# INLINE getPx' #-}
     !(i0, j0) = (floor i, floor j)
@@ -60,4 +65,86 @@
     !f11 = getPx' (i1, j1)
     !fi0 = f00 + iPx*(f10-f00)
     !fi1 = f01 + iPx*(f11-f01)
+  {-# INLINE interpolate #-}
+
+
+instance Interpolation Bicubic where
+
+  interpolate (Bicubic a) border !sz getPx (i, j) =
+      ( f00 + f10 + f20 + f30
+      + f01 + f11 + f21 + f31
+      + f02 + f12 + f22 + f32
+      + f03 + f13 + f23 + f33 ) * promote (fromDouble (1 / w))
+    where
+      getPx' = handleBorderIndex border sz getPx
+      {-# INLINE getPx' #-}
+      distX x = fromIntegral x - i
+      {-# INLINE distX #-}
+      distY y = fromIntegral y - j
+      {-# INLINE distY #-}
+      weight x
+          | x' <= 1 = ((a + 2) * x' - (a + 3)) * x2' + 1
+          | x' <  2 = a * ((x2' - 5 * x' + 8) * x' - 4)
+          | otherwise = 0
+          where x' = abs x
+                x2' = x' * x'
+      {-# INLINE weight #-}
+      !(i0, j0) = (i1 - 1, j1 - 1)
+      !(i1, j1) = (floor i, floor j)
+      !(i2, j2) = (i1 + 1, j1 + 1)
+      !(i3, j3) = (i1 + 2, j1 + 2)
+
+      !weightX0 = weight (distX i0)
+      !weightX1 = weight (distX i1)
+      !weightX2 = weight (distX i2)
+      !weightX3 = weight (distX i3)
+      !weightY0 = weight (distY j0)
+      !weightY1 = weight (distY j1)
+      !weightY2 = weight (distY j2)
+      !weightY3 = weight (distY j3)
+
+      !weightX0Y0 = weightX0 * weightY0
+      !weightX1Y0 = weightX1 * weightY0
+      !weightX2Y0 = weightX2 * weightY0
+      !weightX3Y0 = weightX3 * weightY0
+
+      !weightX0Y1 = weightX0 * weightY1
+      !weightX1Y1 = weightX1 * weightY1
+      !weightX2Y1 = weightX2 * weightY1
+      !weightX3Y1 = weightX3 * weightY1
+
+      !weightX0Y2 = weightX0 * weightY2
+      !weightX1Y2 = weightX1 * weightY2
+      !weightX2Y2 = weightX2 * weightY2
+      !weightX3Y2 = weightX3 * weightY2
+
+      !weightX0Y3 = weightX0 * weightY3
+      !weightX1Y3 = weightX1 * weightY3
+      !weightX2Y3 = weightX2 * weightY3
+      !weightX3Y3 = weightX3 * weightY3
+
+      !f00 = getPx' (i0, j0) * promote (fromDouble weightX0Y0)
+      !f10 = getPx' (i1, j0) * promote (fromDouble weightX1Y0)
+      !f20 = getPx' (i2, j0) * promote (fromDouble weightX2Y0)
+      !f30 = getPx' (i3, j0) * promote (fromDouble weightX3Y0)
+
+      !f01 = getPx' (i0, j1) * promote (fromDouble weightX0Y1)
+      !f11 = getPx' (i1, j1) * promote (fromDouble weightX1Y1)
+      !f21 = getPx' (i2, j1) * promote (fromDouble weightX2Y1)
+      !f31 = getPx' (i3, j1) * promote (fromDouble weightX3Y1)
+
+      !f02 = getPx' (i0, j2) * promote (fromDouble weightX0Y2)
+      !f12 = getPx' (i1, j2) * promote (fromDouble weightX1Y2)
+      !f22 = getPx' (i2, j2) * promote (fromDouble weightX2Y2)
+      !f32 = getPx' (i3, j2) * promote (fromDouble weightX3Y2)
+
+      !f03 = getPx' (i0, j3) * promote (fromDouble weightX0Y3)
+      !f13 = getPx' (i1, j3) * promote (fromDouble weightX1Y3)
+      !f23 = getPx' (i2, j3) * promote (fromDouble weightX2Y3)
+      !f33 = getPx' (i3, j3) * promote (fromDouble weightX3Y3)
+
+      !w = weightX0Y0 + weightX1Y0 + weightX2Y0 + weightX3Y0
+         + weightX0Y1 + weightX1Y1 + weightX2Y1 + weightX3Y1
+         + weightX0Y2 + weightX1Y2 + weightX2Y2 + weightX3Y2
+         + weightX0Y3 + weightX1Y3 + weightX2Y3 + weightX3Y3
   {-# INLINE interpolate #-}
diff --git a/tests/Graphics/Image/ProcessingSpec.hs b/tests/Graphics/Image/ProcessingSpec.hs
--- a/tests/Graphics/Image/ProcessingSpec.hs
+++ b/tests/Graphics/Image/ProcessingSpec.hs
@@ -13,17 +13,20 @@
 data Interpol
   = I1 Nearest
   | I2 Bilinear
+  | I3 Bicubic
 
 instance Show Interpol where
   show (I1 i) = "I1 " ++ show i
   show (I2 i) = "I2 " ++ show i
+  show (I3 i) = "I3 " ++ show i
 
 instance Arbitrary Interpol where
   arbitrary = do
     ix <- arbitrary
-    case ix `mod` (2 :: Int) of
+    case ix `mod` (3 :: Int) of
       0 -> return $ I1 Nearest
       1 -> return $ I2 Bilinear
+      2 -> I3 . Bicubic <$> pure (-1) -- choose (-1, -0.5)
       _ -> error $ "Unknown interpolation: " ++ show ix
 
 
@@ -71,21 +74,25 @@
   rotate90 (leftToRight img $ rotate180 img)
 
 
-prop_rotate90 :: Interpol -> Border (Pixel RGB Double) -> Image VU RGB Double -> Bool
-prop_rotate90 (I1 i) border img = rotate90 img == rotate i border (pi/2) img
-prop_rotate90 (I2 i) border img = rotate90 img == rotate i border (pi/2) img
+prop_rotate90 :: Interpol -> Border (Pixel RGB Double) -> Image VU RGB Double -> Property
+prop_rotate90 (I1 i) border img = rotate90 img === rotate i border (pi/2) img
+prop_rotate90 (I2 i) border img = rotate90 img === rotate i border (pi/2) img
+prop_rotate90 (I3 i) border img = rotate90 img === rotate i border (pi/2) img
 
-prop_rotate180 :: Interpol -> Border (Pixel RGB Double) -> Image VU RGB Double -> Bool
-prop_rotate180 (I1 i) border img = rotate180 img == rotate i border pi img
-prop_rotate180 (I2 i) border img = rotate180 img == rotate i border pi img
+prop_rotate180 :: Interpol -> Border (Pixel RGB Double) -> Image VU RGB Double -> Property
+prop_rotate180 (I1 i) border img = rotate180 img === rotate i border pi img
+prop_rotate180 (I2 i) border img = rotate180 img === rotate i border pi img
+prop_rotate180 (I3 i) border img = rotate180 img === rotate i border pi img
 
-prop_rotate270 :: Interpol -> Border (Pixel RGB Double) -> Image VU RGB Double -> Bool
-prop_rotate270 (I1 i) border img = rotate270 img == rotate i border (3*pi/2) img
-prop_rotate270 (I2 i) border img = rotate270 img == rotate i border (3*pi/2) img
+prop_rotate270 :: Interpol -> Border (Pixel RGB Double) -> Image VU RGB Double -> Property
+prop_rotate270 (I1 i) border img = rotate270 img === rotate i border (3*pi/2) img
+prop_rotate270 (I2 i) border img = rotate270 img === rotate i border (3*pi/2) img
+prop_rotate270 (I3 i) border img = rotate270 img === rotate i border (3*pi/2) img
 
-prop_rotate360 :: Interpol -> Border (Pixel RGB Double) -> Image VU RGB Double -> Bool
-prop_rotate360 (I1 i) border img = (rotate270 . rotate90) img == rotate i border (2*pi) img
-prop_rotate360 (I2 i) border img = (rotate270 . rotate90) img == rotate i border (2*pi) img
+prop_rotate360 :: Interpol -> Border (Pixel RGB Double) -> Image VU RGB Double -> Property
+prop_rotate360 (I1 i) border img = (rotate270 . rotate90) img === rotate i border (2*pi) img
+prop_rotate360 (I2 i) border img = (rotate270 . rotate90) img === rotate i border (2*pi) img
+prop_rotate360 (I3 i) border img = (rotate270 . rotate90) img === rotate i border (2*pi) img
 
 
 struct :: Image VS X Bit
