Read color space info from raw exif data

b/35516531

Change-Id: I86ad40b059f300375b0293bd96ecb967811f3a07
Reviewed-on: https://skia-review.googlesource.com/8951
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Matt Sarett <msarett@google.com>
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
index 995aaa6..1ed76a7 100644
--- a/src/codec/SkJpegCodec.cpp
+++ b/src/codec/SkJpegCodec.cpp
@@ -189,8 +189,8 @@
     return iccData;
 }
 
-bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
-        JpegDecoderMgr** decoderMgrOut) {
+bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, JpegDecoderMgr** decoderMgrOut,
+        sk_sp<SkColorSpace> defaultColorSpace) {
 
     // Create a JpegDecoderMgr to own all of the decompress information
     std::unique_ptr<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
@@ -251,8 +251,7 @@
             }
         }
         if (!colorSpace) {
-            // Treat unmarked jpegs as sRGB.
-            colorSpace = SkColorSpace::MakeSRGB();
+            colorSpace = defaultColorSpace;
         }
 
         const int width = decoderMgr->dinfo()->image_width;
@@ -269,9 +268,13 @@
 }
 
 SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) {
+    return SkJpegCodec::NewFromStream(stream, SkColorSpace::MakeSRGB());
+}
+
+SkCodec* SkJpegCodec::NewFromStream(SkStream* stream, sk_sp<SkColorSpace> defaultColorSpace) {
     std::unique_ptr<SkStream> streamDeleter(stream);
     SkCodec* codec = nullptr;
-    if (ReadHeader(stream,  &codec, nullptr)) {
+    if (ReadHeader(stream,  &codec, nullptr, std::move(defaultColorSpace))) {
         // Codec has taken ownership of the stream, we do not need to delete it
         SkASSERT(codec);
         streamDeleter.release();
@@ -353,7 +356,7 @@
 
 bool SkJpegCodec::onRewind() {
     JpegDecoderMgr* decoderMgr = nullptr;
-    if (!ReadHeader(this->stream(), nullptr, &decoderMgr)) {
+    if (!ReadHeader(this->stream(), nullptr, &decoderMgr, nullptr)) {
         return fDecoderMgr->returnFalse("onRewind");
     }
     SkASSERT(nullptr != decoderMgr);
diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h
index af795ce..b6d7528 100644
--- a/src/codec/SkJpegCodec.h
+++ b/src/codec/SkJpegCodec.h
@@ -62,6 +62,11 @@
 private:
 
     /*
+     * Allows SkRawCodec to communicate the color space from the exif data.
+     */
+    static SkCodec* NewFromStream(SkStream*, sk_sp<SkColorSpace> defaultColorSpace);
+
+    /*
      * Read enough of the stream to initialize the SkJpegCodec.
      * Returns a bool representing success or failure.
      *
@@ -79,9 +84,12 @@
      * codecOut will take ownership of it in the case where we created a codec.
      * Ownership is unchanged when we set decoderMgrOut.
      *
+     * @param defaultColorSpace
+     * If the jpeg does not have an embedded color space, the image data should
+     * be tagged with this color space.
      */
     static bool ReadHeader(SkStream* stream, SkCodec** codecOut,
-            JpegDecoderMgr** decoderMgrOut);
+            JpegDecoderMgr** decoderMgrOut, sk_sp<SkColorSpace> defaultColorSpace);
 
     /*
      * Creates an instance of the decoder
@@ -134,6 +142,8 @@
 
     std::unique_ptr<SkSwizzler>        fSwizzler;
 
+    friend class SkRawCodec;
+
     typedef SkCodec INHERITED;
 };
 
diff --git a/src/codec/SkRawCodec.cpp b/src/codec/SkRawCodec.cpp
index 1684a168..0a1cea1 100644
--- a/src/codec/SkRawCodec.cpp
+++ b/src/codec/SkRawCodec.cpp
@@ -648,6 +648,19 @@
     ::piex::PreviewImageData imageData;
     if (::piex::IsRaw(&piexStream)) {
         ::piex::Error error = ::piex::GetPreviewImageData(&piexStream, &imageData);
+        if (error == ::piex::Error::kFail) {
+            return nullptr;
+        }
+
+        sk_sp<SkColorSpace> colorSpace;
+        switch (imageData.color_space) {
+            case ::piex::PreviewImageData::kSrgb:
+                colorSpace = SkColorSpace::MakeSRGB();
+                break;
+            case ::piex::PreviewImageData::kAdobeRgb:
+                colorSpace = SkColorSpace_Base::MakeNamed(SkColorSpace_Base::kAdobeRGB_Named);
+                break;
+        }
 
         //  Theoretically PIEX can return JPEG compressed image or uncompressed RGB image. We only
         //  handle the JPEG compressed preview image here.
@@ -659,9 +672,8 @@
             // FIXME: one may avoid the copy of memoryStream and use the buffered rawStream.
             SkMemoryStream* memoryStream =
                 rawStream->transferBuffer(imageData.preview.offset, imageData.preview.length);
-            return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nullptr;
-        } else if (error == ::piex::Error::kFail) {
-            return nullptr;
+            return memoryStream ? SkJpegCodec::NewFromStream(memoryStream, std::move(colorSpace))
+                                : nullptr;
         }
     }