diff --git a/JuicyPixels.cabal b/JuicyPixels.cabal
--- a/JuicyPixels.cabal
+++ b/JuicyPixels.cabal
@@ -1,5 +1,5 @@
 Name:                JuicyPixels
-Version:             3.2.2
+Version:             3.2.3
 Synopsis:            Picture loading/serialization (in png, jpeg, bitmap, gif, tga, tiff and radiance)
 Description:
     <<data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADABAMAAACg8nE0AAAAElBMVEUAAABJqDSTWEL/qyb///8AAABH/1GTAAAAAXRSTlMAQObYZgAAAN5JREFUeF7s1sEJgFAQxFBbsAV72v5bEVYWPwT/XDxmCsi7zvHXavYREBDI3XP2GgICqBBYuwIC+/rVayPUAyAg0HvIXBcQoDFDGnUBgWQQ2Bx3AYFaRoBpAQHWb3bt2ARgGAiCYFFuwf3X5HA/McgGJWI2FdykCv4aBYzmKwDwvl6NVmUAAK2vlwEALK7fo88GANB6HQsAAAAAAAAA7P94AQCzswEAAAAAAAAAAAAAAAAAAICzh4UAO4zWAYBfRutHA4Bn5C69JhowAMGoBaMWDG0wCkbBKBgFo2AUAACPmegUST/IJAAAAABJRU5ErkJggg==>>
@@ -18,8 +18,8 @@
 -- Constraint on the version of Cabal needed to build this package.
 Cabal-version:       >= 1.10
 
-extra-source-files: changelog, docimages/*.png, docimages/*.svg
-extra-doc-files: docimages/*.png, docimages/*.svg
+extra-source-files: changelog, docimages/*.png
+extra-doc-files: docimages/*.png
 
 Source-Repository head
     Type:      git
@@ -28,7 +28,7 @@
 Source-Repository this
     Type:      git
     Location:  git://github.com/Twinside/Juicy.Pixels.git
-    Tag:       v3.2.2
+    Tag:       v3.2.3
 
 Flag Mmap
     Description: Enable the file loading via mmap (memory map)
diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -1,20 +1,27 @@
 -*-change-log-*-
 
+v3.2.3 March 2015
+ * Adding: Support for RGB in jpeg (yeah, that exist...)
+ * Adding: Support of CMYK & YCrCbK color space in jpeg files.
+ * Addinng: a pixelFoldMap functions analog to the `foldMap` function
+  of the Foldable type class.
+ * Fix: better performances for the pixelFold* functions
+
 v3.2.2 January 2015
- * Squashing GHC 7.10 warnings
+ * Fix: Squashing GHC 7.10 warnings
 
 v3.2.1 December 2014
- * Bumping deepseq dependencies preparing for GHC 7.10
+ * Fix: Bumping deepseq dependencies preparing for GHC 7.10
    release.
 
 v3.2 December 2014
  BREAKING CHANGES:
    the Codec.Picture.Gif functions has changed interfaces.
 
- * Adding TGA reading.
- * Adding TGA writing.
- * Packeable pixel unpack.
- * Returning gif with transparency (breaking Codec.Picture.Gif interface)
+ * Adding: TGA reading.
+ * Adding: TGA writing.
+ * Adding: Packeable pixel unpack.
+ * Fix: Returning gif with transparency (breaking Codec.Picture.Gif interface)
 
 v3.1.7.1 August 2014
  * Previous gif fix was not working withing the readImage
diff --git a/docimages/pixelgraph.svg b/docimages/pixelgraph.svg
deleted file mode 100644
--- a/docimages/pixelgraph.svg
+++ /dev/null
@@ -1,264 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.22.2 (20090313.1817)
- -->
-<!-- Title: pixelGraphic Pages: 1 -->
-<svg width="620pt" height="464pt"
- viewBox="0.00 0.00 620.00 464.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 460)">
-<title>pixelGraphic</title>
-<polygon fill="white" stroke="white" points="-4,5 -4,-460 617,-460 617,5 -4,5"/>
-<!-- PixelRGB8 -->
-<g id="node1" class="node"><title>PixelRGB8</title>
-<ellipse fill="none" stroke="black" cx="246" cy="-438" rx="31.7878" ry="18"/>
-<text text-anchor="middle" x="246" y="-436.3" font-family="sans-serif" font-size="8.00">PixelRGB8</text>
-</g>
-<!-- PixelRGBA8 -->
-<g id="node6" class="node"><title>PixelRGBA8</title>
-<ellipse fill="none" stroke="black" cx="441" cy="-354" rx="34.8223" ry="18"/>
-<text text-anchor="middle" x="441" y="-352.3" font-family="sans-serif" font-size="8.00">PixelRGBA8</text>
-</g>
-<!-- PixelRGB8&#45;&gt;PixelRGBA8 -->
-<g id="edge4" class="edge"><title>PixelRGB8&#45;&gt;PixelRGBA8</title>
-<path fill="none" stroke="black" d="M274.25,-429.506C295.421,-422.833 324.934,-412.874 350,-402 351.523,-401.339 381.994,-385.244 407.261,-371.871"/>
-<polygon fill="black" stroke="black" points="409.071,-374.874 416.272,-367.102 405.796,-368.687 409.071,-374.874"/>
-<text text-anchor="middle" x="393" y="-394.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- PixelRGBF -->
-<g id="node8" class="node"><title>PixelRGBF</title>
-<ellipse fill="none" stroke="black" cx="33" cy="-102" rx="31.7878" ry="18"/>
-<text text-anchor="middle" x="33" y="-100.3" font-family="sans-serif" font-size="8.00">PixelRGBF</text>
-</g>
-<!-- PixelRGB8&#45;&gt;PixelRGBF -->
-<g id="edge6" class="edge"><title>PixelRGB8&#45;&gt;PixelRGBF</title>
-<path fill="none" stroke="black" d="M214.594,-434.005C148.276,-424.689 0,-398.847 0,-354 0,-354 0,-354 0,-186 0,-165.437 8.67323,-143.88 17.1268,-127.753"/>
-<polygon fill="black" stroke="black" points="20.228,-129.378 22.0115,-118.934 14.1045,-125.986 20.228,-129.378"/>
-<text text-anchor="middle" x="23" y="-268.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- Pixel8 -->
-<g id="node20" class="node"><title>Pixel8</title>
-<ellipse fill="none" stroke="black" cx="308" cy="-270" rx="27" ry="18"/>
-<text text-anchor="middle" x="308" y="-268.3" font-family="sans-serif" font-size="8.00">Pixel8</text>
-</g>
-<!-- PixelRGB8&#45;&gt;Pixel8 -->
-<g id="edge60" class="edge"><title>PixelRGB8&#45;&gt;Pixel8</title>
-<path fill="none" stroke="black" d="M214.516,-433.811C149.341,-423.852 9.37863,-395.049 55,-336 81.2893,-301.973 207.23,-282.163 270.929,-274.163"/>
-<polygon fill="black" stroke="black" points="271.46,-277.624 280.961,-272.936 270.61,-270.676 271.46,-277.624"/>
-<text text-anchor="middle" x="80" y="-352.3" font-family="sans-serif" font-size="8.00">computeLuma</text>
-</g>
-<!-- PixelCMYK8 -->
-<g id="node28" class="node"><title>PixelCMYK8</title>
-<ellipse fill="none" stroke="black" cx="253" cy="-354" rx="34.8223" ry="18"/>
-<text text-anchor="middle" x="253" y="-352.3" font-family="sans-serif" font-size="8.00">PixelCMYK8</text>
-</g>
-<!-- PixelRGB8&#45;&gt;PixelCMYK8 -->
-<g id="edge40" class="edge"><title>PixelRGB8&#45;&gt;PixelCMYK8</title>
-<path fill="none" stroke="black" d="M224.748,-423.894C213.935,-414.831 204.182,-402.459 210,-390 212.758,-384.095 217.013,-378.817 221.794,-374.241"/>
-<polygon fill="black" stroke="black" points="224.225,-376.77 229.601,-367.64 219.705,-371.424 224.225,-376.77"/>
-<text text-anchor="middle" x="232" y="-394.3" font-family="sans-serif" font-size="8.00">convertPixel</text>
-</g>
-<!-- PixelYCbCr8 -->
-<g id="node30" class="node"><title>PixelYCbCr8</title>
-<ellipse fill="none" stroke="black" cx="150" cy="-354" rx="35.9084" ry="18"/>
-<text text-anchor="middle" x="150" y="-352.3" font-family="sans-serif" font-size="8.00">PixelYCbCr8</text>
-</g>
-<!-- PixelRGB8&#45;&gt;PixelYCbCr8 -->
-<g id="edge42" class="edge"><title>PixelRGB8&#45;&gt;PixelYCbCr8</title>
-<path fill="none" stroke="black" d="M214.399,-434.415C177.053,-429.451 118.29,-419.109 105,-402 97.106,-391.837 104.874,-381.324 116.049,-372.736"/>
-<polygon fill="black" stroke="black" points="118.35,-375.401 124.612,-366.856 114.387,-369.631 118.35,-375.401"/>
-<text text-anchor="middle" x="127" y="-394.3" font-family="sans-serif" font-size="8.00">convertPixel</text>
-</g>
-<!-- PixelRGB16 -->
-<g id="node2" class="node"><title>PixelRGB16</title>
-<ellipse fill="none" stroke="black" cx="429" cy="-102" rx="34.1425" ry="18"/>
-<text text-anchor="middle" x="429" y="-100.3" font-family="sans-serif" font-size="8.00">PixelRGB16</text>
-</g>
-<!-- PixelRGBA16 -->
-<g id="node4" class="node"><title>PixelRGBA16</title>
-<ellipse fill="none" stroke="black" cx="343" cy="-18" rx="37.1721" ry="18"/>
-<text text-anchor="middle" x="343" y="-16.3" font-family="sans-serif" font-size="8.00">PixelRGBA16</text>
-</g>
-<!-- PixelRGB16&#45;&gt;PixelRGBA16 -->
-<g id="edge2" class="edge"><title>PixelRGB16&#45;&gt;PixelRGBA16</title>
-<path fill="none" stroke="black" d="M400.098,-92.2134C386.67,-86.4097 371.409,-77.8363 361,-66 355.909,-60.2106 352.202,-52.8433 349.526,-45.6287"/>
-<polygon fill="black" stroke="black" points="352.846,-44.5187 346.482,-36.0479 346.174,-46.6383 352.846,-44.5187"/>
-<text text-anchor="middle" x="384" y="-58.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- Pixel16 -->
-<g id="node16" class="node"><title>Pixel16</title>
-<ellipse fill="none" stroke="black" cx="296" cy="-186" rx="27" ry="18"/>
-<text text-anchor="middle" x="296" y="-184.3" font-family="sans-serif" font-size="8.00">Pixel16</text>
-</g>
-<!-- PixelRGB16&#45;&gt;Pixel16 -->
-<g id="edge58" class="edge"><title>PixelRGB16&#45;&gt;Pixel16</title>
-<path fill="none" stroke="black" d="M424.573,-120.149C421.265,-130.199 415.765,-142.199 407,-150 386.436,-168.304 356.427,-177.32 332.795,-181.75"/>
-<polygon fill="black" stroke="black" points="332.056,-178.325 322.773,-183.431 333.214,-185.228 332.056,-178.325"/>
-<text text-anchor="middle" x="441" y="-142.3" font-family="sans-serif" font-size="8.00">computeLuma</text>
-</g>
-<!-- PixelCMYK16 -->
-<g id="node26" class="node"><title>PixelCMYK16</title>
-<ellipse fill="none" stroke="black" cx="553" cy="-18" rx="37.1721" ry="18"/>
-<text text-anchor="middle" x="553" y="-16.3" font-family="sans-serif" font-size="8.00">PixelCMYK16</text>
-</g>
-<!-- PixelRGB16&#45;&gt;PixelCMYK16 -->
-<g id="edge38" class="edge"><title>PixelRGB16&#45;&gt;PixelCMYK16</title>
-<path fill="none" stroke="black" d="M451.832,-88.3606C462.615,-81.7841 475.593,-73.6731 487,-66 499.46,-57.6189 512.915,-47.9503 524.406,-39.4968"/>
-<polygon fill="black" stroke="black" points="526.807,-42.074 532.761,-33.3106 522.641,-36.4482 526.807,-42.074"/>
-<text text-anchor="middle" x="525" y="-58.3" font-family="sans-serif" font-size="8.00">convertPixel</text>
-</g>
-<!-- PixelRGBA16&#45;&gt;PixelRGB16 -->
-<g id="edge44" class="edge"><title>PixelRGBA16&#45;&gt;PixelRGB16</title>
-<path fill="none" stroke="black" d="M371.789,-29.3863C383.871,-35.2918 397.329,-43.4955 407,-54 412.378,-59.8422 416.636,-67.2266 419.915,-74.4406"/>
-<polygon fill="black" stroke="black" points="416.794,-76.0584 423.794,-84.0115 423.282,-73.4291 416.794,-76.0584"/>
-<text text-anchor="middle" x="449" y="-58.3" font-family="sans-serif" font-size="8.00">dropTransparency</text>
-</g>
-<!-- PixelRGBA8&#45;&gt;PixelRGB8 -->
-<g id="edge46" class="edge"><title>PixelRGBA8&#45;&gt;PixelRGB8</title>
-<path fill="none" stroke="black" d="M437.029,-372.038C433.845,-382.309 428.318,-394.571 419,-402 399.083,-417.88 332.208,-428.306 287.678,-433.672"/>
-<polygon fill="black" stroke="black" points="287.239,-430.2 277.712,-434.834 288.05,-437.153 287.239,-430.2"/>
-<text text-anchor="middle" x="463" y="-394.3" font-family="sans-serif" font-size="8.00">dropTransparency</text>
-</g>
-<!-- PixelRGBA8&#45;&gt;Pixel8 -->
-<g id="edge52" class="edge"><title>PixelRGBA8&#45;&gt;Pixel8</title>
-<path fill="none" stroke="black" d="M413.829,-342.599C399.476,-336.131 381.815,-327.451 367,-318 354.878,-310.267 342.394,-300.428 332.048,-291.673"/>
-<polygon fill="black" stroke="black" points="334.114,-288.833 324.258,-284.946 329.539,-294.131 334.114,-288.833"/>
-<text text-anchor="middle" x="392" y="-310.3" font-family="sans-serif" font-size="8.00">computeLuma</text>
-</g>
-<!-- PixelF -->
-<g id="node14" class="node"><title>PixelF</title>
-<ellipse fill="none" stroke="black" cx="106" cy="-186" rx="27" ry="18"/>
-<text text-anchor="middle" x="106" y="-184.3" font-family="sans-serif" font-size="8.00">PixelF</text>
-</g>
-<!-- PixelRGBF&#45;&gt;PixelF -->
-<g id="edge56" class="edge"><title>PixelRGBF&#45;&gt;PixelF</title>
-<path fill="none" stroke="black" d="M27.0137,-120.147C24.9943,-129.716 24.4635,-141.251 30,-150 38.9021,-164.067 54.9514,-172.745 70.015,-178.044"/>
-<polygon fill="black" stroke="black" points="69.0981,-181.424 79.6867,-181.06 71.1825,-174.741 69.0981,-181.424"/>
-<text text-anchor="middle" x="55" y="-142.3" font-family="sans-serif" font-size="8.00">computeLuma</text>
-</g>
-<!-- PixelYA16 -->
-<g id="node9" class="node"><title>PixelYA16</title>
-<ellipse fill="none" stroke="black" cx="259" cy="-102" rx="31.7878" ry="18"/>
-<text text-anchor="middle" x="259" y="-100.3" font-family="sans-serif" font-size="8.00">PixelYA16</text>
-</g>
-<!-- PixelYA16&#45;&gt;PixelRGBA16 -->
-<g id="edge8" class="edge"><title>PixelYA16&#45;&gt;PixelRGBA16</title>
-<path fill="none" stroke="black" d="M258.152,-83.5434C258.613,-73.883 260.687,-62.36 267,-54 275.273,-43.0444 287.722,-35.28 300.163,-29.8405"/>
-<polygon fill="black" stroke="black" points="301.586,-33.0421 309.607,-26.1198 299.02,-26.5294 301.586,-33.0421"/>
-<text text-anchor="middle" x="290" y="-58.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- PixelYA16&#45;&gt;Pixel16 -->
-<g id="edge48" class="edge"><title>PixelYA16&#45;&gt;Pixel16</title>
-<path fill="none" stroke="black" d="M229.98,-109.854C206.015,-117.845 177.897,-131.656 191,-150 199.293,-161.611 233.125,-171.835 260.175,-178.391"/>
-<polygon fill="black" stroke="black" points="259.609,-181.853 270.143,-180.72 261.201,-175.037 259.609,-181.853"/>
-<text text-anchor="middle" x="225" y="-142.3" font-family="sans-serif" font-size="8.00">dropTransparency</text>
-</g>
-<!-- PixelYA8 -->
-<g id="node11" class="node"><title>PixelYA8</title>
-<ellipse fill="none" stroke="black" cx="439" cy="-186" rx="28.8445" ry="18"/>
-<text text-anchor="middle" x="439" y="-184.3" font-family="sans-serif" font-size="8.00">PixelYA8</text>
-</g>
-<!-- PixelYA8&#45;&gt;PixelRGB8 -->
-<g id="edge12" class="edge"><title>PixelYA8&#45;&gt;PixelRGB8</title>
-<path fill="none" stroke="black" d="M464.762,-194.278C489.627,-203.81 525.815,-222.121 542,-252 574.918,-312.769 554.613,-358.387 501,-402 484.752,-415.217 355.671,-428.373 287.639,-434.476"/>
-<polygon fill="black" stroke="black" points="287.321,-430.99 277.669,-435.359 287.938,-437.963 287.321,-430.99"/>
-<text text-anchor="middle" x="580" y="-310.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- PixelYA8&#45;&gt;PixelRGBA8 -->
-<g id="edge10" class="edge"><title>PixelYA8&#45;&gt;PixelRGBA8</title>
-<path fill="none" stroke="black" d="M460.035,-198.84C467.824,-204.817 475.781,-212.68 480,-222 497.598,-260.871 496.093,-278.904 479,-318 476.725,-323.204 473.295,-328.013 469.411,-332.309"/>
-<polygon fill="black" stroke="black" points="466.792,-329.975 462.079,-339.464 471.681,-334.985 466.792,-329.975"/>
-<text text-anchor="middle" x="515" y="-268.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- PixelYA8&#45;&gt;Pixel8 -->
-<g id="edge50" class="edge"><title>PixelYA8&#45;&gt;Pixel8</title>
-<path fill="none" stroke="black" d="M412.102,-193.018C393.267,-198.789 368.145,-208.269 349,-222 340.05,-228.419 331.808,-237.196 325.098,-245.49"/>
-<polygon fill="black" stroke="black" points="322.247,-243.456 318.929,-253.518 327.797,-247.721 322.247,-243.456"/>
-<text text-anchor="middle" x="383" y="-226.3" font-family="sans-serif" font-size="8.00">dropTransparency</text>
-</g>
-<!-- PixelYA8&#45;&gt;Pixel8 -->
-<g id="edge62" class="edge"><title>PixelYA8&#45;&gt;Pixel8</title>
-<path fill="none" stroke="black" d="M434.558,-204.131C431.244,-214.175 425.744,-226.175 417,-234 397.039,-251.864 367.99,-260.893 344.899,-265.441"/>
-<polygon fill="black" stroke="black" points="344.002,-262.045 334.763,-267.23 345.219,-268.938 344.002,-262.045"/>
-<text text-anchor="middle" x="451" y="-226.3" font-family="sans-serif" font-size="8.00">computeLuma</text>
-</g>
-<!-- PixelF&#45;&gt;PixelRGBF -->
-<g id="edge14" class="edge"><title>PixelF&#45;&gt;PixelRGBF</title>
-<path fill="none" stroke="black" d="M100.45,-168.312C96.8232,-158.653 91.3784,-146.886 84,-138 78.5966,-131.492 71.7476,-125.606 64.8367,-120.568"/>
-<polygon fill="black" stroke="black" points="66.3898,-117.392 56.1539,-114.657 62.4504,-123.178 66.3898,-117.392"/>
-<text text-anchor="middle" x="115" y="-142.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- Pixel16&#45;&gt;PixelRGB16 -->
-<g id="edge18" class="edge"><title>Pixel16&#45;&gt;PixelRGB16</title>
-<path fill="none" stroke="black" d="M313.43,-172.019C326.239,-162.023 344.257,-148.532 361,-138 371.689,-131.277 383.756,-124.61 394.725,-118.875"/>
-<polygon fill="black" stroke="black" points="396.336,-121.982 403.628,-114.295 393.134,-115.757 396.336,-121.982"/>
-<text text-anchor="middle" x="384" y="-142.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- Pixel16&#45;&gt;PixelRGBA16 -->
-<g id="edge16" class="edge"><title>Pixel16&#45;&gt;PixelRGBA16</title>
-<path fill="none" stroke="black" d="M305.084,-168.741C307.903,-162.903 310.835,-156.272 313,-150 325.048,-115.091 333.609,-73.3023 338.424,-46.2333"/>
-<polygon fill="black" stroke="black" points="341.89,-46.732 340.143,-36.2822 334.992,-45.5405 341.89,-46.732"/>
-<text text-anchor="middle" x="353" y="-100.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- Pixel16&#45;&gt;PixelYA16 -->
-<g id="edge20" class="edge"><title>Pixel16&#45;&gt;PixelYA16</title>
-<path fill="none" stroke="black" d="M280.78,-170.7C275.635,-164.701 270.35,-157.469 267,-150 264.277,-143.93 262.473,-137.052 261.279,-130.438"/>
-<polygon fill="black" stroke="black" points="264.727,-129.827 259.862,-120.415 257.796,-130.807 264.727,-129.827"/>
-<text text-anchor="middle" x="290" y="-142.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- Pixel8&#45;&gt;PixelRGB8 -->
-<g id="edge24" class="edge"><title>Pixel8&#45;&gt;PixelRGB8</title>
-<path fill="none" stroke="black" d="M312.919,-288.095C319.136,-314.953 326.712,-366.057 306,-402 300.622,-411.332 291.773,-418.518 282.501,-423.926"/>
-<polygon fill="black" stroke="black" points="280.83,-420.85 273.581,-428.577 284.067,-427.057 280.83,-420.85"/>
-<text text-anchor="middle" x="342" y="-352.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- Pixel8&#45;&gt;PixelRGBA8 -->
-<g id="edge22" class="edge"><title>Pixel8&#45;&gt;PixelRGBA8</title>
-<path fill="none" stroke="black" d="M334.939,-272.185C360.073,-275.561 397.177,-284.15 421,-306 426.855,-311.37 431.048,-318.72 434.03,-326.054"/>
-<polygon fill="black" stroke="black" points="430.836,-327.531 437.387,-335.858 437.458,-325.263 430.836,-327.531"/>
-<text text-anchor="middle" x="452" y="-310.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- Pixel8&#45;&gt;PixelYA8 -->
-<g id="edge26" class="edge"><title>Pixel8&#45;&gt;PixelYA8</title>
-<path fill="none" stroke="black" d="M290.77,-255.865C280.734,-245.919 271.57,-232.553 280,-222 287.559,-212.538 356.092,-199.635 400.682,-192.122"/>
-<polygon fill="black" stroke="black" points="401.335,-195.562 410.626,-190.469 400.187,-188.657 401.335,-195.562"/>
-<text text-anchor="middle" x="303" y="-226.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- Pixel8&#45;&gt;PixelF -->
-<g id="edge28" class="edge"><title>Pixel8&#45;&gt;PixelF</title>
-<path fill="none" stroke="black" d="M281.145,-267.812C249.741,-264.331 196.969,-255.554 157,-234 145.577,-227.84 134.814,-218.473 126.146,-209.643"/>
-<polygon fill="black" stroke="black" points="128.492,-207.028 119.104,-202.117 123.381,-211.81 128.492,-207.028"/>
-<text text-anchor="middle" x="180" y="-226.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- Pixel8&#45;&gt;Pixel16 -->
-<g id="edge30" class="edge"><title>Pixel8&#45;&gt;Pixel16</title>
-<path fill="none" stroke="black" d="M282.206,-263.957C256.398,-257.327 219.359,-246.018 211,-234 196.025,-212.469 230.216,-199.429 259.604,-192.482"/>
-<polygon fill="black" stroke="black" points="260.687,-195.828 269.71,-190.275 259.193,-188.989 260.687,-195.828"/>
-<text text-anchor="middle" x="234" y="-226.3" font-family="sans-serif" font-size="8.00">promotePixel</text>
-</g>
-<!-- PixelCMYK16&#45;&gt;PixelRGB16 -->
-<g id="edge32" class="edge"><title>PixelCMYK16&#45;&gt;PixelRGB16</title>
-<path fill="none" stroke="black" d="M564.03,-35.4654C568.707,-45.2873 571.707,-57.2873 565,-66 553.678,-80.7091 507.858,-90.6423 472.496,-96.2857"/>
-<polygon fill="black" stroke="black" points="471.73,-92.862 462.373,-97.8319 472.787,-99.7817 471.73,-92.862"/>
-<text text-anchor="middle" x="590" y="-58.3" font-family="sans-serif" font-size="8.00">convertPixel</text>
-</g>
-<!-- PixelCMYK8&#45;&gt;PixelRGB8 -->
-<g id="edge34" class="edge"><title>PixelCMYK8&#45;&gt;PixelRGB8</title>
-<path fill="none" stroke="black" d="M257.173,-372.299C258.645,-381.28 259.584,-392.241 258,-402 257.535,-404.865 256.875,-407.811 256.1,-410.724"/>
-<polygon fill="black" stroke="black" points="252.737,-409.753 253.143,-420.34 259.427,-411.811 252.737,-409.753"/>
-<text text-anchor="middle" x="280" y="-394.3" font-family="sans-serif" font-size="8.00">convertPixel</text>
-</g>
-<!-- PixelYCbCr8&#45;&gt;PixelRGB8 -->
-<g id="edge36" class="edge"><title>PixelYCbCr8&#45;&gt;PixelRGB8</title>
-<path fill="none" stroke="black" d="M149.836,-372.162C150.645,-381.97 153.174,-393.727 160,-402 171.431,-415.854 189.112,-424.462 205.475,-429.768"/>
-<polygon fill="black" stroke="black" points="204.847,-433.23 215.426,-432.663 206.802,-426.509 204.847,-433.23"/>
-<text text-anchor="middle" x="182" y="-394.3" font-family="sans-serif" font-size="8.00">convertPixel</text>
-</g>
-<!-- PixelYCbCr8&#45;&gt;Pixel8 -->
-<g id="edge54" class="edge"><title>PixelYCbCr8&#45;&gt;Pixel8</title>
-<path fill="none" stroke="black" d="M174.688,-340.875C202.411,-326.136 247.432,-302.201 277.376,-286.281"/>
-<polygon fill="black" stroke="black" points="279.34,-289.201 286.527,-281.416 276.054,-283.02 279.34,-289.201"/>
-<text text-anchor="middle" x="263" y="-310.3" font-family="sans-serif" font-size="8.00">computeLuma</text>
-</g>
-</g>
-</svg>
diff --git a/src/Codec/Picture/BitWriter.hs b/src/Codec/Picture/BitWriter.hs
--- a/src/Codec/Picture/BitWriter.hs
+++ b/src/Codec/Picture/BitWriter.hs
@@ -26,7 +26,7 @@
                               ) where
 
 #if !MIN_VERSION_base(4,8,0)
-import Control.Applicative( (<$>), (<*>) )
+import Control.Applicative( (<*>) )
 #endif
 
 import Data.STRef
diff --git a/src/Codec/Picture/Jpg.hs b/src/Codec/Picture/Jpg.hs
--- a/src/Codec/Picture/Jpg.hs
+++ b/src/Codec/Picture/Jpg.hs
@@ -16,7 +16,7 @@
 import Control.Applicative( pure )
 #endif
 
-import Control.Applicative( (<$>) )
+import Control.Applicative( (<|>), (<$>) )
 
 import Control.Arrow( (>>>) )
 import Control.Monad( when, forM_ )
@@ -234,7 +234,8 @@
     , quantizationMatrices  :: !(V.Vector (MacroBlock Int16))
     , currentRestartInterv  :: !Int
     , currentFrame          :: Maybe JpgFrameHeader
-    , minimumComponentIndex :: !Int
+    , app14Marker           :: !(Maybe JpgAdobeApp14)
+    , componentIndexMapping :: ![(Word8, Int)]
     , isProgressive         :: !Bool
     , maximumHorizontalResolution :: !Int
     , maximumVerticalResolution   :: !Int
@@ -258,7 +259,8 @@
     , quantizationMatrices = V.replicate 4 (VS.replicate (8 * 8) 1)
     , currentRestartInterv = -1
     , currentFrame         = Nothing
-    , minimumComponentIndex = 1
+    , componentIndexMapping = []
+    , app14Marker = Nothing
     , isProgressive        = False
     , maximumHorizontalResolution = 0
     , maximumVerticalResolution   = 0
@@ -268,6 +270,8 @@
 -- | This pseudo interpreter interpret the Jpg frame for the huffman,
 -- quant table and restart interval parameters.
 jpgMachineStep :: JpgFrame -> JpgScripter s ()
+jpgMachineStep (JpgAdobeAPP14 app14) = modify $ \s ->
+    s { app14Marker = Just app14 }
 jpgMachineStep (JpgAppFrame _ _) = pure ()
 jpgMachineStep (JpgExtension _ _) = pure ()
 jpgMachineStep (JpgScanBlob hdr raw_data) = do
@@ -282,13 +286,15 @@
 
         
         scanSpecifier scanCount scanSpec = do
-            minimumIndex <- gets minimumComponentIndex
+            compMapping <- gets componentIndexMapping
+            comp <- case lookup (componentSelector scanSpec) compMapping of
+                Nothing -> fail "Jpg decoding error - bad component selector in blob."
+                Just v -> return v
             let maximumHuffmanTable = 4
                 dcIndex = min (maximumHuffmanTable - 1) 
                             . fromIntegral $ dcEntropyCodingTable scanSpec
                 acIndex = min (maximumHuffmanTable - 1)
                             . fromIntegral $ acEntropyCodingTable scanSpec
-                comp = fromIntegral (componentSelector scanSpec) - minimumIndex
 
             dcTree <- gets $ (V.! dcIndex) . dcDecoderTables
             acTree <- gets $ (V.! acIndex) . acDecoderTables
@@ -335,8 +341,8 @@
 
 jpgMachineStep (JpgScans kind hdr) = modify $ \s ->
    s { currentFrame = Just hdr
-     , minimumComponentIndex =
-          fromIntegral $ minimum [componentIdentifier comp | comp <- jpgComponents hdr]
+     , componentIndexMapping =
+          [(componentIdentifier comp, ix) | (ix, comp) <- zip [0..] $ jpgComponents hdr]
      , isProgressive = case kind of
             JpgProgressiveDCTHuffman -> True
             _ -> False
@@ -374,7 +380,7 @@
 
 unpackerDecision :: Int -> (Int, Int) -> Unpacker s
 unpackerDecision 1 (1, 1) = unpack444Y
-unpackerDecision _ (1, 1) = unpack444Ycbcr
+unpackerDecision 3 (1, 1) = unpack444Ycbcr
 unpackerDecision _ (2, 1) = unpack421Ycbcr
 unpackerDecision compCount (xScalingFactor, yScalingFactor) =
     unpackMacroBlock compCount xScalingFactor yScalingFactor
@@ -383,7 +389,7 @@
             -> V.Vector (MacroBlock Int16)
             -> [([(JpgUnpackerParameter, Unpacker s)], L.ByteString)]
             -> MutableImage s PixelYCbCr8 -- ^ Result image to write into
-            -> ST s ()
+            -> ST s (MutableImage s PixelYCbCr8)
 decodeImage frame quants lst outImage = do
   let compCount = length $ jpgComponents frame
   zigZagArray <- createEmptyMutableMacroBlock
@@ -434,6 +440,8 @@
         else
           lift $ unpack compIdx (x * maxiW + xd) (y * maxiH + yd) outImage block
 
+  return outImage
+
   where imgComponentCount = length $ jpgComponents frame
 
         imgWidth = fromIntegral $ jpgWidth frame
@@ -454,6 +462,58 @@
 gatherScanInfo :: JpgImage -> (JpgFrameKind, JpgFrameHeader)
 gatherScanInfo img = head [(a, b) | JpgScans a b <- jpgFrame img]
 
+dynamicOfColorSpace :: (Monad m)
+                    => Maybe JpgColorSpace -> Int -> Int -> VS.Vector Word8
+                    -> m DynamicImage
+dynamicOfColorSpace Nothing _ _ _ = fail "Unknown color space"
+dynamicOfColorSpace (Just color) w h imgData = case color of
+  JpgColorSpaceCMYK -> return . ImageCMYK8 $ Image w h imgData
+  JpgColorSpaceYCCK ->
+     let ymg = Image w h $ VS.map (255-) imgData :: Image PixelYCbCrK8 in
+     return . ImageCMYK8 $ convertImage ymg
+  JpgColorSpaceYCbCr -> return . ImageYCbCr8 $ Image w h imgData
+  JpgColorSpaceRGB -> return . ImageRGB8 $ Image w h imgData
+  JpgColorSpaceYA -> return . ImageYA8 $ Image w h imgData
+  JpgColorSpaceY -> return . ImageY8 $ Image w h imgData
+  colorSpace -> fail $ "Wrong color space : " ++ show colorSpace
+
+colorSpaceOfAdobe :: Int -> JpgAdobeApp14 -> Maybe JpgColorSpace
+colorSpaceOfAdobe compCount app = case (compCount, _adobeTransform app) of
+  (3, AdobeYCbCr) -> pure JpgColorSpaceYCbCr
+  (1, AdobeUnknown) -> pure JpgColorSpaceY
+  (3, AdobeUnknown) -> pure JpgColorSpaceRGB
+  (4, AdobeYCck) -> pure JpgColorSpaceYCCK
+  {-(4, AdobeUnknown) -> pure JpgColorSpaceCMYKInverted-}
+  _ -> Nothing
+
+colorSpaceOfState :: JpgDecoderState -> Maybe JpgColorSpace
+colorSpaceOfState st = do
+  hdr <- currentFrame st
+  let compStr = [toEnum . fromEnum $ componentIdentifier comp
+                        | comp <- jpgComponents hdr]
+      app14 = do
+        marker <- app14Marker st
+        colorSpaceOfAdobe (length compStr) marker
+  app14 <|> colorSpaceOfComponentStr compStr
+
+
+colorSpaceOfComponentStr :: String -> Maybe JpgColorSpace
+colorSpaceOfComponentStr s = case s of
+  [_] -> pure  JpgColorSpaceY
+  [_,_] -> pure  JpgColorSpaceYA
+  "\0\1\2" -> pure  JpgColorSpaceYCbCr
+  "\1\2\3" -> pure  JpgColorSpaceYCbCr
+  "RGB" -> pure  JpgColorSpaceRGB
+  "YCc" -> pure  JpgColorSpaceYCC
+  [_,_,_] -> pure  JpgColorSpaceYCbCr
+
+  "RGBA" -> pure  JpgColorSpaceRGBA
+  "YCcA" -> pure  JpgColorSpaceYCCA
+  "CMYK" -> pure  JpgColorSpaceCMYK
+  "YCcK" -> pure  JpgColorSpaceYCCK
+  [_,_,_,_] -> pure  JpgColorSpaceCMYK
+  _ -> Nothing
+
 -- | Try to decompress a jpeg file and decompress. The colorspace is still
 -- YCbCr if you want to perform computation on the luma part. You can
 -- convert it to RGB using 'convertImage' from the 'ColorSpaceConvertible'
@@ -463,49 +523,61 @@
 --
 --    * PixelY8
 --
+--    * PixelYA8
+--
+--    * PixelRGB8
+--
 --    * PixelYCbCr8
 --
 decodeJpeg :: B.ByteString -> Either String DynamicImage
 decodeJpeg file = case runGetStrict get file of
   Left err -> Left err
-  Right img -> case (compCount, imgKind) of
-                 (_, Nothing) -> Left "Unknown Jpg kind"
-                 (3, Just ProgressiveDCT) -> Right . ImageYCbCr8 $ decodeProgressive
-                 (1, Just BaseLineDCT) -> Right . ImageY8 $ Image imgWidth imgHeight pixelData
-                 (3, Just BaseLineDCT) -> Right . ImageYCbCr8 $ Image imgWidth imgHeight pixelData
-                 _ -> Left "Wrong component count"
+  Right img -> case imgKind of
+     Just BaseLineDCT ->
+       let (st, arr) = decodeBaseline in
+       dynamicOfColorSpace (colorSpaceOfState st) imgWidth imgHeight arr
+     Just ProgressiveDCT ->
+       let (st, arr) = decodeProgressive in
+       dynamicOfColorSpace (colorSpaceOfState st) imgWidth imgHeight arr
+     _ -> Left "Unkown JPG kind"
+    where
+      compCount = length $ jpgComponents scanInfo
+      (_,scanInfo) = gatherScanInfo img
 
-      where compCount = length $ jpgComponents scanInfo
-            (_,scanInfo) = gatherScanInfo img
+      imgKind = gatherImageKind $ jpgFrame img
+      imgWidth = fromIntegral $ jpgWidth scanInfo
+      imgHeight = fromIntegral $ jpgHeight scanInfo
 
-            imgKind = gatherImageKind $ jpgFrame img
-            imgWidth = fromIntegral $ jpgWidth scanInfo
-            imgHeight = fromIntegral $ jpgHeight scanInfo
+      imageSize = imgWidth * imgHeight * compCount
 
-            imageSize = imgWidth * imgHeight * compCount
 
-            decodeProgressive = runST $ do
-                let (st, wrotten) =
-                        execRWS (mapM_ jpgMachineStep (jpgFrame img)) () emptyDecoderState
-                    Just fHdr = currentFrame st
-                progressiveUnpack
-                    (maximumHorizontalResolution st, maximumVerticalResolution st)
-                    fHdr
-                    (quantizationMatrices st)
-                    wrotten >>= unsafeFreezeImage
+      decodeProgressive = runST $ do
+        let (st, wrotten) =
+               execRWS (mapM_ jpgMachineStep (jpgFrame img)) () emptyDecoderState
+            Just fHdr = currentFrame st
+        fimg <-
+            progressiveUnpack
+                (maximumHorizontalResolution st, maximumVerticalResolution st)
+                fHdr
+                (quantizationMatrices st)
+                wrotten
+        frozen <- unsafeFreezeImage fimg
+        return (st, imageData frozen)
 
-            pixelData = runST $ do
-                let (st, wrotten) =
-                        execRWS (mapM_ jpgMachineStep (jpgFrame img)) () emptyDecoderState
-                    Just fHdr = currentFrame st
-                resultImage <- M.new imageSize
-                let wrapped = MutableImage imgWidth imgHeight resultImage
-                decodeImage 
-                    fHdr
-                    (quantizationMatrices st)
-                    wrotten
-                    wrapped
-                VS.unsafeFreeze resultImage
+
+      decodeBaseline = runST $ do
+        let (st, wrotten) =
+              execRWS (mapM_ jpgMachineStep (jpgFrame img)) () emptyDecoderState
+            Just fHdr = currentFrame st
+        resultImage <- M.new imageSize
+        let wrapped = MutableImage imgWidth imgHeight resultImage
+        fImg <- decodeImage 
+            fHdr
+            (quantizationMatrices st)
+            wrotten
+            wrapped
+        frozen <- unsafeFreezeImage fImg
+        return (st, imageData frozen)
 
 extractBlock :: Image PixelYCbCr8       -- ^ Source image
              -> MutableMacroBlock s Int16      -- ^ Mutable block where to put extracted block
diff --git a/src/Codec/Picture/Jpg/Common.hs b/src/Codec/Picture/Jpg/Common.hs
--- a/src/Codec/Picture/Jpg/Common.hs
+++ b/src/Codec/Picture/Jpg/Common.hs
@@ -20,7 +20,7 @@
     ) where
 
 #if !MIN_VERSION_base(4,8,0)
-import Control.Applicative( (<$>), pure )
+import Control.Applicative( pure )
 #endif
 
 import Control.Applicative( (<$>) )
diff --git a/src/Codec/Picture/Jpg/Types.hs b/src/Codec/Picture/Jpg/Types.hs
--- a/src/Codec/Picture/Jpg/Types.hs
+++ b/src/Codec/Picture/Jpg/Types.hs
@@ -16,13 +16,16 @@
                               , JpgHuffmanTableSpec( .. )
                               , JpgImageKind( .. )
                               , JpgScanSpecification( .. )
+                              , JpgColorSpace( .. )
+                              , AdobeTransform( .. )
+                              , JpgAdobeApp14( .. )
                               , calculateSize
                               , dctBlockSize
                               ) where
 
 
 #if !MIN_VERSION_base(4,8,0)
-import Control.Applicative( (<*>))
+import Control.Applicative( pure, (<*>))
 #endif
 
 import Control.Applicative( (<$>) )
@@ -36,6 +39,7 @@
 import qualified Data.Vector.Storable as VS
 import qualified Data.Vector.Storable.Mutable as M
 import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as BC
 import qualified Data.ByteString.Lazy as L
 
 import Data.Int( Int16 )
@@ -54,6 +58,7 @@
                       , putWord8
                       , putWord16be
                       , putLazyByteString
+                      , putByteString
                       )
 
 import Codec.Picture.InternalHelper
@@ -96,6 +101,7 @@
 
 data JpgFrame =
       JpgAppFrame        !Word8 B.ByteString
+    | JpgAdobeAPP14      !JpgAdobeApp14
     | JpgExtension       !Word8 B.ByteString
     | JpgQuantTable      ![JpgQuantTableSpec]
     | JpgHuffmanTable    ![(JpgHuffmanTableSpec, HuffmanPackedTree)]
@@ -104,6 +110,67 @@
     | JpgIntervalRestart !Word16
     deriving Show
 
+data JpgColorSpace
+  = JpgColorSpaceYCbCr
+  | JpgColorSpaceYCC
+  | JpgColorSpaceY
+  | JpgColorSpaceYA
+  | JpgColorSpaceYCCA
+  | JpgColorSpaceYCCK
+  | JpgColorSpaceCMYK
+  | JpgColorSpaceRGB
+  | JpgColorSpaceRGBA
+  deriving Show
+
+data AdobeTransform
+  = AdobeUnknown    -- ^ Value 0
+  | AdobeYCbCr      -- ^ value 1
+  | AdobeYCck       -- ^ value 2
+  deriving Show
+
+data JpgAdobeApp14 = JpgAdobeApp14
+  { _adobeDctVersion :: !Word16
+  , _adobeFlag0      :: !Word16
+  , _adobeFlag1      :: !Word16
+  , _adobeTransform  :: !AdobeTransform
+  }
+  deriving Show
+
+instance Binary AdobeTransform where
+  put v = case v of
+    AdobeUnknown -> putWord8 0
+    AdobeYCbCr -> putWord8 1
+    AdobeYCck -> putWord8 2
+
+  get = do
+    v <- getWord8
+    pure $ case v of
+      0 -> AdobeUnknown
+      1 -> AdobeYCbCr
+      2 -> AdobeYCck
+      _ -> AdobeUnknown
+
+instance Binary JpgAdobeApp14 where
+  get = do
+    let sig = BC.pack "Adobe"
+    fileSig <- getByteString 5
+    when (fileSig /= sig) $
+       fail "Invalid Adobe APP14 marker"
+    version <- getWord16be
+    when (version /= 100) $
+       fail $ "Invalid Adobe APP14 version " ++ show version
+    JpgAdobeApp14 version
+                  <$> getWord16be
+                  <*> getWord16be <*> get
+
+  put (JpgAdobeApp14 v f0 f1 t) = do
+    putByteString $ BC.pack "Adobe"
+    putWord16be v
+    putWord16be f0
+    putWord16be f1
+    put t
+
+
 data JpgFrameHeader = JpgFrameHeader
     { jpgFrameHeaderLength   :: !Word16
     , jpgSamplePrecision     :: !Word8
@@ -288,6 +355,7 @@
     getByteString (fromIntegral size - 2)
 
 putFrame :: JpgFrame -> Put
+putFrame (JpgAdobeAPP14 _adobe) = return ()
 putFrame (JpgAppFrame appCode str) =
     put (JpgAppSegment appCode) >> putWord16be (fromIntegral $ B.length str) >> put str
 putFrame (JpgExtension appCode str) =
@@ -327,6 +395,12 @@
                   vNext = str `L.index` (n + 1)
                   isReset = 0xD0 <= vNext && vNext <= 0xD7
 
+parseAdobe14 :: B.ByteString -> [JpgFrame] -> [JpgFrame]
+parseAdobe14 str lst = go where
+  go = case runGetStrict get str of
+    Left _err -> lst
+    Right app14 -> JpgAdobeAPP14 app14 : lst
+
 parseFrames :: Get [JpgFrame]
 parseFrames = do
     kind <- get
@@ -340,6 +414,8 @@
 
     case kind of
         JpgEndOfImage -> return []
+        JpgAppSegment 14 ->
+            parseAdobe14 <$> takeCurrentFrame <*> parseNextFrame
         JpgAppSegment c ->
             (\frm lst -> JpgAppFrame c frm : lst) <$> takeCurrentFrame <*> parseNextFrame
         JpgExtensionSegment c ->
@@ -388,7 +464,7 @@
     aux JpgStartOfScan = 0xDA
     aux JpgRestartInterval = 0xDD
     aux (JpgRestartIntervalEnd v) = v
-    aux (JpgAppSegment a) = a
+    aux (JpgAppSegment a) = (a + 0xE0)
     aux (JpgExtensionSegment a) = a
 
 data JpgImageKind = BaseLineDCT | ProgressiveDCT
@@ -419,7 +495,7 @@
             0xDB -> JpgQuantizationTable
             0xDD -> JpgRestartInterval
             a | a >= 0xF0 -> JpgExtensionSegment a
-              | a >= 0xE0 -> JpgAppSegment a
+              | a >= 0xE0 -> JpgAppSegment (a - 0xE0)
               | a >= 0xD0 && a <= 0xD7 -> JpgRestartIntervalEnd a
               | otherwise -> error ("Invalid frame marker (" ++ show a ++ ")")
 
diff --git a/src/Codec/Picture/Types.hs b/src/Codec/Picture/Types.hs
--- a/src/Codec/Picture/Types.hs
+++ b/src/Codec/Picture/Types.hs
@@ -19,6 +19,7 @@
 
                             -- ** Image functions
                           , createMutableImage
+                          , newMutableImage
                           , freezeImage
                           , unsafeFreezeImage
                           , thawImage
@@ -39,6 +40,7 @@
                           , PixelCMYK8( .. )
                           , PixelCMYK16( .. )
                           , PixelYCbCr8( .. )
+                          , PixelYCbCrK8( .. )
 
                           -- * Type classes
                           , ColorConvertible( .. )
@@ -53,6 +55,7 @@
                           , pixelMapXY
                           , pixelFold
                           , pixelFoldM
+                          , pixelFoldMap
 
                           , dynamicMap
                           , dynamicPixelMap
@@ -90,6 +93,11 @@
                           , unsafeWritePixelBetweenAt
                           ) where
 
+#if !MIN_VERSION_base(4,8,0)
+import Data.Monoid( Monoid, mempty )
+#endif
+
+import Data.Monoid( (<>) )
 import Control.Monad( foldM, liftM, ap )
 import Control.DeepSeq( NFData( .. ) )
 import Control.Monad.ST( runST )
@@ -98,7 +106,6 @@
 import Foreign.Storable ( Storable )
 import Data.Bits( unsafeShiftL, unsafeShiftR, (.|.), (.&.) )
 import Data.Word( Word8, Word16, Word32, Word64 )
-import Data.List( foldl' )
 import Data.Vector.Storable ( (!) )
 import qualified Data.Vector.Storable as V
 import qualified Data.Vector.Storable.Mutable as M
@@ -319,9 +326,19 @@
                    -> Int -- ^ Height
                    -> px  -- ^ Background color
                    -> m (MutableImage (PrimState m) px)
+{-# INLINE createMutableImage #-}
 createMutableImage width height background =
    unsafeThawImage $ generateImage (\_ _ -> background) width height
 
+-- | Create a mutable image with garbage as content. All data
+-- is uninitialized.
+newMutableImage :: forall px m. (Pixel px, PrimMonad m)
+                => Int -- ^ Width
+                -> Int -- ^ Height
+                -> m (MutableImage (PrimState m) px)
+newMutableImage w h = MutableImage w h `liftM` M.new (w * h * compCount)
+  where compCount = componentCount (undefined :: px)
+
 instance NFData (MutableImage s a) where
     rnf (MutableImage width height dat) = width  `seq`
                                           height `seq`
@@ -390,7 +407,7 @@
 -- without caring about colorspace, you can use the following snippet.
 --
 -- > dynSquare :: DynamicImage -> DynamicImage
--- > dynSquare = dynMap squareImage
+-- > dynSquare = dynamicPixelMap squareImage
 -- >
 -- > squareImage :: Pixel a => Image a -> Image a
 -- > squareImage img = generateImage (\x y -> pixelAt img x y) edge edge
@@ -481,6 +498,22 @@
                            {-# UNPACK #-} !Pixel8 -- Blue
                deriving (Eq, Ord, Show)
 
+-- | Pixel type storing value for the YCCK color space:
+--
+-- * Y (Luminance)
+--
+-- * Cb
+--
+-- * Cr
+--
+-- * Black
+--
+data PixelYCbCrK8 = PixelYCbCrK8 {-# UNPACK #-} !Pixel8
+                                 {-# UNPACK #-} !Pixel8
+                                 {-# UNPACK #-} !Pixel8
+                                 {-# UNPACK #-} !Pixel8
+               deriving (Eq, Ord, Show)
+
 -- | Pixel type storing 16bit red, green and blue (RGB) information.
 -- Values are stored in the following order:
 --
@@ -724,9 +757,9 @@
   where compCount = componentCount (undefined :: a)
         generated = runST $ do
             arr <- M.new (w * h * compCount)
-            let lineGenerator _ y | y >= h = return ()
-                lineGenerator lineIdx y = column lineIdx 0
-                  where column idx x | x >= w = lineGenerator idx $ y + 1
+            let lineGenerator _ !y | y >= h = return ()
+                lineGenerator !lineIdx y = column lineIdx 0
+                  where column !idx !x | x >= w = lineGenerator idx $ y + 1
                         column idx x = do
                             unsafeWritePixel arr idx $ f x y
                             column (idx + compCount) $ x + 1
@@ -795,14 +828,23 @@
 -- | Fold over the pixel of an image with a raster scan order:
 -- from top to bottom, left to right
 {-# INLINE pixelFold #-}
-pixelFold :: (Pixel pixel)
+pixelFold :: forall acc pixel. (Pixel pixel)
           => (acc -> Int -> Int -> pixel -> acc) -> acc -> Image pixel -> acc
 pixelFold f initialAccumulator img@(Image { imageWidth = w, imageHeight = h }) =
-  foldl' columnFold initialAccumulator [0 .. h - 1]
+  columnFold 0 initialAccumulator 0
     where
-      pixelFolder y acc x = f acc x y $ pixelAt img x y
-      columnFold lineAcc y = foldl' (pixelFolder y) lineAcc [0 .. w - 1]
+      !compCount = componentCount (undefined :: pixel)
+      !vec = imageData img
 
+      lfold !y acc !x !idx
+        | x >= w = columnFold (y + 1) acc idx
+        | otherwise = 
+            lfold y (f acc x y $ unsafePixelAt vec idx) (x + 1) (idx + compCount)
+
+      columnFold !y lineAcc !readIdx
+        | y >= h = lineAcc
+        | otherwise = lfold y lineAcc 0 readIdx
+
 -- | Fold over the pixel of an image with a raster scan order:
 -- from top to bottom, left to right, carrying out a state
 pixelFoldM :: (Pixel pixel, Monad m)
@@ -817,6 +859,20 @@
       pixelFolder y acc x = action acc x y $ pixelAt img x y
       columnFold lineAcc y = lineFold lineAcc w (pixelFolder y)
 
+
+-- | Fold over the pixel of an image with a raster scan order:
+-- from top to bottom, left to right. This functions is analog
+-- to the foldMap from the 'Foldable' typeclass, but due to the
+-- Pixel constraint, Image cannot be made an instance of it.
+pixelFoldMap :: forall m px. (Pixel px, Monoid m) => (px -> m) -> Image px -> m
+pixelFoldMap f Image { imageWidth = w, imageHeight = h, imageData = vec } = folder 0
+  where
+    compCount = componentCount (undefined :: px)
+    maxi = w * h * compCount
+
+    folder idx | idx >= maxi = mempty
+    folder idx = f (unsafePixelAt vec idx) <> folder (idx + compCount)
+
 -- | `map` equivalent for an image, working at the pixel level.
 -- Little example : a brightness function for an rgb image
 --
@@ -1921,14 +1977,109 @@
   convertPixel (PixelCMYK8 c m y k) =
       PixelRGB8 (clampWord8 r) (clampWord8 g) (clampWord8 b)
     where
-          clampWord8 = fromIntegral . (`unsafeShiftR` 8)
-          ik :: Int
-          ik = 255 - fromIntegral k
+      clampWord8 = fromIntegral . max 0 . min 255 . (`div` 255)
+      ik :: Int
+      ik = 255 - fromIntegral k
 
-          r = (255 - fromIntegral c) * ik
-          g = (255 - fromIntegral m) * ik
-          b = (255 - fromIntegral y) * ik
+      r = (255 - fromIntegral c) * ik
+      g = (255 - fromIntegral m) * ik
+      b = (255 - fromIntegral y) * ik
 
+--------------------------------------------------
+----            PixelYCbCrK8 instances
+--------------------------------------------------
+instance Pixel PixelYCbCrK8 where
+    type PixelBaseComponent PixelYCbCrK8 = Word8
+
+    {-# INLINE pixelOpacity #-}
+    pixelOpacity = const maxBound
+
+    {-# INLINE mixWith #-}
+    mixWith f (PixelYCbCrK8 ya cba cra ka) (PixelYCbCrK8 yb cbb crb kb) =
+        PixelYCbCrK8 (f 0 ya yb) (f 1 cba cbb) (f 2 cra crb) (f 3 ka kb)
+
+    {-# INLINE colorMap #-}
+    colorMap f (PixelYCbCrK8 y cb cr k) = PixelYCbCrK8 (f y) (f cb) (f cr) (f k)
+
+    {-# INLINE componentCount #-}
+    componentCount _ = 4
+
+    {-# INLINE pixelAt #-}
+    pixelAt image@(Image { imageData = arr }) x y =
+        PixelYCbCrK8 (arr ! (baseIdx + 0)) (arr ! (baseIdx + 1))
+                     (arr ! (baseIdx + 2)) (arr ! (baseIdx + 3))
+        where baseIdx = pixelBaseIndex image x y
+
+    {-# INLINE readPixel #-}
+    readPixel image@(MutableImage { mutableImageData = arr }) x y = do
+        yv <- arr `M.read` baseIdx
+        cbv <- arr `M.read` (baseIdx + 1)
+        crv <- arr `M.read` (baseIdx + 2)
+        kv <- arr `M.read` (baseIdx + 3)
+        return $ PixelYCbCrK8 yv cbv crv kv
+        where baseIdx = mutablePixelBaseIndex image x y
+
+    {-# INLINE writePixel #-}
+    writePixel image@(MutableImage { mutableImageData = arr }) x y (PixelYCbCrK8 yv cbv crv kv) = do
+        let baseIdx = mutablePixelBaseIndex image x y
+        (arr `M.write` (baseIdx + 0)) yv
+        (arr `M.write` (baseIdx + 1)) cbv
+        (arr `M.write` (baseIdx + 2)) crv
+        (arr `M.write` (baseIdx + 3)) kv
+
+    {-# INLINE unsafePixelAt #-}
+    unsafePixelAt v idx =
+        PixelYCbCrK8 (V.unsafeIndex v idx)
+                     (V.unsafeIndex v $ idx + 1)
+                     (V.unsafeIndex v $ idx + 2)
+                     (V.unsafeIndex v $ idx + 3)
+
+    {-# INLINE unsafeReadPixel #-}
+    unsafeReadPixel vec idx =
+      PixelYCbCrK8 `liftM` M.unsafeRead vec idx
+                   `ap` M.unsafeRead vec (idx + 1)
+                   `ap` M.unsafeRead vec (idx + 2)
+                   `ap` M.unsafeRead vec (idx + 3)
+
+    {-# INLINE unsafeWritePixel #-}
+    unsafeWritePixel v idx (PixelYCbCrK8 y cb cr k) =
+        M.unsafeWrite v idx y >> M.unsafeWrite v (idx + 1) cb
+                              >> M.unsafeWrite v (idx + 2) cr
+                              >> M.unsafeWrite v (idx + 3) k
+
+instance ColorSpaceConvertible PixelYCbCrK8 PixelRGB8 where
+  convertPixel (PixelYCbCrK8 y cb cr _k) = PixelRGB8 (clamp r) (clamp g) (clamp b)
+    where
+      tof :: Word8 -> Float
+      tof v = fromIntegral v
+
+      clamp :: Float -> Word8
+      clamp = floor . max 0 . min 255
+
+      yf = tof y
+
+      r = yf + 1.402 * tof cr - 179.456
+      g = yf - 0.3441363 * tof cb - 0.71413636 * tof cr + 135.4589
+      b = yf + 1.772 * tof cb - 226.816
+
+instance ColorSpaceConvertible PixelYCbCrK8 PixelCMYK8 where
+  convertPixel (PixelYCbCrK8 y cb cr k) = PixelCMYK8 c m ye k
+    where
+      tof :: Word8 -> Float
+      tof v = fromIntegral v
+
+      clamp :: Float -> Word8
+      clamp = floor . max 0 . min 255
+
+      yf = tof y
+
+      r = yf + 1.402 * tof cr - 179.456
+      g = yf - 0.3441363 * tof cb - 0.71413636 * tof cr + 135.4589
+      b = yf + 1.772 * tof cb - 226.816
+
+      c = clamp $ 255 - r
+      m = clamp $ 255 - g
+      ye = clamp $ 255 - b
 
 {-# SPECIALIZE integralRGBToCMYK :: (Word8 -> Word8 -> Word8 -> Word8 -> b)
                                  -> (Word8, Word8, Word8) -> b #-}
