/** * Render the SKP file(s) within inputPath, writing their bitmap images into outputDir. * * @param inputPath path to an individual SKP file, or a directory of SKP files * @param outputDir if not NULL, write the image(s) generated into this directory * @param renderer PictureRenderer to use to render the SKPs * @param jsonSummaryPtr if not NULL, add the image(s) generated to this summary */ static bool render_picture(const SkString& inputPath, const SkString* outputDir, sk_tools::PictureRenderer& renderer, sk_tools::ImageResultsSummary *jsonSummaryPtr) { int diffs[256] = {0}; SkBitmap* bitmap = NULL; renderer.setJsonSummaryPtr(jsonSummaryPtr); bool success = render_picture_internal(inputPath, FLAGS_writeWholeImage ? NULL : outputDir, renderer, FLAGS_validate || FLAGS_writeWholeImage ? &bitmap : NULL); if (!success || ((FLAGS_validate || FLAGS_writeWholeImage) && bitmap == NULL)) { SkDebugf("Failed to draw the picture.\n"); SkDELETE(bitmap); return false; } if (FLAGS_validate) { SkBitmap* referenceBitmap = NULL; sk_tools::PictureRenderer* referenceRenderer; // If the renderer uses a BBoxHierarchy, then the reference renderer // will be the same renderer, without the bbh. AutoRestoreBbhType arbbh; if (sk_tools::PictureRenderer::kNone_BBoxHierarchyType != renderer.getBBoxHierarchyType()) { referenceRenderer = &renderer; referenceRenderer->ref(); // to match auto unref below arbbh.set(referenceRenderer, sk_tools::PictureRenderer::kNone_BBoxHierarchyType); } else { referenceRenderer = SkNEW(sk_tools::SimplePictureRenderer); } SkAutoTUnref<sk_tools::PictureRenderer> aurReferenceRenderer(referenceRenderer); success = render_picture_internal(inputPath, NULL, *referenceRenderer, &referenceBitmap); if (!success || NULL == referenceBitmap || NULL == referenceBitmap->getPixels()) { SkDebugf("Failed to draw the reference picture.\n"); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } if (success && (bitmap->width() != referenceBitmap->width())) { SkDebugf("Expected image width: %i, actual image width %i.\n", referenceBitmap->width(), bitmap->width()); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } if (success && (bitmap->height() != referenceBitmap->height())) { SkDebugf("Expected image height: %i, actual image height %i", referenceBitmap->height(), bitmap->height()); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } for (int y = 0; success && y < bitmap->height(); y++) { for (int x = 0; success && x < bitmap->width(); x++) { int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y), *bitmap->getAddr32(x, y)); SkASSERT(diff >= 0 && diff <= 255); diffs[diff]++; if (diff > FLAGS_maxComponentDiff) { SkDebugf("Expected pixel at (%i %i) exceedds maximum " "component diff of %i: 0x%x, actual 0x%x\n", x, y, FLAGS_maxComponentDiff, *referenceBitmap->getAddr32(x, y), *bitmap->getAddr32(x, y)); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } } } SkDELETE(referenceBitmap); for (int i = 1; i <= 255; ++i) { if(diffs[i] > 0) { SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]); } } } if (FLAGS_writeWholeImage) { sk_tools::force_all_opaque(*bitmap); SkString inputFilename, outputPath; sk_tools::get_basename(&inputFilename, inputPath); sk_tools::make_filepath(&outputPath, *outputDir, inputFilename); sk_tools::replace_char(&outputPath, '.', '_'); outputPath.append(".png"); if (NULL != jsonSummaryPtr) { SkString outputFileBasename; sk_tools::get_basename(&outputFileBasename, outputPath); jsonSummaryPtr->add(inputFilename.c_str(), outputFileBasename.c_str(), *bitmap); } if (NULL != outputDir) { if (!SkImageEncoder::EncodeFile(outputPath.c_str(), *bitmap, SkImageEncoder::kPNG_Type, 100)) { SkDebugf("Failed to draw the picture.\n"); success = false; } } } SkDELETE(bitmap); return success; }
/** * Render the SKP file(s) within inputPath, writing their bitmap images into outputDir. * * @param inputPath path to an individual SKP file, or a directory of SKP files * @param outputDir if not NULL, write the image(s) generated into this directory * @param renderer PictureRenderer to use to render the SKPs * @param jsonSummaryPtr if not NULL, add the image(s) generated to this summary */ static bool render_picture(const SkString& inputPath, const SkString* outputDir, sk_tools::PictureRenderer& renderer, sk_tools::ImageResultsSummary *jsonSummaryPtr) { int diffs[256] = {0}; SkBitmap* bitmap = NULL; renderer.setJsonSummaryPtr(jsonSummaryPtr); bool success = render_picture_internal(inputPath, FLAGS_writeWholeImage ? NULL : outputDir, renderer, FLAGS_validate || FLAGS_writeWholeImage ? &bitmap : NULL); if (!success || ((FLAGS_validate || FLAGS_writeWholeImage) && bitmap == NULL)) { SkDebugf("Failed to draw the picture.\n"); SkDELETE(bitmap); return false; } if (FLAGS_validate) { SkBitmap* referenceBitmap = NULL; sk_tools::PictureRenderer* referenceRenderer; // If the renderer uses a BBoxHierarchy, then the reference renderer // will be the same renderer, without the bbh. AutoRestoreBbhType arbbh; if (sk_tools::PictureRenderer::kNone_BBoxHierarchyType != renderer.getBBoxHierarchyType()) { referenceRenderer = &renderer; referenceRenderer->ref(); // to match auto unref below arbbh.set(referenceRenderer, sk_tools::PictureRenderer::kNone_BBoxHierarchyType); } else { referenceRenderer = SkNEW(sk_tools::SimplePictureRenderer); } SkAutoTUnref<sk_tools::PictureRenderer> aurReferenceRenderer(referenceRenderer); success = render_picture_internal(inputPath, NULL, *referenceRenderer, &referenceBitmap); if (!success || NULL == referenceBitmap || NULL == referenceBitmap->getPixels()) { SkDebugf("Failed to draw the reference picture.\n"); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } if (success && (bitmap->width() != referenceBitmap->width())) { SkDebugf("Expected image width: %i, actual image width %i.\n", referenceBitmap->width(), bitmap->width()); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } if (success && (bitmap->height() != referenceBitmap->height())) { SkDebugf("Expected image height: %i, actual image height %i", referenceBitmap->height(), bitmap->height()); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } for (int y = 0; success && y < bitmap->height(); y++) { for (int x = 0; success && x < bitmap->width(); x++) { int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y), *bitmap->getAddr32(x, y)); SkASSERT(diff >= 0 && diff <= 255); diffs[diff]++; if (diff > FLAGS_maxComponentDiff) { SkDebugf("Expected pixel at (%i %i) exceedds maximum " "component diff of %i: 0x%x, actual 0x%x\n", x, y, FLAGS_maxComponentDiff, *referenceBitmap->getAddr32(x, y), *bitmap->getAddr32(x, y)); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } } } SkDELETE(referenceBitmap); for (int i = 1; i <= 255; ++i) { if(diffs[i] > 0) { SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]); } } } if (FLAGS_writeWholeImage) { sk_tools::force_all_opaque(*bitmap); if (NULL != jsonSummaryPtr) { // TODO(epoger): This is a hacky way of constructing the filename associated with the // image checksum; we basically are repeating the logic of make_output_filepath() // and code below here, within here. // It would be better for the filename (without outputDir) to be passed in here, // and used both for the checksum file and writing into outputDir. // // TODO(epoger): what about including the config type within hashFilename? That way, // we could combine results of different config types without conflicting filenames. SkString hashFilename; sk_tools::get_basename(&hashFilename, inputPath); hashFilename.remove(hashFilename.size() - 4, 4); // Remove ".skp" hashFilename.append(".png"); jsonSummaryPtr->add(hashFilename.c_str(), *bitmap); } if (NULL != outputDir) { SkString inputFilename; sk_tools::get_basename(&inputFilename, inputPath); SkString outputPath; make_output_filepath(&outputPath, *outputDir, inputFilename); outputPath.append(".png"); if (!SkImageEncoder::EncodeFile(outputPath.c_str(), *bitmap, SkImageEncoder::kPNG_Type, 100)) { SkDebugf("Failed to draw the picture.\n"); success = false; } } } SkDELETE(bitmap); return success; }
/** * Render the SKP file(s) within inputPath. * * @param inputPath path to an individual SKP file, or a directory of SKP files * @param writePath if not NULL, write all image(s) generated into this directory * @param mismatchPath if not NULL, write any image(s) not matching expectations into this directory * @param renderer PictureRenderer to use to render the SKPs * @param jsonSummaryPtr if not NULL, add the image(s) generated to this summary */ static bool render_picture(const SkString& inputPath, const SkString* writePath, const SkString* mismatchPath, sk_tools::PictureRenderer& renderer, sk_tools::ImageResultsAndExpectations *jsonSummaryPtr) { int diffs[256] = {0}; SkBitmap* bitmap = NULL; renderer.setJsonSummaryPtr(jsonSummaryPtr); bool success = render_picture_internal(inputPath, FLAGS_writeWholeImage ? NULL : writePath, FLAGS_writeWholeImage ? NULL : mismatchPath, renderer, FLAGS_validate || FLAGS_writeWholeImage ? &bitmap : NULL); if (!success || ((FLAGS_validate || FLAGS_writeWholeImage) && bitmap == NULL)) { SkDebugf("Failed to draw the picture.\n"); delete bitmap; return false; } if (FLAGS_validate) { SkBitmap* referenceBitmap = NULL; sk_tools::PictureRenderer* referenceRenderer; // If the renderer uses a BBoxHierarchy, then the reference renderer // will be the same renderer, without the bbh. AutoRestoreBbhType arbbh; if (sk_tools::PictureRenderer::kNone_BBoxHierarchyType != renderer.getBBoxHierarchyType()) { referenceRenderer = &renderer; referenceRenderer->ref(); // to match auto unref below arbbh.set(referenceRenderer, sk_tools::PictureRenderer::kNone_BBoxHierarchyType); } else { #if SK_SUPPORT_GPU referenceRenderer = new sk_tools::SimplePictureRenderer(renderer.getGrContextOptions()); #else referenceRenderer = new sk_tools::SimplePictureRenderer; #endif } SkAutoTUnref<sk_tools::PictureRenderer> aurReferenceRenderer(referenceRenderer); success = render_picture_internal(inputPath, NULL, NULL, *referenceRenderer, &referenceBitmap); if (!success || NULL == referenceBitmap || NULL == referenceBitmap->getPixels()) { SkDebugf("Failed to draw the reference picture.\n"); delete bitmap; delete referenceBitmap; return false; } if (success && (bitmap->width() != referenceBitmap->width())) { SkDebugf("Expected image width: %i, actual image width %i.\n", referenceBitmap->width(), bitmap->width()); delete bitmap; delete referenceBitmap; return false; } if (success && (bitmap->height() != referenceBitmap->height())) { SkDebugf("Expected image height: %i, actual image height %i", referenceBitmap->height(), bitmap->height()); delete bitmap; delete referenceBitmap; return false; } for (int y = 0; success && y < bitmap->height(); y++) { for (int x = 0; success && x < bitmap->width(); x++) { int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y), *bitmap->getAddr32(x, y)); SkASSERT(diff >= 0 && diff <= 255); diffs[diff]++; if (diff > FLAGS_maxComponentDiff) { SkDebugf("Expected pixel at (%i %i) exceedds maximum " "component diff of %i: 0x%x, actual 0x%x\n", x, y, FLAGS_maxComponentDiff, *referenceBitmap->getAddr32(x, y), *bitmap->getAddr32(x, y)); delete bitmap; delete referenceBitmap; return false; } } } delete referenceBitmap; for (int i = 1; i <= 255; ++i) { if(diffs[i] > 0) { SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]); } } } if (FLAGS_writeWholeImage) { sk_tools::force_all_opaque(*bitmap); SkString inputFilename = SkOSPath::Basename(inputPath.c_str()); SkString outputFilename(inputFilename); sk_tools::replace_char(&outputFilename, '.', '_'); outputFilename.append(".png"); if (jsonSummaryPtr) { sk_tools::ImageDigest imageDigest(*bitmap); jsonSummaryPtr->add(inputFilename.c_str(), outputFilename.c_str(), imageDigest); if ((mismatchPath) && !mismatchPath->isEmpty() && !jsonSummaryPtr->getExpectation(inputFilename.c_str()).matches(imageDigest)) { success &= sk_tools::write_bitmap_to_disk(*bitmap, *mismatchPath, NULL, outputFilename); } } if ((writePath) && !writePath->isEmpty()) { success &= sk_tools::write_bitmap_to_disk(*bitmap, *writePath, NULL, outputFilename); } } delete bitmap; return success; }