OLD | NEW |
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 "SkImageEncoder.h" | 6 #include "SkImageEncoder.h" |
| 7 #include "SkMallocPixelRef.h" |
| 8 #include "SkStream.h" |
7 #include "SkString.h" | 9 #include "SkString.h" |
8 #include "SkStream.h" | |
9 | 10 |
10 DEFINE_string2(writePath, w, "", "If set, write GMs here as .pngs."); | 11 DEFINE_string2(writePath, w, "", "If set, write GMs here as .pngs."); |
11 | 12 |
12 namespace DM { | 13 namespace DM { |
13 | 14 |
14 // Splits off the last N suffixes of name (splitting on _) and appends them to o
ut. | 15 // Splits off the last N suffixes of name (splitting on _) and appends them to o
ut. |
15 // Returns the total number of characters consumed. | 16 // Returns the total number of characters consumed. |
16 static int split_suffixes(int N, const char* name, SkTArray<SkString>* out) { | 17 static int split_suffixes(int N, const char* name, SkTArray<SkString>* out) { |
17 SkTArray<SkString> split; | 18 SkTArray<SkString> split; |
18 SkStrSplit(name, "_", &split); | 19 SkStrSplit(name, "_", &split); |
(...skipping 12 matching lines...) Expand all Loading... |
31 const int totalSuffixLength = split_suffixes(suffixes, name.c_str(), &fSuffi
xes); | 32 const int totalSuffixLength = split_suffixes(suffixes, name.c_str(), &fSuffi
xes); |
32 fGmName.set(name.c_str(), name.size()-totalSuffixLength); | 33 fGmName.set(name.c_str(), name.size()-totalSuffixLength); |
33 } | 34 } |
34 | 35 |
35 void WriteTask::makeDirOrFail(SkString dir) { | 36 void WriteTask::makeDirOrFail(SkString dir) { |
36 if (!sk_mkdir(dir.c_str())) { | 37 if (!sk_mkdir(dir.c_str())) { |
37 this->fail(); | 38 this->fail(); |
38 } | 39 } |
39 } | 40 } |
40 | 41 |
| 42 namespace { |
| 43 |
41 // One file that first contains a .png of an SkBitmap, then its raw pixels. | 44 // 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. | 45 // We use this custom format to avoid premultiplied/unpremultiplied pixel conver
sions. |
43 struct PngAndRaw { | 46 struct PngAndRaw { |
44 static bool Encode(SkBitmap bitmap, const char* path) { | 47 static bool Encode(SkBitmap bitmap, const char* path) { |
45 SkFILEWStream stream(path); | 48 SkFILEWStream stream(path); |
46 if (!stream.isValid()) { | 49 if (!stream.isValid()) { |
47 SkDebugf("Can't write %s.\n", path); | 50 SkDebugf("Can't write %s.\n", path); |
48 return false; | 51 return false; |
49 } | 52 } |
50 | 53 |
51 // Write a PNG first for humans and other tools to look at. | 54 // Write a PNG first for humans and other tools to look at. |
52 if (!SkImageEncoder::EncodeStream(&stream, bitmap, SkImageEncoder::kPNG_
Type, 100)) { | 55 if (!SkImageEncoder::EncodeStream(&stream, bitmap, SkImageEncoder::kPNG_
Type, 100)) { |
53 SkDebugf("Can't encode a PNG.\n"); | 56 SkDebugf("Can't encode a PNG.\n"); |
54 return false; | 57 return false; |
55 } | 58 } |
56 | 59 |
| 60 // Pad out so the raw pixels start 4-byte aligned. |
| 61 const uint32_t maxPadding = 0; |
| 62 const size_t pos = stream.bytesWritten(); |
| 63 stream.write(&maxPadding, SkAlign4(pos) - pos); |
| 64 |
57 // Then write our secret raw pixels that only DM reads. | 65 // Then write our secret raw pixels that only DM reads. |
58 SkAutoLockPixels lock(bitmap); | 66 SkAutoLockPixels lock(bitmap); |
59 return stream.write(bitmap.getPixels(), bitmap.getSize()); | 67 return stream.write(bitmap.getPixels(), bitmap.getSize()); |
60 } | 68 } |
61 | 69 |
62 // This assumes bitmap already has allocated pixels of the correct size. | 70 // This assumes bitmap already has allocated pixels of the correct size. |
63 static bool Decode(const char* path, SkBitmap* bitmap) { | 71 static bool Decode(const char* path, SkImageInfo info, SkBitmap* bitmap) { |
64 SkAutoTUnref<SkStreamRewindable> stream(SkStream::NewFromFile(path)); | 72 SkAutoTUnref<SkData> data(SkData::NewFromFileName(path)); |
65 if (NULL == stream.get()) { | 73 if (!data) { |
66 SkDebugf("Can't read %s.\n", path); | 74 SkDebugf("Can't read %s.\n", path); |
67 return false; | 75 return false; |
68 } | 76 } |
69 | 77 |
70 // The raw pixels are at the end of the stream. Seek ahead to skip beyo
nd the encoded PNG. | 78 // The raw pixels are at the end of the file. We'll skip the encoded PN
G at the front. |
71 const size_t bitmapBytes = bitmap->getSize(); | 79 const size_t rowBytes = info.minRowBytes(); // Assume densely packed. |
72 if (stream->getLength() < bitmapBytes) { | 80 const size_t bitmapBytes = info.getSafeSize(rowBytes); |
| 81 if (data->size() < bitmapBytes) { |
73 SkDebugf("%s is too small to contain the bitmap we're looking for.\n
", path); | 82 SkDebugf("%s is too small to contain the bitmap we're looking for.\n
", path); |
74 return false; | 83 return false; |
75 } | 84 } |
76 SkAssertResult(stream->seek(stream->getLength() - bitmapBytes)); | |
77 | 85 |
78 // Read the raw pixels. | 86 const size_t offset = data->size() - bitmapBytes; |
79 // TODO(mtklein): can we install a pixelref that just hangs onto the str
eam instead of | 87 SkAutoTUnref<SkPixelRef> pixels( |
80 // copying into a malloc'd buffer? | 88 SkMallocPixelRef::NewWithData(info, rowBytes, NULL/*ctable*/, data,
offset)); |
81 SkAutoLockPixels lock(*bitmap); | 89 SkASSERT(pixels); |
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 | 90 |
88 SkASSERT(stream->isAtEnd()); | 91 bitmap->setConfig(info, rowBytes); |
| 92 bitmap->setPixelRef(pixels); |
89 return true; | 93 return true; |
90 } | 94 } |
91 }; | 95 }; |
92 | 96 |
| 97 } // namespace |
| 98 |
93 void WriteTask::draw() { | 99 void WriteTask::draw() { |
94 SkString dir(FLAGS_writePath[0]); | 100 SkString dir(FLAGS_writePath[0]); |
95 this->makeDirOrFail(dir); | 101 this->makeDirOrFail(dir); |
96 for (int i = 0; i < fSuffixes.count(); i++) { | 102 for (int i = 0; i < fSuffixes.count(); i++) { |
97 dir = SkOSPath::SkPathJoin(dir.c_str(), fSuffixes[i].c_str()); | 103 dir = SkOSPath::SkPathJoin(dir.c_str(), fSuffixes[i].c_str()); |
98 this->makeDirOrFail(dir); | 104 this->makeDirOrFail(dir); |
99 } | 105 } |
100 SkString path = SkOSPath::SkPathJoin(dir.c_str(), fGmName.c_str()); | 106 SkString path = SkOSPath::SkPathJoin(dir.c_str(), fGmName.c_str()); |
101 path.append(".png"); | 107 path.append(".png"); |
102 if (!PngAndRaw::Encode(fBitmap, path.c_str())) { | 108 if (!PngAndRaw::Encode(fBitmap, path.c_str())) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 } | 143 } |
138 | 144 |
139 bool WriteTask::Expectations::check(const Task& task, SkBitmap bitmap) const { | 145 bool WriteTask::Expectations::check(const Task& task, SkBitmap bitmap) const { |
140 if (!FLAGS_writePath.isEmpty() && 0 == strcmp(FLAGS_writePath[0], fRoot)) { | 146 if (!FLAGS_writePath.isEmpty() && 0 == strcmp(FLAGS_writePath[0], fRoot)) { |
141 SkDebugf("We seem to be reading and writing %s concurrently. This won't
work.\n", fRoot); | 147 SkDebugf("We seem to be reading and writing %s concurrently. This won't
work.\n", fRoot); |
142 return false; | 148 return false; |
143 } | 149 } |
144 | 150 |
145 const SkString path = path_to_expected_image(fRoot, task); | 151 const SkString path = path_to_expected_image(fRoot, task); |
146 SkBitmap expected; | 152 SkBitmap expected; |
147 expected.allocPixels(bitmap.info()); | 153 if (!PngAndRaw::Decode(path.c_str(), bitmap.info(), &expected)) { |
148 if (!PngAndRaw::Decode(path.c_str(), &expected)) { | |
149 return false; | 154 return false; |
150 } | 155 } |
151 | 156 |
152 return BitmapsEqual(expected, bitmap); | 157 return BitmapsEqual(expected, bitmap); |
153 } | 158 } |
154 | 159 |
155 } // namespace DM | 160 } // namespace DM |
OLD | NEW |