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

Side by Side Diff: dm/DMWriteTask.cpp

Issue 185343002: DM: fix -w/-r problems stemming from PM/UPM conversions. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: notes and errors Created 6 years, 9 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #include "DMWriteTask.h" 1 #include "DMWriteTask.h"
2 2
3 #include "DMUtil.h" 3 #include "DMUtil.h"
4 #include "SkColorPriv.h" 4 #include "SkColorPriv.h"
5 #include "SkCommandLineFlags.h" 5 #include "SkCommandLineFlags.h"
6 #include "SkImageDecoder.h"
7 #include "SkImageEncoder.h" 6 #include "SkImageEncoder.h"
8 #include "SkString.h" 7 #include "SkString.h"
9 #include "SkUnPreMultiply.h" 8 #include "SkStream.h"
10 9
11 DEFINE_string2(writePath, w, "", "If set, write GMs here as .pngs."); 10 DEFINE_string2(writePath, w, "", "If set, write GMs here as .pngs.");
12 11
13 namespace DM { 12 namespace DM {
14 13
15 // Splits off the last N suffixes of name (splitting on _) and appends them to o ut. 14 // Splits off the last N suffixes of name (splitting on _) and appends them to o ut.
16 // Returns the total number of characters consumed. 15 // Returns the total number of characters consumed.
17 static int split_suffixes(int N, const char* name, SkTArray<SkString>* out) { 16 static int split_suffixes(int N, const char* name, SkTArray<SkString>* out) {
18 SkTArray<SkString> split; 17 SkTArray<SkString> split;
19 SkStrSplit(name, "_", &split); 18 SkStrSplit(name, "_", &split);
(...skipping 12 matching lines...) Expand all
32 const int totalSuffixLength = split_suffixes(suffixes, name.c_str(), &fSuffi xes); 31 const int totalSuffixLength = split_suffixes(suffixes, name.c_str(), &fSuffi xes);
33 fGmName.set(name.c_str(), name.size()-totalSuffixLength); 32 fGmName.set(name.c_str(), name.size()-totalSuffixLength);
34 } 33 }
35 34
36 void WriteTask::makeDirOrFail(SkString dir) { 35 void WriteTask::makeDirOrFail(SkString dir) {
37 if (!sk_mkdir(dir.c_str())) { 36 if (!sk_mkdir(dir.c_str())) {
38 this->fail(); 37 this->fail();
39 } 38 }
40 } 39 }
41 40
41 // One file that first contains a .png of an SkBitmap, then its raw pixels.
42 // We use this custom format to avoid premultiplied/unpremultiplied pixel conver sions.
43 struct PngAndRaw {
44 static bool Encode(SkBitmap bitmap, const char* path) {
45 SkFILEWStream stream(path);
46 if (!stream.isValid()) {
47 SkDebugf("Can't write %s.\n", path);
48 return false;
49 }
50
51 // Write a PNG first for humans and other tools to look at.
52 if (!SkImageEncoder::EncodeStream(&stream, bitmap, SkImageEncoder::kPNG_ Type, 100)) {
53 SkDebugf("Can't encode a PNG.\n");
54 return false;
55 }
56
57 // Then write our secret raw pixels that only DM reads.
58 SkAutoLockPixels lock(bitmap);
59 return stream.write(bitmap.getPixels(), bitmap.getSize());
60 }
61
62 // This assumes bitmap already has allocated pixels of the correct size.
63 static bool Decode(const char* path, SkBitmap* bitmap) {
64 SkAutoTUnref<SkStreamRewindable> stream(SkStream::NewFromFile(path));
65 if (NULL == stream.get()) {
66 SkDebugf("Can't read %s.\n", path);
67 return false;
68 }
69
70 // The raw pixels are at the end of the stream. Seek ahead to skip beyo nd the encoded PNG.
71 const size_t bitmapBytes = bitmap->getSize();
72 if (stream->getLength() < bitmapBytes) {
73 SkDebugf("%s is too small to contain the bitmap we're looking for.\n ", path);
74 return false;
75 }
76 SkAssertResult(stream->seek(stream->getLength() - bitmapBytes));
77
78 // Read the raw pixels.
79 // TODO(mtklein): can we install a pixelref that just hangs onto the str eam instead of
80 // copying into a malloc'd buffer?
81 SkAutoLockPixels lock(*bitmap);
82 if (bitmapBytes != stream->read(bitmap->getPixels(), bitmapBytes)) {
83 SkDebugf("Couldn't read raw bitmap from %s at %lu of %lu.\n",
84 path, stream->getPosition(), stream->getLength());
85 return false;
86 }
87
88 SkASSERT(stream->isAtEnd());
89 return true;
90 }
91 };
92
42 void WriteTask::draw() { 93 void WriteTask::draw() {
43 SkString dir(FLAGS_writePath[0]); 94 SkString dir(FLAGS_writePath[0]);
44 this->makeDirOrFail(dir); 95 this->makeDirOrFail(dir);
45 for (int i = 0; i < fSuffixes.count(); i++) { 96 for (int i = 0; i < fSuffixes.count(); i++) {
46 dir = SkOSPath::SkPathJoin(dir.c_str(), fSuffixes[i].c_str()); 97 dir = SkOSPath::SkPathJoin(dir.c_str(), fSuffixes[i].c_str());
47 this->makeDirOrFail(dir); 98 this->makeDirOrFail(dir);
48 } 99 }
49 SkString path = SkOSPath::SkPathJoin(dir.c_str(), fGmName.c_str()); 100 SkString path = SkOSPath::SkPathJoin(dir.c_str(), fGmName.c_str());
50 path.append(".png"); 101 path.append(".png");
51 if (!SkImageEncoder::EncodeFile(path.c_str(), 102 if (!PngAndRaw::Encode(fBitmap, path.c_str())) {
52 fBitmap,
53 SkImageEncoder::kPNG_Type,
54 100/*quality*/)) {
55 this->fail(); 103 this->fail();
56 } 104 }
57 } 105 }
58 106
59 SkString WriteTask::name() const { 107 SkString WriteTask::name() const {
60 SkString name("writing "); 108 SkString name("writing ");
61 for (int i = 0; i < fSuffixes.count(); i++) { 109 for (int i = 0; i < fSuffixes.count(); i++) {
62 name.appendf("%s/", fSuffixes[i].c_str()); 110 name.appendf("%s/", fSuffixes[i].c_str());
63 } 111 }
64 name.append(fGmName.c_str()); 112 name.append(fGmName.c_str());
(...skipping 13 matching lines...) Expand all
78 const int suffixLength = split_suffixes(1, filename.c_str(), &suffixes); 126 const int suffixLength = split_suffixes(1, filename.c_str(), &suffixes);
79 SkASSERT(1 == suffixes.count()); 127 SkASSERT(1 == suffixes.count());
80 128
81 // We'll look in root/suffix for images. 129 // We'll look in root/suffix for images.
82 const SkString dir = SkOSPath::SkPathJoin(root, suffixes[0].c_str()); 130 const SkString dir = SkOSPath::SkPathJoin(root, suffixes[0].c_str());
83 131
84 // Remove the suffix and tack on a .png. 132 // Remove the suffix and tack on a .png.
85 filename.remove(filename.size() - suffixLength, suffixLength); 133 filename.remove(filename.size() - suffixLength, suffixLength);
86 filename.append(".png"); 134 filename.append(".png");
87 135
88 //SkDebugf("dir %s, filename %s\n", dir.c_str(), filename.c_str());
89
90 return SkOSPath::SkPathJoin(dir.c_str(), filename.c_str()); 136 return SkOSPath::SkPathJoin(dir.c_str(), filename.c_str());
91 } 137 }
92 138
93 bool WriteTask::Expectations::check(const Task& task, SkBitmap bitmap) const { 139 bool WriteTask::Expectations::check(const Task& task, SkBitmap bitmap) const {
94 if (!FLAGS_writePath.isEmpty() && 0 == strcmp(FLAGS_writePath[0], fRoot)) { 140 if (!FLAGS_writePath.isEmpty() && 0 == strcmp(FLAGS_writePath[0], fRoot)) {
95 SkDebugf("We seem to be reading and writing %s concurrently. This won't work.\n", fRoot); 141 SkDebugf("We seem to be reading and writing %s concurrently. This won't work.\n", fRoot);
96 return false; 142 return false;
97 } 143 }
98 144
99 // PNG is stored unpremultiplied, and going from premul to unpremul to premu l is lossy. To
100 // skirt this problem, we decode the PNG into an unpremul bitmap, convert ou r bitmap to unpremul
101 // if needed, and compare those. Each image goes once from premul to unprem ul, never back.
102 const SkString path = path_to_expected_image(fRoot, task); 145 const SkString path = path_to_expected_image(fRoot, task);
103 146 SkBitmap expected;
104 SkAutoTUnref<SkStreamRewindable> stream(SkStream::NewFromFile(path.c_str())) ; 147 expected.allocPixels(bitmap.info());
105 if (NULL == stream.get()) { 148 if (!PngAndRaw::Decode(path.c_str(), &expected)) {
106 SkDebugf("Could not read %s.\n", path.c_str());
107 return false; 149 return false;
108 } 150 }
109 151
110 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
111 if (NULL == decoder.get()) {
112 SkDebugf("Could not find a decoder for %s.\n", path.c_str());
113 return false;
114 }
115
116 const SkImageInfo info = bitmap.info();
117
118 SkBitmap expected;
119 expected.allocPixels(info);
120
121 // expected will be unpremultiplied.
122 decoder->setRequireUnpremultipliedColors(true);
123 if (!decoder->decode(stream, &expected, SkImageDecoder::kDecodePixels_Mode)) {
124 SkDebugf("Could not decode %s.\n", path.c_str());
125 return false;
126 }
127
128 // We always seem to decode to 8888. This puts 565 back in 565.
129 if (expected.colorType() != bitmap.colorType()) {
130 SkBitmap converted;
131 SkAssertResult(expected.copyTo(&converted, bitmap.colorType()));
132 expected.swap(converted);
133 }
134 SkASSERT(expected.config() == bitmap.config());
135
136 // Manually unpremultiply 8888 bitmaps to match expected.
137 // Their pixels are shared, concurrently even, so we must copy them.
138 if (info.colorType() == kPMColor_SkColorType) {
139 SkBitmap unpremul;
140 unpremul.allocPixels(info);
141
142 SkAutoLockPixels lockSrc(bitmap), lockDst(unpremul);
143 const SkPMColor* src = (SkPMColor*)bitmap.getPixels();
144 uint32_t* dst = (uint32_t*)unpremul.getPixels();
145 for (size_t i = 0; i < bitmap.getSize()/4; i++) {
146 dst[i] = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(src[i]);
147 }
148 bitmap.swap(unpremul);
149 }
150
151 return BitmapsEqual(expected, bitmap); 152 return BitmapsEqual(expected, bitmap);
152 } 153 }
153 154
154 } // namespace DM 155 } // namespace DM
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698