diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Vanessa McHale (c) 2016
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Vanessa McHale nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,25 @@
+#QR Imager Library
+This is a library to generate `.png` files from QR codes.
+
+##Dependencies
+The library depends on the C library [https://github.com/fukuchi/libqrencode](libqrencode) which you will need to install separately.
+
+##Usage
+The library exports main functions - `createQRCode` and `byteStringToQR` - and their secured/signed versions. The first takes any object that is an instance of `ToJSON` and writes an image to file, while the second takes a (strict) bytestring and writes it to file.
+
+##Executable
+
+###Installation
+For building haskell, the best tool is currently [http://haskellstack.org](stack). Install it, and then type
+
+```
+stack install --install-ghc
+```
+
+in the appropriate directory, and it will be installed on your path. 
+
+###Use
+
+Compiling will generate an executable called `QRPipe` which reads from `stdin` and outputs a file as the second argument, e.g.
+
+```echo 'My name is:" | QRPipe "nametag.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/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -0,0 +1,11 @@
+{-#LANGUAGE OverloadedStrings #-}
+
+import Data.QRCodes
+import qualified Data.ByteString as B
+import System.Environment (getArgs)
+
+main :: IO ()
+main = do
+    pipeIn <- B.getContents
+    filepath <- fmap (flip (!!) 0) getArgs
+    byteStringToQRSec pipeIn filepath
diff --git a/qr-imager.cabal b/qr-imager.cabal
new file mode 100644
--- /dev/null
+++ b/qr-imager.cabal
@@ -0,0 +1,42 @@
+name:                qr-imager
+version:             0.1.0.0
+synopsis:            Library to generate QR codes from bytestrings and objects
+description:         Please see README.md
+homepage:            https://github.com/vmchale/QRImager#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Vanessa McHale
+maintainer:          tmchale@wisc.edu
+copyright:           Copyright: (c) 2016 Vanessa McHale
+category:            Data
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Data.QRCodes
+  build-depends:       base >= 4.7 && < 5
+                     , aeson
+                     , JuicyPixels
+                     , vector
+                     , bytestring
+                     , lens
+                     , cryptonite
+                     , jose-jwt
+                     , directory
+                     , haskell-qrencode
+  default-language:    Haskell2010
+
+executable QRPipe
+  hs-source-dirs:      app
+  main-is:             Main.hs
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  build-depends:       base
+                     , qr-imager
+                     , bytestring
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/vmchale/QRImager
diff --git a/src/Data/QRCodes.hs b/src/Data/QRCodes.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/QRCodes.hs
@@ -0,0 +1,85 @@
+{-# LANGUAGE GADTs            #-}
+{-# LANGUAGE FlexibleContexts #-}
+
+module Data.QRCodes (createSecureQRCode
+              , createQRCode
+              , byteStringToQR
+              , byteStringToQRSec
+              ) where
+
+import Data.Aeson
+import Data.QRCode
+import Codec.Picture.Types as T
+import Codec.Picture.Png (writePng)
+import Data.Word (Word8)
+import qualified Data.Vector.Storable as V
+import Data.ByteString.Lazy (toStrict)
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as BSL
+import Data.List (replicate)
+import Data.Char (toLower)
+import Prelude as P
+import Crypto.PubKey.RSA as Cr
+import Jose.Jws
+import System.Directory (doesFileExist)
+import Control.Lens.Tuple
+import Control.Lens (view)
+import Jose.Jwt (unJwt, JwtError)
+import Jose.Jwa (JwsAlg (RS512))
+import Data.Either (either)
+import Data.Bits ((.&.))
+import Control.Applicative ((<$>))
+
+checkSig :: BS.ByteString -> IO (Either JwtError BS.ByteString)
+checkSig tok = do
+    key <- read <$> readFile "~/.key.hk" :: IO (Cr.PublicKey, Cr.PrivateKey)
+    let jws = rsaDecode (view _1 key) tok
+    return $ fmap (view _2) jws
+
+mkSig :: BS.ByteString -> IO BS.ByteString
+mkSig string = do
+    switch <- doesFileExist "~/.key.hk"
+    if not switch then do
+        putStrLn "generating key..."
+        key <- Cr.generate 512 0x10001
+        writeFile "~/.key.hk" (show key)
+    else
+        return ()
+    key' <- read <$> readFile "~/.key.hk" :: IO (Cr.PublicKey, Cr.PrivateKey)
+    signedToken <- rsaEncode RS512 (view _2 key') string
+    let signed = fmap unJwt signedToken
+    liftEither id (return <$> signed)
+
+-- | Creates a signed QR code from a strict bytestring
+byteStringToQRSec :: BS.ByteString -> FilePath -> IO ()
+byteStringToQRSec string filepath = (flip byteStringToQR filepath) =<< (mkSig string)
+
+-- | Creates a signed QR code from an object that is part of the ToJSON class
+createSecureQRCode :: (ToJSON a) => a -> FilePath -> IO ()
+createSecureQRCode object = byteStringToQRSec (toStrict $ encode object)
+
+liftEither :: (Show b, Monad m) => (t -> m a) -> Either b t -> m a
+liftEither = either (error . show)
+
+-- | Creates a QR code from an object that is part of the ToJSON class
+createQRCode :: (ToJSON a) => a -> FilePath -> IO ()
+createQRCode object filepath = let input = toStrict $ encode object in byteStringToQR input filepath
+
+-- | Creates a QR code from a strict bytestring
+byteStringToQR :: BS.ByteString -> FilePath -> IO ()
+byteStringToQR input filepath = do
+    smallMatrix <- toMatrix <$> encodeByteString input Nothing QR_ECLEVEL_H QR_MODE_EIGHT False
+    let qrMatrix = fattenList 8 $ P.map (fattenList 8) smallMatrix
+    writePng filepath (encodePng qrMatrix)
+
+encodePng :: [[Word8]] -> T.Image Word8
+encodePng matrix = Image dim dim vector
+    where dim    = P.length matrix
+          vector = V.map ((*255) . swapWord) $ V.fromList $ P.concat matrix
+
+fattenList :: Int -> [a] -> [a]
+fattenList i l = P.concat $ P.foldr ((:) . (P.replicate i)) [] l
+
+swapWord :: Word8 -> Word8
+swapWord 1 = 0
+swapWord 0 = 1
