/** * Helper function to write a bitmap subset to a file. Only called if subsets were created * and a writePath was provided. Behaves differently depending on * FLAGS_writeChecksumBasedFilenames. If true: * Writes the image to a PNG file named according to the digest hash, as described in * write_bitmap. * If false: * Creates a subdirectory called 'subsets' and writes a PNG to that directory. Also * creates a subdirectory called 'extracted' and writes a bitmap created using * extractSubset to a PNG in that directory. Both files will represent the same * subrectangle and have the same name for convenient comparison. In this case, the * digest is ignored. * * @param writePath Parent directory to hold the folders for the PNG files to write. Must * not be NULL. * @param subsetName Basename of the original file, with the dimensions of the subset tacked * on. Used to name the new file/folder. * @param bitmapAndDigestFromDecodeSubset SkBitmap (with digest) created by * SkImageDecoder::DecodeSubset, using rect as the area to decode. * @param rect Rectangle of the area decoded into bitmapFromDecodeSubset. Used to call * extractSubset on originalBitmap to create a bitmap with the same dimensions/pixels as * bitmapFromDecodeSubset (assuming decodeSubset worked properly). * @param originalBitmap SkBitmap decoded from the same stream as bitmapFromDecodeSubset, * using SkImageDecoder::decode to get the entire image. Used to create a PNG file for * comparison to the PNG created by bitmapAndDigestFromDecodeSubset's bitmap. * @return bool Whether the function succeeded at drawing the decoded subset and the extracted * subset to files. */ static bool write_subset(const char* writePath, const SkString& subsetName, const skiagm::BitmapAndDigest bitmapAndDigestFromDecodeSubset, SkIRect rect, const SkBitmap& originalBitmap) { // All parameters must be valid. SkASSERT(writePath != NULL); SkString subsetPath; if (FLAGS_writeChecksumBasedFilenames) { subsetPath.set(writePath); } else { // Create a subdirectory to hold the results of decodeSubset. subsetPath = SkOSPath::SkPathJoin(writePath, "subsets"); if (!sk_mkdir(subsetPath.c_str())) { gFailedSubsetDecodes.push_back().printf("Successfully decoded subset %s, but " "failed to create a directory to write to.", subsetName.c_str()); return false; } } SkAssertResult(write_bitmap(subsetPath.c_str(), subsetName.c_str(), bitmapAndDigestFromDecodeSubset)); gSuccessfulSubsetDecodes.push_back().printf("\twrote %s", subsetName.c_str()); if (!FLAGS_writeChecksumBasedFilenames) { // FIXME: The goal of extracting the subset is for visual comparison/using skdiff/skpdiff. // Currently disabling for writeChecksumBasedFilenames since it will be trickier to // determine which files to compare. // Also use extractSubset from the original for visual comparison. // Write the result to a file in a separate subdirectory. SkBitmap extractedSubset; if (!originalBitmap.extractSubset(&extractedSubset, rect)) { gFailedSubsetDecodes.push_back().printf("Successfully decoded subset %s, but failed " "to extract a similar subset for comparison.", subsetName.c_str()); return false; } SkString dirExtracted = SkOSPath::SkPathJoin(writePath, "extracted"); if (!sk_mkdir(dirExtracted.c_str())) { gFailedSubsetDecodes.push_back().printf("Successfully decoded subset%s, but failed " "to create a directory for extractSubset " "comparison.", subsetName.c_str()); return false; } skiagm::BitmapAndDigest bitmapAndDigestFromExtractSubset(extractedSubset); SkAssertResult(write_bitmap(dirExtracted.c_str(), subsetName.c_str(), bitmapAndDigestFromExtractSubset)); } return true; }
void JsonWriter::DumpJson() { if (FLAGS_writePath.isEmpty()) { return; } Json::Value root; for (int i = 1; i < FLAGS_properties.count(); i += 2) { root[FLAGS_properties[i-1]] = FLAGS_properties[i]; } for (int i = 1; i < FLAGS_key.count(); i += 2) { root["key"][FLAGS_key[i-1]] = FLAGS_key[i]; } { SkAutoMutexAcquire lock(&gBitmapResultLock); for (int i = 0; i < gBitmapResults.count(); i++) { Json::Value result; result["key"]["name"] = gBitmapResults[i].name.c_str(); result["key"]["config"] = gBitmapResults[i].config.c_str(); result["key"]["source_type"] = gBitmapResults[i].sourceType.c_str(); result["options"]["ext"] = gBitmapResults[i].ext.c_str(); result["options"]["gamma_correct"] = gBitmapResults[i].gammaCorrect ? "yes" : "no"; result["md5"] = gBitmapResults[i].md5.c_str(); // Source options only need to be part of the key if they exist. // Source type by source type, we either always set options or never set options. if (!gBitmapResults[i].sourceOptions.isEmpty()) { result["key"]["source_options"] = gBitmapResults[i].sourceOptions.c_str(); } root["results"].append(result); } } { SkAutoMutexAcquire lock(gFailureLock); for (int i = 0; i < gFailures.count(); i++) { Json::Value result; result["file_name"] = gFailures[i].fileName; result["line_no"] = gFailures[i].lineNo; result["condition"] = gFailures[i].condition; result["message"] = gFailures[i].message.c_str(); root["test_results"]["failures"].append(result); } } int maxResidentSetSizeMB = sk_tools::getMaxResidentSetSizeMB(); if (maxResidentSetSizeMB != -1) { root["max_rss_MB"] = sk_tools::getMaxResidentSetSizeMB(); } SkString path = SkOSPath::Join(FLAGS_writePath[0], "dm.json"); sk_mkdir(FLAGS_writePath[0]); SkFILEWStream stream(path.c_str()); stream.writeText(Json::StyledWriter().write(root).c_str()); stream.flush(); }
/** * Encode the bitmap to a file, written one of two ways, depending on * FLAGS_writeChecksumBasedFilenames. If true, the final image will be * written to: * outDir/hashType/src/digestValue.png * If false, the final image will be written out to: * outDir/src.png * The function returns whether the file was successfully written. */ static bool write_bitmap(const char outDir[], const char src[], const skiagm::BitmapAndDigest& bitmapAndDigest) { SkString filename; if (FLAGS_writeChecksumBasedFilenames) { // First create the directory for the hashtype. const SkString hashType = bitmapAndDigest.fDigest.getHashType(); const SkString hashDir = SkOSPath::SkPathJoin(outDir, hashType.c_str()); if (!sk_mkdir(hashDir.c_str())) { return false; } // Now create the name of the folder specific to this image. SkString basename = SkOSPath::SkBasename(src); const SkString imageDir = SkOSPath::SkPathJoin(hashDir.c_str(), basename.c_str()); if (!sk_mkdir(imageDir.c_str())) { return false; } // Name the file <digest>.png SkString checksumBasedName = bitmapAndDigest.fDigest.getDigestValue(); checksumBasedName.append(".png"); filename = SkOSPath::SkPathJoin(imageDir.c_str(), checksumBasedName.c_str()); } else { make_outname(&filename, outDir, src, ".png"); } const SkBitmap& bm = bitmapAndDigest.fBitmap; if (SkImageEncoder::EncodeFile(filename.c_str(), bm, SkImageEncoder::kPNG_Type, 100)) { return true; } if (bm.colorType() == kN32_SkColorType) { // First attempt at encoding failed, and the bitmap was already 8888. Making // a copy is not going to help. return false; } // Encoding failed. Copy to 8888 and try again. SkBitmap bm8888; if (!bm.copyTo(&bm8888, kN32_SkColorType)) { return false; } return SkImageEncoder::EncodeFile(filename.c_str(), bm8888, SkImageEncoder::kPNG_Type, 100); }
static void make_recursive_dir(const SkString& path) { if (sk_exists(path.c_str())) { return; } const char* pathStr = path.c_str(); int last = (int) path.size(); do { while (last > 0 && pathStr[--last] != PATH_SLASH[0]) ; SkASSERT(last > 0); SkString shorter(pathStr, last); if (sk_mkdir(shorter.c_str())) { break; } } while (true); do { while (last < (int) path.size() && pathStr[++last] != PATH_SLASH[0]) ; SkString shorter(pathStr, last); SkAssertResult(sk_mkdir(shorter.c_str())); } while (last < (int) path.size()); }
bool write_bitmap_to_disk(const SkBitmap& bm, const SkString& dirPath, const char *subdirOrNull, const SkString& baseName) { SkString partialPath; if (subdirOrNull) { partialPath = SkOSPath::Join(dirPath.c_str(), subdirOrNull); sk_mkdir(partialPath.c_str()); } else { partialPath.set(dirPath); } SkString fullPath = SkOSPath::Join(partialPath.c_str(), baseName.c_str()); if (SkImageEncoder::EncodeFile(fullPath.c_str(), bm, SkImageEncoder::kPNG_Type, 100)) { return true; } else { SkDebugf("Failed to write the bitmap to %s.\n", fullPath.c_str()); return false; } }
static bool make_out_dirs() { SkString outDir = make_filepath(0, OUT_DIR, ""); if (!sk_exists(outDir.c_str())) { if (!sk_mkdir(outDir.c_str())) { SkDebugf("could not create dir %s\n", outDir.c_str()); return false; } } SkString grDir = make_filepath(0, outGrDir, ""); if (!sk_exists(grDir.c_str())) { if (!sk_mkdir(grDir.c_str())) { SkDebugf("could not create dir %s\n", grDir.c_str()); return false; } } SkString skDir = make_filepath(0, outSkDir, ""); if (!sk_exists(skDir.c_str())) { if (!sk_mkdir(skDir.c_str())) { SkDebugf("could not create dir %s\n", skDir.c_str()); return false; } } SkString skpDir = make_filepath(0, outSkpDir, ""); if (!sk_exists(skpDir.c_str())) { if (!sk_mkdir(skpDir.c_str())) { SkDebugf("could not create dir %s\n", skpDir.c_str()); return false; } } SkString diffDir = make_filepath(0, outDiffDir, ""); if (!sk_exists(diffDir.c_str())) { if (!sk_mkdir(diffDir.c_str())) { SkDebugf("could not create dir %s\n", diffDir.c_str()); return false; } } SkString statusDir = make_filepath(0, outStatusDir, ""); if (!sk_exists(statusDir.c_str())) { if (!sk_mkdir(statusDir.c_str())) { SkDebugf("could not create dir %s\n", statusDir.c_str()); return false; } } return true; }
void WriteTask::makeDirOrFail(SkString dir) { if (!sk_mkdir(dir.c_str())) { this->fail(); } }
void SkDiffContext::setWhiteDiffDir(const SkString& path) { if (!path.isEmpty() && sk_mkdir(path.c_str())) { fWhiteDiffDir = path; } }
void SkDiffContext::setAlphaMaskDir(const SkString& path) { if (!path.isEmpty() && sk_mkdir(path.c_str())) { fAlphaMaskDir = path; } }
/// Creates difference images, returns the number that have a 0 metric. /// If outputDir.isEmpty(), don't write out diff files. static void create_diff_images (DiffMetricProc dmp, const int colorThreshold, RecordArray* differences, const SkString& baseDir, const SkString& comparisonDir, const SkString& outputDir, const StringArray& matchSubstrings, const StringArray& nomatchSubstrings, bool recurseIntoSubdirs, bool getBounds, bool verbose, DiffSummary* summary) { SkASSERT(!baseDir.isEmpty()); SkASSERT(!comparisonDir.isEmpty()); FileArray baseFiles; FileArray comparisonFiles; get_file_list(baseDir, matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, &baseFiles); get_file_list(comparisonDir, matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, &comparisonFiles); if (!baseFiles.isEmpty()) { qsort(baseFiles.begin(), baseFiles.count(), sizeof(SkString*), SkCastForQSort(compare_file_name_metrics)); } if (!comparisonFiles.isEmpty()) { qsort(comparisonFiles.begin(), comparisonFiles.count(), sizeof(SkString*), SkCastForQSort(compare_file_name_metrics)); } if (!outputDir.isEmpty()) { sk_mkdir(outputDir.c_str()); } int i = 0; int j = 0; while (i < baseFiles.count() && j < comparisonFiles.count()) { SkString basePath(baseDir); SkString comparisonPath(comparisonDir); DiffRecord *drp = new DiffRecord; int v = strcmp(baseFiles[i]->c_str(), comparisonFiles[j]->c_str()); if (v < 0) { // in baseDir, but not in comparisonDir drp->fResult = DiffRecord::kCouldNotCompare_Result; basePath.append(*baseFiles[i]); comparisonPath.append(*baseFiles[i]); drp->fBase.fFilename = *baseFiles[i]; drp->fBase.fFullPath = basePath; drp->fBase.fStatus = DiffResource::kExists_Status; drp->fComparison.fFilename = *baseFiles[i]; drp->fComparison.fFullPath = comparisonPath; drp->fComparison.fStatus = DiffResource::kDoesNotExist_Status; VERBOSE_STATUS("MISSING", ANSI_COLOR_YELLOW, baseFiles[i]); ++i; } else if (v > 0) { // in comparisonDir, but not in baseDir drp->fResult = DiffRecord::kCouldNotCompare_Result; basePath.append(*comparisonFiles[j]); comparisonPath.append(*comparisonFiles[j]); drp->fBase.fFilename = *comparisonFiles[j]; drp->fBase.fFullPath = basePath; drp->fBase.fStatus = DiffResource::kDoesNotExist_Status; drp->fComparison.fFilename = *comparisonFiles[j]; drp->fComparison.fFullPath = comparisonPath; drp->fComparison.fStatus = DiffResource::kExists_Status; VERBOSE_STATUS("MISSING", ANSI_COLOR_YELLOW, comparisonFiles[j]); ++j; } else { // Found the same filename in both baseDir and comparisonDir. SkASSERT(DiffRecord::kUnknown_Result == drp->fResult); basePath.append(*baseFiles[i]); comparisonPath.append(*comparisonFiles[j]); drp->fBase.fFilename = *baseFiles[i]; drp->fBase.fFullPath = basePath; drp->fBase.fStatus = DiffResource::kExists_Status; drp->fComparison.fFilename = *comparisonFiles[j]; drp->fComparison.fFullPath = comparisonPath; drp->fComparison.fStatus = DiffResource::kExists_Status; sk_sp<SkData> baseFileBits(read_file(drp->fBase.fFullPath.c_str())); if (baseFileBits) { drp->fBase.fStatus = DiffResource::kRead_Status; } sk_sp<SkData> comparisonFileBits(read_file(drp->fComparison.fFullPath.c_str())); if (comparisonFileBits) { drp->fComparison.fStatus = DiffResource::kRead_Status; } if (nullptr == baseFileBits || nullptr == comparisonFileBits) { if (nullptr == baseFileBits) { drp->fBase.fStatus = DiffResource::kCouldNotRead_Status; VERBOSE_STATUS("READ FAIL", ANSI_COLOR_RED, baseFiles[i]); } if (nullptr == comparisonFileBits) { drp->fComparison.fStatus = DiffResource::kCouldNotRead_Status; VERBOSE_STATUS("READ FAIL", ANSI_COLOR_RED, comparisonFiles[j]); } drp->fResult = DiffRecord::kCouldNotCompare_Result; } else if (are_buffers_equal(baseFileBits.get(), comparisonFileBits.get())) { drp->fResult = DiffRecord::kEqualBits_Result; VERBOSE_STATUS("MATCH", ANSI_COLOR_GREEN, baseFiles[i]); } else { AutoReleasePixels arp(drp); get_bitmap(baseFileBits.get(), drp->fBase, false); get_bitmap(comparisonFileBits.get(), drp->fComparison, false); VERBOSE_STATUS("DIFFERENT", ANSI_COLOR_RED, baseFiles[i]); if (DiffResource::kDecoded_Status == drp->fBase.fStatus && DiffResource::kDecoded_Status == drp->fComparison.fStatus) { create_and_write_diff_image(drp, dmp, colorThreshold, outputDir, drp->fBase.fFilename); } else { drp->fResult = DiffRecord::kCouldNotCompare_Result; } } ++i; ++j; } if (getBounds) { get_bounds(*drp); } SkASSERT(DiffRecord::kUnknown_Result != drp->fResult); differences->push(drp); summary->add(drp); } for (; i < baseFiles.count(); ++i) { // files only in baseDir DiffRecord *drp = new DiffRecord(); drp->fBase.fFilename = *baseFiles[i]; drp->fBase.fFullPath = baseDir; drp->fBase.fFullPath.append(drp->fBase.fFilename); drp->fBase.fStatus = DiffResource::kExists_Status; drp->fComparison.fFilename = *baseFiles[i]; drp->fComparison.fFullPath = comparisonDir; drp->fComparison.fFullPath.append(drp->fComparison.fFilename); drp->fComparison.fStatus = DiffResource::kDoesNotExist_Status; drp->fResult = DiffRecord::kCouldNotCompare_Result; if (getBounds) { get_bounds(*drp); } differences->push(drp); summary->add(drp); } for (; j < comparisonFiles.count(); ++j) { // files only in comparisonDir DiffRecord *drp = new DiffRecord(); drp->fBase.fFilename = *comparisonFiles[j]; drp->fBase.fFullPath = baseDir; drp->fBase.fFullPath.append(drp->fBase.fFilename); drp->fBase.fStatus = DiffResource::kDoesNotExist_Status; drp->fComparison.fFilename = *comparisonFiles[j]; drp->fComparison.fFullPath = comparisonDir; drp->fComparison.fFullPath.append(drp->fComparison.fFilename); drp->fComparison.fStatus = DiffResource::kExists_Status; drp->fResult = DiffRecord::kCouldNotCompare_Result; if (getBounds) { get_bounds(*drp); } differences->push(drp); summary->add(drp); } release_file_list(&baseFiles); release_file_list(&comparisonFiles); }
int tool_main_core(int argc, char** argv) { SkCommandLineFlags::Parse(argc, argv); SkAutoGraphics ag; SkString outputDir; if (FLAGS_outputDir.count() > 0) { outputDir = FLAGS_outputDir[0]; if (!sk_mkdir(outputDir.c_str())) { SkDebugf("Unable to mkdir '%s'\n", outputDir.c_str()); return 1; } } SkTArray<SkString> files; process_input_files(FLAGS_inputPaths, &files); size_t maximumPathLength = 0; for (int i = 0; i < files.count(); i ++) { SkString basename = SkOSPath::Basename(files[i].c_str()); maximumPathLength = SkTMax(maximumPathLength, basename.size()); } int failures = 0; for (int i = 0; i < files.count(); i ++) { SkString basename = SkOSPath::Basename(files[i].c_str()); SkFILEStream inputStream; inputStream.setPath(files[i].c_str()); if (!inputStream.isValid()) { SkDebugf("Could not open file %s\n", files[i].c_str()); ++failures; continue; } SkAutoTUnref<SkPicture> picture( SkPicture::CreateFromStream(&inputStream)); if (NULL == picture.get()) { SkDebugf("Could not read an SkPicture from %s\n", files[i].c_str()); ++failures; continue; } SkDebugf("[%6g %6g %6g %6g] %-*s", picture->cullRect().fLeft, picture->cullRect().fTop, picture->cullRect().fRight, picture->cullRect().fBottom, maximumPathLength, basename.c_str()); SkAutoTDelete<SkWStream> stream(open_stream(outputDir, files[i])); if (!stream.get()) { ++failures; continue; } if (!pdf_to_stream(picture, stream.get())) { SkDebugf("Error in PDF Serialization."); ++failures; } int max_rss_mb = sk_tools::getMaxResidentSetSizeMB(); if (max_rss_mb >= 0) { SkDebugf(" %4dM peak rss", max_rss_mb); } SkDebugf("\n"); } if (failures != 0) { SkDebugf("Failed to render %i of %i PDFs.\n", failures, files.count()); return 1; } return 0; }