Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(147)

Side by Side Diff: src/codec/SkRawCodec.cpp

Issue 1520403003: Prototype of RAW decoding in Skia. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address comments Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkCodec.h"
9 #include "SkRawCodec.h"
10 #include "SkCodecPriv.h"
11 #include "SkColorPriv.h"
12 #include "SkJpegCodec.h"
13 #include "SkStream.h"
14 #include "SkStreamPriv.h"
15 #include "SkSwizzler.h"
16 #include "SkTemplates.h"
17 #include "SkTypes.h"
18
19 #include "dng_color_space.h"
20 #include "dng_exceptions.h"
21 #include "dng_host.h"
22 #include "dng_info.h"
23 #include "dng_render.h"
24 #include "dng_stream.h"
25
26 #include "src/piex.h"
27
28 #include <limits>
29
30 namespace {
31
32 // T must be unsigned type.
33 template <class T>
34 bool safe_add_to_size_t(T arg1, T arg2, size_t* result) {
35 SkASSERT(arg1 >= 0);
36 SkASSERT(arg2 >= 0);
37 if (arg1 >= 0 && arg2 <= std::numeric_limits<T>::max() - arg1) {
38 T sum = arg1 + arg2;
39 if (sum <= std::numeric_limits<size_t>::max()) {
40 *result = static_cast<size_t>(sum);
41 return true;
42 }
43 }
44 return false;
45 }
46
47 dng_negative* read_dng(dng_stream* stream, dng_host* host, dng_info* info) {
48 try {
49 SkAutoTDelete<dng_negative> negative;
50 host->ValidateSizes();
51
52 info->Parse(*host, *stream);
53 info->PostParse(*host);
54
55 if (!info->IsValidDNG()) {
56 return nullptr;
57 }
58
59 negative.reset(host->Make_dng_negative());
60 negative->Parse(*host, *stream, *info);
61 negative->PostParse(*host, *stream, *info);
62 negative->SynchronizeMetadata();
63
64 return negative.release();
65 } catch (...) {
66 return nullptr;
67 }
68 }
69
70 dng_image* render_dng_for_prefered_size(const int prefered_size, dng_stream* str eam,
71 dng_host* host, dng_info* info, dng_nega tive* negative) {
72 try {
73 host->SetPreferredSize(prefered_size);
74 host->ValidateSizes();
75
76 negative->ReadStage1Image(*host, *stream, *info);
77
78 if (info->fMaskIndex != -1) {
79 negative->ReadTransparencyMask(*host, *stream, *info);
80 }
81
82 negative->ValidateRawImageDigest(*host);
83 if (negative->IsDamaged()) {
84 return nullptr;
85 }
86
87 const int32 kMosaicPlane = -1;
88 negative->BuildStage2Image(*host);
89 negative->BuildStage3Image(*host, kMosaicPlane);
90
91 dng_render render(*host, *negative);
92 render.SetFinalSpace(dng_space_sRGB::Get());
93 render.SetFinalPixelType(ttByte);
94
95 dng_point stage3_size = negative->Stage3Image()->Size();
96 render.SetMaximumSize(SkTMax(stage3_size.h, stage3_size.v));
97
98 return render.Render();
99 } catch (...) {
100 return nullptr;
101 }
102 }
103
104 } // namespace
105
106 // Note: this class could throw exception if it is used as dng_stream.
107 class SkRawStream : public dng_stream, public ::piex::StreamInterface {
108 public:
109 // Note that this call will take the ownership of stream.
110 explicit SkRawStream(SkStream* stream)
111 : fStream(stream), fWholeStreamRead(false), fStreamBufferSize(0) {}
112
113 ~SkRawStream() override {}
114
115 // Creates a SkMemoryStream from the offset with size.
116 SkMemoryStream* copyBuffer(size_t offset, size_t size) {
117 size_t sum;
118 if (!safe_add_to_size_t(offset, size, &sum) || !this->bufferMoreData(sum )) {
119 return nullptr;
120 }
121 return new SkMemoryStream(fStreamBuffer.get() + offset, size, true);
122 }
123
124 // For PIEX
125 ::piex::Error GetData(const size_t offset, const size_t length,
126 uint8* data) override {
127 if (offset == 0 && length == 0) {
128 return ::piex::Error::kOk;
129 }
130 size_t sum;
131 if (!safe_add_to_size_t(offset, length, &sum) || !this->bufferMoreData(s um)) {
132 return ::piex::Error::kFail;
scroggo 2016/01/11 17:44:02 nit: four space indent.
yujieqin 2016/01/12 10:47:40 Done.
133 }
134 memcpy(data, fStreamBuffer.get() + offset, length);
135 return ::piex::Error::kOk;
136 }
137
138 protected:
139 // For dng_stream
140 uint64 DoGetLength() override {
141 if (!this->bufferMoreData(kReadToEnd)) { // read whole stream
142 ThrowReadFile();
143 }
144 return fStreamBufferSize;
145 }
146
147 // For dng_stream
148 void DoRead(void* data, uint32 count, uint64 offset) override {
149 if (count == 0 && offset == 0) {
150 return;
151 }
152 size_t sum;
153 if (!safe_add_to_size_t(static_cast<uint64>(count), offset, &sum) ||
154 !this->bufferMoreData(sum)) {
155 ThrowReadFile();
156 }
157 memcpy(data, fStreamBuffer.get() + offset, count);
158 }
159
160 private:
161 // Note: if the newSize == kReadToEnd (0), this function will read to the en d of stream..
162 bool bufferMoreData(size_t newSize) {
163 if (newSize == kReadToEnd) {
164 if (fWholeStreamRead) { // the stream is already read-to-end.
165 return true;
166 }
167
168 SkDynamicMemoryWStream tempStream;
169 // TODO: optimize for the special case when the input is SkMemoryStr eam.
170 if (!SkStreamCopyToDynamicMemoryW(&tempStream, fStream.get())) {
171 return false;
172 }
173
174 size_t wholeStreamSize;
175 if (!safe_add_to_size_t(fStreamBufferSize, tempStream.bytesWritten() ,
176 &wholeStreamSize)) {
177 return false;
178 }
179
180 fStreamBuffer.realloc(wholeStreamSize);
181 uint8_t* appendDst = fStreamBuffer.get() + fStreamBufferSize;
182 tempStream.copyTo(appendDst);
183 fStreamBufferSize = wholeStreamSize;
184 return true;
185 }
186
187 if (newSize <= fStreamBufferSize) { // the stream is already buffered t o newSize.
188 return true;
189 }
190 if (fWholeStreamRead) { // newSize is larger than the whole stream.
191 return false;
192 }
193
194 fStreamBuffer.realloc(newSize);
195 uint8_t* appendDst = fStreamBuffer.get() + fStreamBufferSize;
196 const size_t sizeToRead = newSize - fStreamBufferSize;
197 const size_t bytesRead = fStream->read(appendDst, sizeToRead);
198 if (bytesRead < sizeToRead) {
199 return false;
200 }
201 fStreamBufferSize = newSize;
202 return true;
203 }
204
205 SkAutoTDelete<SkStream> fStream;
206 bool fWholeStreamRead;
207
208 SkAutoTMalloc<uint8> fStreamBuffer;
209 size_t fStreamBufferSize;
210
211 const size_t kReadToEnd = 0;
212 };
213
214 SkCodec* SkRawCodec::NewFromStream(SkStream* stream) {
215 SkAutoTDelete<SkRawStream> rawStream(new SkRawStream(stream));
216 ::piex::PreviewImageData imageData;
217 if (::piex::IsRaw(rawStream.get()) &&
218 ::piex::GetPreviewImageData(rawStream.get(), &imageData) == ::piex::Erro r::kOk)
219 {
220 SkMemoryStream* memoryStream =
221 rawStream->copyBuffer(imageData.jpeg_offset, imageData.jpeg_leng th);
222 return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nullptr ;
223 }
224
225 SkAutoTDelete<dng_host> host(new dng_host);
226 SkAutoTDelete<dng_info> info(new dng_info);
227 SkAutoTDelete<dng_negative> negative(read_dng(rawStream.get(), host.get(), i nfo.get()));
228 if (!negative) {
229 return nullptr;
230 }
231
232 const SkImageInfo& imageInfo = SkImageInfo::Make(
233 negative->DefaultCropSizeH().As_real64(),
234 negative->DefaultCropSizeV().As_real64(),
235 kN32_SkColorType, kOpaque_SkAlphaType);
236 return new SkRawCodec(imageInfo, rawStream.release(), host.release(),
237 info.release(), negative.release());
238 }
239
240 SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
241 size_t dstRowBytes, const Options& optio ns,
242 SkPMColor ctable[], int* ctableCount,
243 int* rowsDecoded) {
244 const int width = requestedInfo.width();
245 const int height = requestedInfo.height();
246 if (!fDngImage) {
247 const int preferedSize = SkTMax(width, height);
msarett 2016/01/11 19:12:44 I believe this should be: preferredSize = origina
yujieqin 2016/01/12 10:47:40 onGetPixel() should only support the requests, whi
msarett 2016/01/12 14:01:29 My mistake you're right - if we ever pass the wron
248 fDngImage.reset(render_dng_for_prefered_size(preferedSize, fRawStream, f DngHost.get(),
249 fDngInfo.get(), fDngNegativ e.get()));
250 if (!fDngImage) {
251 return kInvalidInput;
252 }
253 }
254
255 const dng_point& imageSize = fDngImage->Size();
256 if (imageSize.h != width || imageSize.v != height) {
257 return kInvalidScale;
scroggo 2016/01/11 17:44:02 nit: four space indents
yujieqin 2016/01/12 10:47:40 Done.
258 }
259
260 void* dstRow = dst;
261 uint8 srcRow[width * 3];
262 SkAutoTDelete<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(
263 SkSwizzler::kRGB, nullptr, requestedInfo, options));
264 SkASSERT(swizzler);
265 for (int i = 0; i < height; ++i) {
266 dng_pixel_buffer buffer;
267 buffer.fData = &srcRow[0];
268 buffer.fArea = dng_rect(i, 0, i + 1, width);
269 buffer.fPlane = 0;
270 buffer.fPlanes = 3;
271 buffer.fColStep = buffer.fPlanes;
272 buffer.fPlaneStep = 1;
273 buffer.fPixelType = ttByte;
274 buffer.fPixelSize = sizeof(uint8);
275 buffer.fRowStep = sizeof(srcRow);
276
277 try {
278 fDngImage->Get(buffer, dng_image::edge_zero);
279 } catch (...) {
280 return kInvalidInput;
281 }
282
283 swizzler->swizzle(dstRow, &srcRow[0]);
284 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
285 }
286 return kSuccess;
287 }
288
289 SkISize SkRawCodec::onGetScaledDimensions(float desiredScale) const {
290 SkISize dim = this->getInfo().dimensions();
291 // SkCodec treats zero dimensional images as errors, so the minimum size
292 // that we will recommend is 1x1.
293 dim.fWidth = SkTMax(1, SkScalarRoundToInt(desiredScale * dim.fWidth));
294 dim.fHeight = SkTMax(1, SkScalarRoundToInt(desiredScale * dim.fHeight));
295
296 const int preferedSize = SkTMax(dim.fWidth, dim.fHeight);
297 fDngImage.reset(render_dng_for_prefered_size(preferedSize, fRawStream, fDngH ost.get(),
298 fDngInfo.get(), fDngNegative.ge t()));
299 if (!fDngImage) {
300 return SkISize::Make(0, 0);
301 }
302
303 dng_point imageSize = fDngImage->Size();
304 dim.fWidth = imageSize.h;
305 dim.fHeight = imageSize.v;
306
307 return dim;
308 }
309
310 bool SkRawCodec::onDimensionsSupported(const SkISize& dim) {
311 const SkImageInfo& info = this->getInfo();
312 return dim.width() >= 1 && dim.width() <= info.width()
313 && dim.height() >= 1 && dim.height() <= info.height();
314 }
315
316 SkRawCodec::~SkRawCodec() {
317 delete fRawStream;
318 }
319
320 SkRawCodec::SkRawCodec(const SkImageInfo& srcInfo, SkRawStream* stream, dng_host * host,
321 dng_info* info, dng_negative* negative)
322 : INHERITED(srcInfo, nullptr)
323 , fRawStream(stream)
324 , fDngHost(host)
325 , fDngInfo(info)
326 , fDngNegative(negative) {}
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698