/** * Test that for Jpeg files that use the JFIF colorspace, they are * directly embedded into the PDF (without re-encoding) when that * makes sense. */ DEF_TEST(PDFJpegEmbedTest, r) { const char test[] = "PDFJpegEmbedTest"; SkAutoTUnref<SkData> mandrillData( load_resource(r, test, "mandrill_512_q075.jpg")); SkAutoTUnref<SkData> cmykData(load_resource(r, test, "CMYK.jpg")); if (!mandrillData || !cmykData) { return; } //////////////////////////////////////////////////////////////////////////// SkDynamicMemoryWStream pdf; SkAutoTUnref<SkDocument> document(SkDocument::CreatePDF(&pdf)); SkCanvas* canvas = document->beginPage(642, 1028); canvas->clear(SK_ColorLTGRAY); SkBitmap bm1(bitmap_from_data(mandrillData)); canvas->drawBitmap(bm1, 65.0, 0.0, nullptr); SkBitmap bm2(bitmap_from_data(cmykData)); canvas->drawBitmap(bm2, 0.0, 512.0, nullptr); canvas->flush(); document->endPage(); document->close(); SkAutoTUnref<SkData> pdfData(pdf.copyToData()); SkASSERT(pdfData); pdf.reset(); REPORTER_ASSERT(r, is_subset_of(mandrillData, pdfData)); // This JPEG uses a nonstandard colorspace - it can not be // embedded into the PDF directly. REPORTER_ASSERT(r, !is_subset_of(cmykData, pdfData)); //////////////////////////////////////////////////////////////////////////// pdf.reset(); document.reset(SkDocument::CreatePDF(&pdf)); canvas = document->beginPage(642, 1028); canvas->clear(SK_ColorLTGRAY); SkAutoTUnref<SkImage> im1(SkImage::NewFromEncoded(mandrillData)); canvas->drawImage(im1, 65.0, 0.0, nullptr); SkAutoTUnref<SkImage> im2(SkImage::NewFromEncoded(cmykData)); canvas->drawImage(im2, 0.0, 512.0, nullptr); canvas->flush(); document->endPage(); document->close(); pdfData.reset(pdf.copyToData()); SkASSERT(pdfData); pdf.reset(); REPORTER_ASSERT(r, is_subset_of(mandrillData, pdfData)); // This JPEG uses a nonstandard colorspace - it can not be // embedded into the PDF directly. REPORTER_ASSERT(r, !is_subset_of(cmykData, pdfData)); }
void PipingBench::onDraw(int loops, SkCanvas*) { SkDynamicMemoryWStream stream; SkPipeSerializer serializer; while (loops --> 0) { fSrc->playback(serializer.beginWrite(fSrc->cullRect(), &stream)); serializer.endWrite(); stream.reset(); } }
// http://crbug.com/473572 DEF_TEST(SkPDF_OpaqueSrcModeToSrcOver, r) { REQUIRE_PDF_DOCUMENT(SkPDF_OpaqueSrcModeToSrcOver, r); SkDynamicMemoryWStream srcMode; SkDynamicMemoryWStream srcOverMode; U8CPU alpha = SK_AlphaOPAQUE; run_test(&srcMode, SkBlendMode::kSrc, alpha); run_test(&srcOverMode, SkBlendMode::kSrcOver, alpha); REPORTER_ASSERT(r, srcMode.bytesWritten() == srcOverMode.bytesWritten()); // The two PDFs should be equal because they have an opaque alpha. srcMode.reset(); srcOverMode.reset(); alpha = 0x80; run_test(&srcMode, SkBlendMode::kSrc, alpha); run_test(&srcOverMode, SkBlendMode::kSrcOver, alpha); REPORTER_ASSERT(r, srcMode.bytesWritten() > srcOverMode.bytesWritten()); // The two PDFs should not be equal because they have a non-opaque alpha. }
static void stream_copy_test(skiatest::Reporter* reporter, const void* srcData, size_t N, SkStream* stream) { SkDynamicMemoryWStream tgt; if (!SkStreamCopy(&tgt, stream)) { ERRORF(reporter, "SkStreamCopy failed"); return; } SkAutoTUnref<SkData> data(tgt.copyToData()); tgt.reset(); if (data->size() != N) { ERRORF(reporter, "SkStreamCopy incorrect size"); return; } if (0 != memcmp(data->data(), srcData, N)) { ERRORF(reporter, "SkStreamCopy bad copy"); } }
/** * Test that for Jpeg files that use the JFIF colorspace, they are * directly embedded into the PDF (without re-encoding) when that * makes sense. */ DEF_TEST(PDFJpegEmbedTest, r) { const char test[] = "PDFJpegEmbedTest"; SkAutoTUnref<SkData> mandrillData( load_resource(r, test, "mandrill_512_q075.jpg")); SkAutoTUnref<SkData> cmykData(load_resource(r, test, "CMYK.jpg")); if (!mandrillData || !cmykData) { return; } SkDynamicMemoryWStream pdf; SkAutoTUnref<SkDocument> document(SkDocument::CreatePDF(&pdf)); SkCanvas* canvas = document->beginPage(642, 1028); canvas->clear(SK_ColorLTGRAY); SkBitmap bm1(bitmap_from_data(mandrillData)); canvas->drawBitmap(bm1, 65.0, 0.0, NULL); SkBitmap bm2(bitmap_from_data(cmykData)); canvas->drawBitmap(bm2, 0.0, 512.0, NULL); canvas->flush(); document->endPage(); document->close(); SkAutoTUnref<SkData> pdfData(pdf.copyToData()); SkASSERT(pdfData); pdf.reset(); // Test disabled, waiting on resolution to http://skbug.com/3180 // REPORTER_ASSERT(r, is_subset_of(mandrillData, pdfData)); // This JPEG uses a nonstandard colorspace - it can not be // embedded into the PDF directly. REPORTER_ASSERT(r, !is_subset_of(cmykData, pdfData)); // The following is for debugging purposes only. const char* outputPath = getenv("SKIA_TESTS_PDF_JPEG_EMBED_OUTPUT_PATH"); if (outputPath) { SkFILEWStream output(outputPath); if (output.isValid()) { output.write(pdfData->data(), pdfData->size()); } } }
static void TestPDFStream(skiatest::Reporter* reporter) { char streamBytes[] = "Test\nFoo\tBar"; SkAutoTDelete<SkMemoryStream> streamData(new SkMemoryStream( streamBytes, strlen(streamBytes), true)); SkAutoTUnref<SkPDFStream> stream(new SkPDFStream(streamData.get())); ASSERT_EMIT_EQ(reporter, *stream, "<</Length 12>> stream\nTest\nFoo\tBar\nendstream"); stream->insertInt("Attribute", 42); ASSERT_EMIT_EQ(reporter, *stream, "<</Length 12\n/Attribute 42>> stream\n" "Test\nFoo\tBar\nendstream"); { char streamBytes2[] = "This is a longer string, so that compression " "can do something with it. With shorter strings, " "the short circuit logic cuts in and we end up " "with an uncompressed string."; SkAutoDataUnref streamData2(SkData::NewWithCopy(streamBytes2, strlen(streamBytes2))); SkAutoTUnref<SkPDFStream> stream(new SkPDFStream(streamData2.get())); SkDynamicMemoryWStream compressedByteStream; SkDeflateWStream deflateWStream(&compressedByteStream); deflateWStream.write(streamBytes2, strlen(streamBytes2)); deflateWStream.finalize(); SkDynamicMemoryWStream expected; expected.writeText("<</Filter /FlateDecode\n/Length 116>> stream\n"); compressedByteStream.writeToStream(&expected); compressedByteStream.reset(); expected.writeText("\nendstream"); SkAutoDataUnref expectedResultData2(expected.copyToData()); SkString result = emit_to_string(*stream); ASSERT_EQL(reporter, result, (const char*)expectedResultData2->data(), expectedResultData2->size()); } }
static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj, const char* expectedData, size_t expectedSize, bool indirect, bool compression) { SkPDFDocument::Flags docFlags = (SkPDFDocument::Flags) 0; if (!compression) { docFlags = SkTBitOr(docFlags, SkPDFDocument::kFavorSpeedOverSize_Flags); } SkPDFCatalog catalog(docFlags); size_t directSize = obj->getOutputSize(&catalog, false); REPORTER_ASSERT(reporter, directSize == expectedSize); SkDynamicMemoryWStream buffer; obj->emit(&buffer, &catalog, false); REPORTER_ASSERT(reporter, directSize == buffer.getOffset()); REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedData, directSize)); if (indirect) { // Indirect output. static char header[] = "1 0 obj\n"; static size_t headerLen = strlen(header); static char footer[] = "\nendobj\n"; static size_t footerLen = strlen(footer); catalog.addObject(obj, false); size_t indirectSize = obj->getOutputSize(&catalog, true); REPORTER_ASSERT(reporter, indirectSize == directSize + headerLen + footerLen); buffer.reset(); obj->emit(&buffer, &catalog, true); REPORTER_ASSERT(reporter, indirectSize == buffer.getOffset()); REPORTER_ASSERT(reporter, stream_equals(buffer, 0, header, headerLen)); REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen, expectedData, directSize)); REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen + directSize, footer, footerLen)); } }
// static void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle, SkWStream* content) { // Filling a path with no area results in a drawing in PDF renderers but // Chrome expects to be able to draw some such entities with no visible // result, so we detect those cases and discard the drawing for them. // Specifically: moveTo(X), lineTo(Y) and moveTo(X), lineTo(X), lineTo(Y). enum SkipFillState { kEmpty_SkipFillState = 0, kSingleLine_SkipFillState = 1, kNonSingleLine_SkipFillState = 2, }; SkipFillState fillState = kEmpty_SkipFillState; if (paintStyle != SkPaint::kFill_Style) { fillState = kNonSingleLine_SkipFillState; } SkPoint lastMovePt = SkPoint::Make(0,0); SkDynamicMemoryWStream currentSegment; SkPoint args[4]; SkPath::Iter iter(path, false); for (SkPath::Verb verb = iter.next(args); verb != SkPath::kDone_Verb; verb = iter.next(args)) { // args gets all the points, even the implicit first point. switch (verb) { case SkPath::kMove_Verb: MoveTo(args[0].fX, args[0].fY, ¤tSegment); lastMovePt = args[0]; fillState = kEmpty_SkipFillState; break; case SkPath::kLine_Verb: AppendLine(args[1].fX, args[1].fY, ¤tSegment); if (fillState == kEmpty_SkipFillState) { if (args[0] != lastMovePt) { fillState = kSingleLine_SkipFillState; } } else if (fillState == kSingleLine_SkipFillState) { fillState = kNonSingleLine_SkipFillState; } break; case SkPath::kQuad_Verb: { SkPoint cubic[4]; SkConvertQuadToCubic(args, cubic); AppendCubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY, ¤tSegment); fillState = kNonSingleLine_SkipFillState; break; } case SkPath::kCubic_Verb: AppendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY, args[3].fX, args[3].fY, ¤tSegment); fillState = kNonSingleLine_SkipFillState; break; case SkPath::kClose_Verb: if (fillState != kSingleLine_SkipFillState) { ClosePath(¤tSegment); SkData* data = currentSegment.copyToData(); content->write(data->data(), data->size()); data->unref(); } currentSegment.reset(); break; default: SkASSERT(false); break; } } if (currentSegment.bytesWritten() > 0) { SkData* data = currentSegment.copyToData(); content->write(data->data(), data->size()); data->unref(); } }