| OLD | NEW |
| (Empty) |
| 1 #include "DMWriteTask.h" | |
| 2 | |
| 3 #include "DMJsonWriter.h" | |
| 4 #include "DMUtil.h" | |
| 5 #include "SkColorPriv.h" | |
| 6 #include "SkCommonFlags.h" | |
| 7 #include "SkData.h" | |
| 8 #include "SkImageEncoder.h" | |
| 9 #include "SkMD5.h" | |
| 10 #include "SkMallocPixelRef.h" | |
| 11 #include "SkOSFile.h" | |
| 12 #include "SkStream.h" | |
| 13 #include "SkString.h" | |
| 14 | |
| 15 DEFINE_bool(nameByHash, false, "If true, write .../hash.png instead of .../mode/
config/name.png"); | |
| 16 | |
| 17 namespace DM { | |
| 18 | |
| 19 // Splits off the last N suffixes of name (splitting on _) and appends them to o
ut. | |
| 20 // Returns the total number of characters consumed. | |
| 21 static int split_suffixes(int N, const char* name, SkTArray<SkString>* out) { | |
| 22 SkTArray<SkString> split; | |
| 23 SkStrSplit(name, "_", &split); | |
| 24 int consumed = 0; | |
| 25 for (int i = 0; i < N; i++) { | |
| 26 // We're splitting off suffixes from the back to front. | |
| 27 out->push_back(split[split.count()-i-1]); | |
| 28 consumed += SkToInt(out->back().size() + 1); // Add one for the _. | |
| 29 } | |
| 30 return consumed; | |
| 31 } | |
| 32 | |
| 33 inline static SkString find_base_name(const Task& parent, SkTArray<SkString>* su
ffixList) { | |
| 34 const int suffixes = parent.depth() + 1; | |
| 35 const SkString& name = parent.name(); | |
| 36 const int totalSuffixLength = split_suffixes(suffixes, name.c_str(), suffixL
ist); | |
| 37 return SkString(name.c_str(), name.size() - totalSuffixLength); | |
| 38 } | |
| 39 | |
| 40 WriteTask::WriteTask(const Task& parent, const char* sourceType, SkBitmap bitmap
) | |
| 41 : CpuTask(parent) | |
| 42 , fBaseName(find_base_name(parent, &fSuffixes)) | |
| 43 , fSourceType(sourceType) | |
| 44 , fBitmap(bitmap) | |
| 45 , fData(NULL) | |
| 46 , fExtension(".png") { | |
| 47 } | |
| 48 | |
| 49 WriteTask::WriteTask(const Task& parent, | |
| 50 const char* sourceType, | |
| 51 SkStreamAsset *data, | |
| 52 const char* ext) | |
| 53 : CpuTask(parent) | |
| 54 , fBaseName(find_base_name(parent, &fSuffixes)) | |
| 55 , fSourceType(sourceType) | |
| 56 , fData(data) | |
| 57 , fExtension(ext) { | |
| 58 SkASSERT(fData.get()); | |
| 59 SkASSERT(fData->unique()); | |
| 60 } | |
| 61 | |
| 62 void WriteTask::makeDirOrFail(SkString dir) { | |
| 63 // This can be a little racy, so if it fails check to see if someone else su
cceeded. | |
| 64 if (!sk_mkdir(dir.c_str()) && !sk_isdir(dir.c_str())) { | |
| 65 this->fail("Can't make directory."); | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 static SkString get_md5_string(SkMD5* hasher) { | |
| 70 SkMD5::Digest digest; | |
| 71 hasher->finish(digest); | |
| 72 | |
| 73 SkString md5; | |
| 74 for (int i = 0; i < 16; i++) { | |
| 75 md5.appendf("%02x", digest.data[i]); | |
| 76 } | |
| 77 return md5; | |
| 78 } | |
| 79 | |
| 80 static SkString get_md5(const void* ptr, size_t len) { | |
| 81 SkMD5 hasher; | |
| 82 hasher.write(ptr, len); | |
| 83 return get_md5_string(&hasher); | |
| 84 } | |
| 85 | |
| 86 static bool write_asset(SkStreamAsset* input, SkWStream* output) { | |
| 87 return input->rewind() && output->writeStream(input, input->getLength()); | |
| 88 } | |
| 89 | |
| 90 static SkString get_md5(SkStreamAsset* stream) { | |
| 91 SkMD5 hasher; | |
| 92 write_asset(stream, &hasher); | |
| 93 return get_md5_string(&hasher); | |
| 94 } | |
| 95 | |
| 96 static bool encode_png(const SkBitmap& src, SkFILEWStream* file) { | |
| 97 SkBitmap bm; | |
| 98 // We can't encode A8 bitmaps as PNGs. Convert them to 8888 first. | |
| 99 if (src.info().colorType() == kAlpha_8_SkColorType) { | |
| 100 if (!src.copyTo(&bm, kN32_SkColorType)) { | |
| 101 return false; | |
| 102 } | |
| 103 } else { | |
| 104 bm = src; | |
| 105 } | |
| 106 return SkImageEncoder::EncodeStream(file, bm, SkImageEncoder::kPNG_Type, 100
); | |
| 107 } | |
| 108 | |
| 109 void WriteTask::draw() { | |
| 110 SkString md5; | |
| 111 { | |
| 112 SkAutoLockPixels lock(fBitmap); | |
| 113 md5 = fData ? get_md5(fData) | |
| 114 : get_md5(fBitmap.getPixels(), fBitmap.getSize()); | |
| 115 } | |
| 116 | |
| 117 SkASSERT(fSuffixes.count() > 0); | |
| 118 SkString config = fSuffixes.back(); | |
| 119 SkString mode("direct"); | |
| 120 if (fSuffixes.count() > 1) { | |
| 121 mode = fSuffixes.fromBack(1); | |
| 122 } | |
| 123 | |
| 124 { | |
| 125 const JsonWriter::BitmapResult entry = { fBaseName, | |
| 126 config, | |
| 127 mode, | |
| 128 fSourceType, | |
| 129 md5 }; | |
| 130 JsonWriter::AddBitmapResult(entry); | |
| 131 } | |
| 132 | |
| 133 SkString dir(FLAGS_writePath[0]); | |
| 134 #if defined(SK_BUILD_FOR_IOS) | |
| 135 if (dir.equals("@")) { | |
| 136 dir.set(FLAGS_resourcePath[0]); | |
| 137 } | |
| 138 #endif | |
| 139 this->makeDirOrFail(dir); | |
| 140 | |
| 141 SkString path; | |
| 142 if (FLAGS_nameByHash) { | |
| 143 // Flat directory of hash-named files. | |
| 144 path = SkOSPath::Join(dir.c_str(), md5.c_str()); | |
| 145 path.append(fExtension); | |
| 146 // We're content-addressed, so it's possible two threads race to write | |
| 147 // this file. We let the first one win. This also means we won't | |
| 148 // overwrite identical files from previous runs. | |
| 149 if (sk_exists(path.c_str())) { | |
| 150 return; | |
| 151 } | |
| 152 } else { | |
| 153 // Nested by mode, config, etc. | |
| 154 for (int i = 0; i < fSuffixes.count(); i++) { | |
| 155 dir = SkOSPath::Join(dir.c_str(), fSuffixes[i].c_str()); | |
| 156 this->makeDirOrFail(dir); | |
| 157 } | |
| 158 path = SkOSPath::Join(dir.c_str(), fBaseName.c_str()); | |
| 159 path.append(fExtension); | |
| 160 // The path is unique, so two threads can't both write to the same file. | |
| 161 // If already present we overwrite here, since the content may have chan
ged. | |
| 162 } | |
| 163 | |
| 164 SkFILEWStream file(path.c_str()); | |
| 165 if (!file.isValid()) { | |
| 166 return this->fail("Can't open file."); | |
| 167 } | |
| 168 | |
| 169 bool ok = fData ? write_asset(fData, &file) | |
| 170 : encode_png(fBitmap, &file); | |
| 171 if (!ok) { | |
| 172 return this->fail("Can't write to file."); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 SkString WriteTask::name() const { | |
| 177 SkString name("writing "); | |
| 178 for (int i = 0; i < fSuffixes.count(); i++) { | |
| 179 name.appendf("%s/", fSuffixes[i].c_str()); | |
| 180 } | |
| 181 name.append(fBaseName.c_str()); | |
| 182 return name; | |
| 183 } | |
| 184 | |
| 185 bool WriteTask::shouldSkip() const { | |
| 186 return FLAGS_writePath.isEmpty(); | |
| 187 } | |
| 188 | |
| 189 } // namespace DM | |
| OLD | NEW |