static bool render_picture(const SkString& inputPath, const SkString* outputDir, sk_tools::PictureRenderer& renderer, SkBitmap** out, int clones) { SkString inputFilename; sk_tools::get_basename(&inputFilename, inputPath); SkFILEStream inputStream; inputStream.setPath(inputPath.c_str()); if (!inputStream.isValid()) { SkDebugf("Could not open file %s\n", inputPath.c_str()); return false; } bool success = false; SkPicture* picture = SkNEW_ARGS(SkPicture, (&inputStream, &success, &SkImageDecoder::DecodeStream)); if (!success) { SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str()); return false; } for (int i = 0; i < clones; ++i) { SkPicture* clone = picture->clone(); SkDELETE(picture); picture = clone; } SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(), inputPath.c_str()); renderer.init(picture); renderer.setup(); SkString* outputPath = NULL; if (NULL != outputDir) { outputPath = SkNEW(SkString); make_output_filepath(outputPath, *outputDir, inputFilename); } success = renderer.render(outputPath, out); if (outputPath) { if (!success) { SkDebugf("Could not write to file %s\n", outputPath->c_str()); } SkDELETE(outputPath); } renderer.resetState(); renderer.end(); SkDELETE(picture); 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; }
/** * Called only by render_picture(). */ static bool render_picture_internal(const SkString& inputPath, const SkString* outputDir, sk_tools::PictureRenderer& renderer, SkBitmap** out) { SkString inputFilename; sk_tools::get_basename(&inputFilename, inputPath); SkString outputDirString; if (NULL != outputDir && outputDir->size() > 0 && !FLAGS_writeEncodedImages) { outputDirString.set(*outputDir); } SkFILEStream inputStream; inputStream.setPath(inputPath.c_str()); if (!inputStream.isValid()) { SkDebugf("Could not open file %s\n", inputPath.c_str()); return false; } SkPicture::InstallPixelRefProc proc; if (FLAGS_deferImageDecoding) { proc = &sk_tools::LazyDecodeBitmap; } else if (FLAGS_writeEncodedImages) { SkASSERT(!FLAGS_writePath.isEmpty()); reset_image_file_base_name(inputFilename); proc = &write_image_to_file; } else { proc = &SkImageDecoder::DecodeMemory; } SkDebugf("deserializing... %s\n", inputPath.c_str()); SkPicture* picture = SkPicture::CreateFromStream(&inputStream, proc); if (NULL == picture) { SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str()); return false; } while (FLAGS_bench_record) { const int kRecordFlags = 0; SkPicture other; picture->draw(other.beginRecording(picture->width(), picture->height(), kRecordFlags)); other.endRecording(); } for (int i = 0; i < FLAGS_clone; ++i) { SkPicture* clone = picture->clone(); SkDELETE(picture); picture = clone; } SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(), inputPath.c_str()); renderer.init(picture, &outputDirString, &inputFilename, FLAGS_writeChecksumBasedFilenames); if (FLAGS_preprocess) { if (NULL != renderer.getCanvas()) { renderer.getCanvas()->EXPERIMENTAL_optimize(picture); } } renderer.setup(); bool success = renderer.render(out); if (!success) { SkDebugf("Failed to render %s\n", inputFilename.c_str()); } renderer.end(); SkDELETE(picture); 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); 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. * * @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; }
/** * Called only by render_picture(). */ static bool render_picture_internal(const SkString& inputPath, const SkString* writePath, const SkString* mismatchPath, sk_tools::PictureRenderer& renderer, SkBitmap** out) { SkString inputFilename = SkOSPath::Basename(inputPath.c_str()); SkString writePathString; if (writePath && writePath->size() > 0 && !FLAGS_writeEncodedImages) { writePathString.set(*writePath); } SkString mismatchPathString; if (mismatchPath && mismatchPath->size() > 0) { mismatchPathString.set(*mismatchPath); } SkFILEStream inputStream; inputStream.setPath(inputPath.c_str()); if (!inputStream.isValid()) { SkDebugf("Could not open file %s\n", inputPath.c_str()); return false; } SkPicture::InstallPixelRefProc proc; if (FLAGS_deferImageDecoding) { proc = &sk_tools::LazyDecodeBitmap; } else if (FLAGS_writeEncodedImages) { SkASSERT(!FLAGS_writePath.isEmpty()); reset_image_file_base_name(inputFilename); proc = &write_image_to_file; } else { proc = &SkImageDecoder::DecodeMemory; } SkDebugf("deserializing... %s\n", inputPath.c_str()); SkAutoTUnref<SkPicture> picture(SkPicture::CreateFromStream(&inputStream, proc)); if (NULL == picture) { SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str()); return false; } while (FLAGS_bench_record) { SkPictureRecorder recorder; picture->playback(recorder.beginRecording(picture->cullRect().width(), picture->cullRect().height(), NULL, 0)); SkAutoTUnref<SkPicture> other(recorder.endRecording()); } SkDebugf("drawing... [%f %f %f %f] %s\n", picture->cullRect().fLeft, picture->cullRect().fTop, picture->cullRect().fRight, picture->cullRect().fBottom, inputPath.c_str()); renderer.init(picture, &writePathString, &mismatchPathString, &inputFilename, FLAGS_writeChecksumBasedFilenames, FLAGS_mpd); renderer.setup(); renderer.enableWrites(); bool success = renderer.render(out); if (!success) { SkDebugf("Failed to render %s\n", inputFilename.c_str()); } renderer.end(); return success; }