1e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com/* 2e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com * Copyright 2012 Google Inc. 3e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com * 4e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com * Use of this source code is governed by a BSD-style license that can be 5e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com * found in the LICENSE file. 6e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com */ 7e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "skdiff.h" 8e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "skdiff_utils.h" 9e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "SkBitmap.h" 10e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "SkData.h" 11e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "SkImageEncoder.h" 12e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "SkOSFile.h" 13e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "SkTypes.h" 14e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 1516b2dd05f0c5faca90b101c28ea01ff80257408abungeman@google.com#include <stdio.h> 1616b2dd05f0c5faca90b101c28ea01ff80257408abungeman@google.com 17e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com/// If outputDir.isEmpty(), don't write out diff files. 18e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic void create_diff_images (DiffMetricProc dmp, 19e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const int colorThreshold, 20e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const SkString& baseFile, 21e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const SkString& comparisonFile, 22e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const SkString& outputDir, 23e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const SkString& outputFilename, 24e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com DiffRecord* drp) { 25e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkASSERT(!baseFile.isEmpty()); 26e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkASSERT(!comparisonFile.isEmpty()); 27e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 28e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fBase.fFilename = baseFile; 29e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fBase.fFullPath = baseFile; 30e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fBase.fStatus = DiffResource::kSpecified_Status; 31e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 32e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fComparison.fFilename = comparisonFile; 33e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fComparison.fFullPath = comparisonFile; 34e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fComparison.fStatus = DiffResource::kSpecified_Status; 35e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 36fe9172705791848ebfe5b5630973b7e67305f64cbungeman sk_sp<SkData> baseFileBits = read_file(drp->fBase.fFullPath.c_str()); 3749f085dddff10473b6ebf832a974288300224e60bsalomon if (baseFileBits) { 38e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fBase.fStatus = DiffResource::kRead_Status; 39e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 40fe9172705791848ebfe5b5630973b7e67305f64cbungeman sk_sp<SkData> comparisonFileBits = read_file(drp->fComparison.fFullPath.c_str()); 4149f085dddff10473b6ebf832a974288300224e60bsalomon if (comparisonFileBits) { 42e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fComparison.fStatus = DiffResource::kRead_Status; 43e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 4496fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (nullptr == baseFileBits || nullptr == comparisonFileBits) { 4596fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (nullptr == baseFileBits) { 46e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fBase.fStatus = DiffResource::kCouldNotRead_Status; 47e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 4896fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (nullptr == comparisonFileBits) { 49e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fComparison.fStatus = DiffResource::kCouldNotRead_Status; 50e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 51e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fResult = DiffRecord::kCouldNotCompare_Result; 52e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 53e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 54e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 55fe9172705791848ebfe5b5630973b7e67305f64cbungeman if (are_buffers_equal(baseFileBits.get(), comparisonFileBits.get())) { 56e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fResult = DiffRecord::kEqualBits_Result; 57e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 58e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 59e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 60667433ff5bc65680af31ca718d4cc29cce7b7040msarett get_bitmap(baseFileBits, drp->fBase, false); 61667433ff5bc65680af31ca718d4cc29cce7b7040msarett get_bitmap(comparisonFileBits, drp->fComparison, false); 62e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (DiffResource::kDecoded_Status != drp->fBase.fStatus || 63e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com DiffResource::kDecoded_Status != drp->fComparison.fStatus) 64e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com { 65e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com drp->fResult = DiffRecord::kCouldNotCompare_Result; 66e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 67e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 68e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 69e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com create_and_write_diff_image(drp, dmp, colorThreshold, outputDir, outputFilename); 70e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com //TODO: copy fBase.fFilename and fComparison.fFilename to outputDir 71e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // svn and git often present tmp files to diff tools which are promptly deleted 72e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 73e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com //TODO: serialize drp to outputDir 74e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // write a tool to deserialize them and call print_diff_page 75e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 76e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkASSERT(DiffRecord::kUnknown_Result != drp->fResult); 77e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 78e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 79e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic void usage (char * argv0) { 80e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("Skia image diff tool\n"); 81e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("\n" 82e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"Usage: \n" 83e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com" %s <baseFile> <comparisonFile>\n" , argv0); 84e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf( 85e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\nArguments:" 86e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n --failonresult <result>: After comparing all file pairs, exit with nonzero" 87e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n return code (number of file pairs yielding this" 88e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n result) if any file pairs yielded this result." 89e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n This flag may be repeated, in which case the" 90e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n return code will be the number of fail pairs" 91e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n yielding ANY of these results." 92e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n --failonstatus <baseStatus> <comparisonStatus>: exit with nonzero return" 93e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n code if any file pairs yeilded this status." 94e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n --help: display this info" 95e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n --listfilenames: list all filenames for each result type in stdout" 96e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n --nodiffs: don't write out image diffs, just generate report on stdout" 97e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n --outputdir: directory to write difference images" 98e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n --threshold <n>: only report differences > n (per color channel) [default 0]" 99e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n -u: ignored. Recognized for compatibility with svn diff." 100e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n -L: first occurrence label for base, second occurrence label for comparison." 101e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n Labels must be of the form \"<filename>(\t<specifier>)?\"." 102e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n The base <filename> will be used to create files in outputdir." 103e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n" 104e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n baseFile: baseline image file." 105e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n comparisonFile: comparison image file" 106e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n" 107e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\nIf no sort is specified, it will sort by fraction of pixels mismatching." 108e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com"\n"); 109e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 110e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 111e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comconst int kNoError = 0; 112e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comconst int kGenericError = -1; 113e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 114be28ee2974474800323ce4fabf62a839018be591Mike Kleinint main(int argc, char** argv) { 115e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com DiffMetricProc diffProc = compute_diff_pmcolor; 116e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 117e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Maximum error tolerated in any one color channel in any one pixel before 118e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // a difference is reported. 119e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com int colorThreshold = 0; 120e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkString baseFile; 121e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkString baseLabel; 122e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkString comparisonFile; 123e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkString comparisonLabel; 124e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkString outputDir; 125e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 126e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com bool listFilenames = false; 127e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 128e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com bool failOnResultType[DiffRecord::kResultCount]; 129e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com for (int i = 0; i < DiffRecord::kResultCount; i++) { 130e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com failOnResultType[i] = false; 131e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 132e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 133e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com bool failOnStatusType[DiffResource::kStatusCount][DiffResource::kStatusCount]; 134e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com for (int base = 0; base < DiffResource::kStatusCount; ++base) { 135e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) { 136e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com failOnStatusType[base][comparison] = false; 137e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 138e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 139e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 140e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com int i; 141e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com int numUnflaggedArguments = 0; 142e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com int numLabelArguments = 0; 143e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com for (i = 1; i < argc; i++) { 144e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!strcmp(argv[i], "--failonresult")) { 145e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (argc == ++i) { 146e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("failonresult expects one argument.\n"); 147e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 148e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 149e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com DiffRecord::Result type = DiffRecord::getResultByName(argv[i]); 150e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (type != DiffRecord::kResultCount) { 151e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com failOnResultType[type] = true; 152e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } else { 153e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("ignoring unrecognized result <%s>\n", argv[i]); 154e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 155e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 156e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 157e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!strcmp(argv[i], "--failonstatus")) { 158e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (argc == ++i) { 159e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("failonstatus missing base status.\n"); 160e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 161e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 162e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com bool baseStatuses[DiffResource::kStatusCount]; 163e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!DiffResource::getMatchingStatuses(argv[i], baseStatuses)) { 164e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("unrecognized base status <%s>\n", argv[i]); 165e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 166e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 167e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (argc == ++i) { 168e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("failonstatus missing comparison status.\n"); 169e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 170e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 171e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com bool comparisonStatuses[DiffResource::kStatusCount]; 172e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!DiffResource::getMatchingStatuses(argv[i], comparisonStatuses)) { 173e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("unrecognized comarison status <%s>\n", argv[i]); 174e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 175e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 176e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com for (int base = 0; base < DiffResource::kStatusCount; ++base) { 177e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) { 178e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com failOnStatusType[base][comparison] |= 179e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com baseStatuses[base] && comparisonStatuses[comparison]; 180e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 181e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 182e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 183e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 184e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!strcmp(argv[i], "--help")) { 185e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com usage(argv[0]); 186e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return kNoError; 187e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 188e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!strcmp(argv[i], "--listfilenames")) { 189e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com listFilenames = true; 190e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 191e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 192e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!strcmp(argv[i], "--outputdir")) { 193e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (argc == ++i) { 194e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("outputdir expects one argument.\n"); 195e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 196e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 197e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com outputDir.set(argv[i]); 198e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 199e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 200e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!strcmp(argv[i], "--threshold")) { 201e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com colorThreshold = atoi(argv[++i]); 202e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 203e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 204e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!strcmp(argv[i], "-u")) { 205e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com //we don't produce unified diffs, ignore parameter to work with svn diff 206e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 207e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 208e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!strcmp(argv[i], "-L")) { 209e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (argc == ++i) { 210e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("label expects one argument.\n"); 211e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 212e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 213e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com switch (numLabelArguments++) { 214e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case 0: 215e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com baseLabel.set(argv[i]); 216e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 217e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case 1: 218e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com comparisonLabel.set(argv[i]); 219e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 220e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com default: 221e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("extra label argument <%s>\n", argv[i]); 222e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com usage(argv[0]); 223e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return kGenericError; 224e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 225e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 226e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 227e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (argv[i][0] != '-') { 228e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com switch (numUnflaggedArguments++) { 229e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case 0: 230e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com baseFile.set(argv[i]); 231e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 232e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case 1: 233e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com comparisonFile.set(argv[i]); 234e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 235e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com default: 236e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("extra unflagged argument <%s>\n", argv[i]); 237e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com usage(argv[0]); 238e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return kGenericError; 239e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 240e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 241e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 242e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDebugf("Unrecognized argument <%s>\n", argv[i]); 243e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com usage(argv[0]); 244e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return kGenericError; 245e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 246e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 247e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (numUnflaggedArguments != 2) { 248e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com usage(argv[0]); 249e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return kGenericError; 250e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 251e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 252e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (listFilenames) { 253e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("Base file is [%s]\n", baseFile.c_str()); 254e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 255e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 256e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (listFilenames) { 257e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("Comparison file is [%s]\n", comparisonFile.c_str()); 258e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 259e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 260e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (outputDir.isEmpty()) { 261e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (listFilenames) { 262e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("Not writing any diffs. No output dir specified.\n"); 263e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 264e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } else { 265e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!outputDir.endsWith(PATH_DIV_STR)) { 266e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com outputDir.append(PATH_DIV_STR); 267e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 268e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (listFilenames) { 269e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("Writing diffs. Output dir is [%s]\n", outputDir.c_str()); 270e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 271e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 272e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 273e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Some obscure documentation about diff/patch labels: 274e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // 275e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Posix says the format is: <filename><tab><date> 276e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // It also states that if a filename contains <tab> or <newline> 277e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // the result is implementation defined 278e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // 279e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Svn diff --diff-cmd provides labels of the form: <filename><tab><revision> 280e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // 281e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Git diff --ext-diff does not supply arguments compatible with diff. 282e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // However, it does provide the filename directly. 283e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // skimagediff_git.sh: skimagediff %2 %5 -L "%1\t(%3)" -L "%1\t(%6)" 284e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // 285e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Git difftool sets $LOCAL, $REMOTE, $MERGED, and $BASE instead of command line parameters. 286e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // difftool.<>.cmd: skimagediff $LOCAL $REMOTE -L "$MERGED\t(local)" -L "$MERGED\t(remote)" 287e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // 288e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Diff will write any specified label verbatim. Without a specified label diff will write 289e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // <filename><tab><date> 290e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // However, diff will encode the filename as a cstring if the filename contains 291e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Any of <space> or <double quote> 292e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // A char less than 32 2935b7bac5ce162eee6d73c33373029a4e5a9f94683bungeman@google.com // Any escapable character \\, \a, \b, \t, \n, \v, \f, \r 294e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // 295e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Patch decodes: 296e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // If first <non-white-space> is <double quote>, parse filename from cstring. 297e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // If there is a <tab> after the first <non-white-space>, filename is 298e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // [first <non-white-space>, the next run of <white-space> with an embedded <tab>). 299e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Otherwise the filename is [first <non-space>, the next <white-space>). 300e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // 301e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // The filename /dev/null means the file does not exist (used in adds and deletes). 302e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 303e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Considering the above, skimagediff will consider the contents of a -L parameter as 304e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // <filename>(\t<specifier>)? 305e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkString outputFile; 306e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 307e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (baseLabel.isEmpty()) { 308e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com baseLabel.set(baseFile); 309e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com outputFile = baseLabel; 310e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } else { 311e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const char* baseLabelCstr = baseLabel.c_str(); 312e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const char* tab = strchr(baseLabelCstr, '\t'); 31396fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (nullptr == tab) { 314e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com outputFile = baseLabel; 315e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } else { 316e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com outputFile.set(baseLabelCstr, tab - baseLabelCstr); 317e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 318e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 319e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (comparisonLabel.isEmpty()) { 320e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com comparisonLabel.set(comparisonFile); 321e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 322e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("Base: %s\n", baseLabel.c_str()); 323e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("Comparison: %s\n", comparisonLabel.c_str()); 324e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 325e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com DiffRecord dr; 326e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com create_diff_images(diffProc, colorThreshold, baseFile, comparisonFile, outputDir, outputFile, 327e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com &dr); 328e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 329e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (DiffResource::isStatusFailed(dr.fBase.fStatus)) { 330e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("Base %s.\n", DiffResource::getStatusDescription(dr.fBase.fStatus)); 331e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 332e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (DiffResource::isStatusFailed(dr.fComparison.fStatus)) { 333e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("Comparison %s.\n", DiffResource::getStatusDescription(dr.fComparison.fStatus)); 334e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 335e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("Base and Comparison %s.\n", DiffRecord::getResultDescription(dr.fResult)); 336e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 337e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (DiffRecord::kDifferentPixels_Result == dr.fResult) { 338e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("%.4f%% of pixels differ", 100 * dr.fFractionDifference); 339e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf(" (%.4f%% weighted)", 100 * dr.fWeightedFraction); 340e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (dr.fFractionDifference < 0.01) { 341e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf(" %d pixels", static_cast<int>(dr.fFractionDifference * 342e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com dr.fBase.fBitmap.width() * 343e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com dr.fBase.fBitmap.height())); 344e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 345e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 346e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("\nAverage color mismatch: "); 347e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("%d", static_cast<int>(MAX3(dr.fAverageMismatchR, 348e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com dr.fAverageMismatchG, 349e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com dr.fAverageMismatchB))); 350e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("\nMax color mismatch: "); 351e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("%d", MAX3(dr.fMaxMismatchR, 352e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com dr.fMaxMismatchG, 353e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com dr.fMaxMismatchB)); 354e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("\n"); 355e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 356e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com printf("\n"); 357e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 358e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com int num_failing_results = 0; 359e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (failOnResultType[dr.fResult]) { 360e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com ++num_failing_results; 361e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 362e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (failOnStatusType[dr.fBase.fStatus][dr.fComparison.fStatus]) { 363e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com ++num_failing_results; 364e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 365e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 366e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return num_failing_results; 367e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 368