diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,5 @@
+# Changelog for qrcode-juicypixels
+
+## 0.8.0 -- 2019-01-xx
+
+* Initial release
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2019 ALeX Kazik
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,8 @@
+# qrcode
+
+QR code library in pure Haskell
+
+## qrcode-juicypixels
+
+This package adds a function to convert the QRCode into a JuicyPixels image.
+And some to create a data url containing the QRCode as a PNG.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/qrcode-juicypixels.cabal b/qrcode-juicypixels.cabal
new file mode 100644
--- /dev/null
+++ b/qrcode-juicypixels.cabal
@@ -0,0 +1,46 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.31.1.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 6e6d256f698e213892696daa3ade945d2973202981e27ffb81e424b3d5e9d4d8
+
+name:           qrcode-juicypixels
+version:        0.8.0
+synopsis:       Converts a qrcode-core image to JuicyPixels
+description:    Please see the README on GitHub at <https://github.com/alexkazik/qrcode/qrcode-juicypixels#readme>
+category:       graphics
+homepage:       https://github.com/alexkazik/qrcode#readme
+bug-reports:    https://github.com/alexkazik/qrcode/issues
+author:         ALeX Kazik
+maintainer:     alex@kazik.de
+copyright:      2018 ALeX Kazik
+license:        MIT
+license-file:   LICENSE
+tested-with:    GHC == 7.10.3, GHC == 8.0.1, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.3
+build-type:     Simple
+extra-source-files:
+    README.md
+    ChangeLog.md
+
+source-repository head
+  type: git
+  location: https://github.com/alexkazik/qrcode
+
+library
+  exposed-modules:
+      Codec.QRCode.JuicyPixels
+  other-modules:
+      Paths_qrcode_juicypixels
+  hs-source-dirs:
+      src
+  build-depends:
+      JuicyPixels >=3.2.6 && <3.4
+    , base >=4.8.2.0 && <5
+    , base64-bytestring >=1.0.0.1 && <1.1
+    , bytestring >=0.10.6.0 && <0.11
+    , qrcode-core >=0.8 && <1
+    , text >=1.2.2.0 && <1.3
+    , vector >=0.11.0.0 && <0.13
+  default-language: Haskell2010
diff --git a/src/Codec/QRCode/JuicyPixels.hs b/src/Codec/QRCode/JuicyPixels.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/QRCode/JuicyPixels.hs
@@ -0,0 +1,89 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+
+module Codec.QRCode.JuicyPixels
+  ( -- * Image
+    toImage
+    -- * URL
+  , toPngDataUrlBS
+  , toPngDataUrlS
+  , toPngDataUrlT
+  ) where
+
+import           Codec.Picture               (Image (..), Pixel8, encodePng)
+import           Data.Bool                   (bool)
+import qualified Data.ByteString.Base64.Lazy as B64L
+import qualified Data.ByteString.Lazy        as BL
+import qualified Data.ByteString.Lazy.Char8  as BLC8
+import qualified Data.Text.Lazy              as TL
+import qualified Data.Vector.Storable        as SV
+import qualified Data.Vector.Unboxed         as UV
+import           Data.Word                   (Word8)
+
+import           Codec.QRCode                (QRImage (..))
+
+-- | Convert the QR code into an image.
+--
+--   If this is not the required image format use `Codec.Picture.Types.promoteImage` and/or `Codec.Picture.Types.convertImage`.
+toImage
+  :: Int -- ^ Border to add around the QR code, recommended is 4 (<0 is treated as 0)
+  -> Int -- ^ Factor to scale the image (<1 is treated as 1)
+  -> QRImage -- ^ The QRImage
+  -> Image Pixel8
+toImage border scale QRImage{..}
+  | border <= 0 && scale <= 1 =
+    Image qrImageSize qrImageSize (SV.fromList $ map (bool 0xff 0x00) (UV.toList qrImageData))
+toImage border' scale' QRImage{..} =
+  let
+    border = border' `max` 0
+    scale = scale' `max` 1
+    size = (qrImageSize + 2 * border) * scale
+  in
+    Image size size (SV.fromList $ concat $ doScale scale $ addBorder border $ toMatrix qrImageData)
+  where
+    toMatrix :: UV.Vector Bool -> [[Word8]]
+    toMatrix img
+      | UV.null img = []
+      | otherwise =
+        let
+          (h, t) = UV.splitAt qrImageSize img
+        in
+          map (bool 0xff 0x00) (UV.toList h) : toMatrix t
+    addBorder :: Int -> [[Word8]] -> [[Word8]]
+    addBorder 0 img = img
+    addBorder n img = topBottom ++ addLeftRight img ++ topBottom
+      where
+        topBottom = [replicate ((qrImageSize + 2 * n) * n) 0xff]
+        leftRight = replicate n 0xff
+        addLeftRight = map (\ x -> leftRight ++ x ++ leftRight)
+    doScale :: Int -> [[Word8]] -> [[Word8]]
+    doScale 1 img = img
+    doScale n img = scaleV img
+      where
+        scaleV :: [[Word8]] -> [[Word8]]
+        scaleV = concatMap (replicate n . scaleH)
+        scaleH :: [Word8] -> [Word8]
+        scaleH = concatMap (replicate n)
+
+-- | Convert an QR code into a Uri.
+--   Has the same arguments as `toImage`.
+--
+--   This can be used to display a image in HTML without creating a temporary file.
+toPngDataUrlBS :: Int -> Int -> QRImage -> BL.ByteString
+toPngDataUrlBS border scale img = "data:image/png;base64," `BL.append` B64L.encode (encodePng $ toImage border scale img)
+
+-- | Convert an QR code into a Uri.
+--   Has the same arguments as `toImage`.
+--
+--   Like `toPngDataUrlBS` but with a to String conversion afterwards.
+toPngDataUrlS :: Int -> Int -> QRImage -> String
+{-# INLINE toPngDataUrlS #-}
+toPngDataUrlS border scale = BLC8.unpack . toPngDataUrlBS border scale
+
+-- | Convert an QR code into a Uri.
+--   Has the same arguments as `toImage`.
+--
+--   Like `toPngDataUrlS` but with a to Text conversion afterwards.
+toPngDataUrlT :: Int -> Int -> QRImage -> TL.Text
+{-# INLINE toPngDataUrlT #-}
+toPngDataUrlT border scale = TL.pack . toPngDataUrlS border scale
