Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Functions
JpegGainmapTest.cpp File Reference
#include "include/codec/SkAndroidCodec.h"
#include "include/codec/SkCodec.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkImage.h"
#include "include/core/SkShader.h"
#include "include/core/SkSize.h"
#include "include/core/SkStream.h"
#include "include/core/SkTypes.h"
#include "include/encode/SkJpegEncoder.h"
#include "include/private/SkGainmapInfo.h"
#include "include/private/SkGainmapShader.h"
#include "include/private/SkJpegGainmapEncoder.h"
#include "src/codec/SkJpegCodec.h"
#include "src/codec/SkJpegConstants.h"
#include "src/codec/SkJpegMultiPicture.h"
#include "src/codec/SkJpegSegmentScan.h"
#include "src/codec/SkJpegSourceMgr.h"
#include "tests/Test.h"
#include "tools/Resources.h"
#include <cstdint>
#include <cstring>
#include <memory>
#include <utility>
#include <vector>

Go to the source code of this file.

Functions

 DEF_TEST (Codec_jpegSegmentScan, r)
 
static bool find_mp_params_segment (SkStream *stream, std::unique_ptr< SkJpegMultiPictureParameters > *outMpParams, SkJpegSegment *outMpParamsSegment)
 
 DEF_TEST (Codec_multiPictureParams, r)
 
 DEF_TEST (Codec_jpegMultiPicture, r)
 
template<typename Reporter >
void decode_all (Reporter &r, std::unique_ptr< SkStream > stream, SkBitmap &baseBitmap, SkBitmap &gainmapBitmap, SkGainmapInfo &gainmapInfo)
 
static bool approx_eq (float x, float y, float epsilon)
 
 DEF_TEST (AndroidCodec_jpegGainmapDecode, r)
 
 DEF_TEST (AndroidCodec_jpegNoGainmap, r)
 
static bool approx_eq_rgb (const SkColor4f &x, const SkColor4f &y, float epsilon)
 
 DEF_TEST (AndroidCodec_gainmapInfoEncode, r)
 
static SkBitmap render_gainmap (const SkImageInfo &renderInfo, float renderHdrRatio, const SkBitmap &baseBitmap, const SkBitmap &gainmapBitmap, const SkGainmapInfo &gainmapInfo, int x, int y)
 
static SkColor4f render_gainmap_pixel (float renderHdrRatio, const SkBitmap &baseBitmap, const SkBitmap &gainmapBitmap, const SkGainmapInfo &gainmapInfo, int x, int y)
 
 DEF_TEST (AndroidCodec_jpegGainmapTranscode, r)
 

Function Documentation

◆ approx_eq()

static bool approx_eq ( float  x,
float  y,
float  epsilon 
)
static

Definition at line 461 of file JpegGainmapTest.cpp.

461{ return std::abs(x - y) < epsilon; }
double y
double x

◆ approx_eq_rgb()

static bool approx_eq_rgb ( const SkColor4f x,
const SkColor4f y,
float  epsilon 
)
static

Definition at line 574 of file JpegGainmapTest.cpp.

574 {
575 return approx_eq(x.fR, y.fR, epsilon) && approx_eq(x.fG, y.fG, epsilon) &&
576 approx_eq(x.fB, y.fB, epsilon);
577}
static bool approx_eq(float x, float y, float epsilon)

◆ decode_all()

template<typename Reporter >
void decode_all ( Reporter &  r,
std::unique_ptr< SkStream stream,
SkBitmap baseBitmap,
SkBitmap gainmapBitmap,
SkGainmapInfo gainmapInfo 
)

Definition at line 426 of file JpegGainmapTest.cpp.

430 {
431 // Decode the base bitmap.
433 std::unique_ptr<SkCodec> baseCodec = SkJpegCodec::MakeFromStream(std::move(stream), &result);
434 REPORTER_ASSERT(r, baseCodec);
435 baseBitmap.allocPixels(baseCodec->getInfo());
437 SkCodec::kSuccess == baseCodec->getPixels(baseBitmap.info(),
438 baseBitmap.getPixels(),
439 baseBitmap.rowBytes()));
440 std::unique_ptr<SkAndroidCodec> androidCodec =
441 SkAndroidCodec::MakeFromCodec(std::move(baseCodec));
442 REPORTER_ASSERT(r, androidCodec);
443
444 // Extract the gainmap info and stream.
445 std::unique_ptr<SkStream> gainmapStream;
446 REPORTER_ASSERT(r, androidCodec->getAndroidGainmap(&gainmapInfo, &gainmapStream));
447 REPORTER_ASSERT(r, gainmapStream);
448
449 // Decode the gainmap bitmap.
450 std::unique_ptr<SkCodec> gainmapCodec = SkCodec::MakeFromStream(std::move(gainmapStream));
451 REPORTER_ASSERT(r, gainmapCodec);
452 SkBitmap bm;
453 bm.allocPixels(gainmapCodec->getInfo());
454 gainmapBitmap.allocPixels(gainmapCodec->getInfo());
456 SkCodec::kSuccess == gainmapCodec->getPixels(gainmapBitmap.info(),
457 gainmapBitmap.getPixels(),
458 gainmapBitmap.rowBytes()));
459}
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
static std::unique_ptr< SkAndroidCodec > MakeFromCodec(std::unique_ptr< SkCodec >)
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition SkBitmap.cpp:258
size_t rowBytes() const
Definition SkBitmap.h:238
void * getPixels() const
Definition SkBitmap.h:283
const SkImageInfo & info() const
Definition SkBitmap.h:139
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, SkSpan< const SkCodecs::Decoder > decoders, Result *=nullptr, SkPngChunkReader *=nullptr, SelectionPolicy selectionPolicy=SelectionPolicy::kPreferStillImage)
Definition SkCodec.cpp:163
@ kSuccess
Definition SkCodec.h:80
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, Result *)
GAsyncResult * result

◆ DEF_TEST() [1/7]

DEF_TEST ( AndroidCodec_gainmapInfoEncode  ,
 
)

Definition at line 579 of file JpegGainmapTest.cpp.

579 {
580 SkDynamicMemoryWStream encodeStream;
581 SkGainmapInfo gainmapInfo;
582
583 SkBitmap baseBitmap;
584 baseBitmap.allocPixels(SkImageInfo::MakeN32Premul(8, 8));
585
586 SkBitmap gainmapBitmap;
587 gainmapBitmap.allocPixels(SkImageInfo::MakeN32Premul(8, 8));
588
589 gainmapInfo.fGainmapRatioMin.fR = 1.f;
590 gainmapInfo.fGainmapRatioMin.fG = 2.f;
591 gainmapInfo.fGainmapRatioMin.fB = 4.f;
592 gainmapInfo.fGainmapRatioMax.fR = 8.f;
593 gainmapInfo.fGainmapRatioMax.fG = 16.f;
594 gainmapInfo.fGainmapRatioMax.fB = 32.f;
595 gainmapInfo.fGainmapGamma.fR = 64.f;
596 gainmapInfo.fGainmapGamma.fG = 128.f;
597 gainmapInfo.fGainmapGamma.fB = 256.f;
598 gainmapInfo.fEpsilonSdr.fR = 1 / 10.f;
599 gainmapInfo.fEpsilonSdr.fG = 1 / 11.f;
600 gainmapInfo.fEpsilonSdr.fB = 1 / 12.f;
601 gainmapInfo.fEpsilonHdr.fR = 1 / 13.f;
602 gainmapInfo.fEpsilonHdr.fG = 1 / 14.f;
603 gainmapInfo.fEpsilonHdr.fB = 1 / 15.f;
604 gainmapInfo.fDisplayRatioSdr = 4.f;
605 gainmapInfo.fDisplayRatioHdr = 32.f;
606
607 for (int i = 0; i < 2; ++i) {
608 // In the second iteration, change some of the lists to scalars.
609 if (i == 1) {
610 gainmapInfo.fGainmapRatioMax.fR = 32.f;
611 gainmapInfo.fGainmapRatioMax.fG = 32.f;
612 gainmapInfo.fGainmapRatioMax.fB = 32.f;
613 gainmapInfo.fEpsilonSdr.fR = 1 / 10.f;
614 gainmapInfo.fEpsilonSdr.fG = 1 / 10.f;
615 gainmapInfo.fEpsilonSdr.fB = 1 / 10.f;
616 }
617
618 // Encode |gainmapInfo|.
619 bool encodeResult = SkJpegGainmapEncoder::EncodeHDRGM(&encodeStream,
620 baseBitmap.pixmap(),
622 gainmapBitmap.pixmap(),
624 gainmapInfo);
625 REPORTER_ASSERT(r, encodeResult);
626
627 // Decode into |decodedGainmapInfo|.
628 SkGainmapInfo decodedGainmapInfo;
629 auto decodeStream = std::make_unique<SkMemoryStream>(encodeStream.detachAsData());
630 decode_all(r, std::move(decodeStream), baseBitmap, gainmapBitmap, decodedGainmapInfo);
631
632 // Verify they are |gainmapInfo| matches |decodedGainmapInfo|.
633 REPORTER_ASSERT(r, gainmapInfo == decodedGainmapInfo);
634 }
635}
void decode_all(Reporter &r, std::unique_ptr< SkStream > stream, SkBitmap &baseBitmap, SkBitmap &gainmapBitmap, SkGainmapInfo &gainmapInfo)
const SkPixmap & pixmap() const
Definition SkBitmap.h:133
sk_sp< SkData > detachAsData()
Definition SkStream.cpp:707
static bool EncodeHDRGM(SkWStream *dst, const SkPixmap &base, const SkJpegEncoder::Options &baseOptions, const SkPixmap &gainmap, const SkJpegEncoder::Options &gainmapOptions, const SkGainmapInfo &gainmapInfo)
SkColor4f fGainmapRatioMax
SkColor4f fEpsilonSdr
SkColor4f fGainmapGamma
SkColor4f fGainmapRatioMin
float fDisplayRatioSdr
SkColor4f fEpsilonHdr
float fDisplayRatioHdr
static SkImageInfo MakeN32Premul(int width, int height)

◆ DEF_TEST() [2/7]

DEF_TEST ( AndroidCodec_jpegGainmapDecode  ,
 
)

Definition at line 463 of file JpegGainmapTest.cpp.

463 {
464 const struct Rec {
465 const char* path;
466 SkISize dimensions;
467 SkColor originColor;
468 SkColor farCornerColor;
469 float ratioMin;
470 float ratioMax;
471 float hdrRatioMin;
472 float hdrRatioMax;
473 } recs[] = {
474 {"images/iphone_13_pro.jpeg",
475 SkISize::Make(1512, 2016),
476 0xFF3B3B3B,
477 0xFF101010,
478 std::exp(0.f),
479 std::exp(1.f),
480 1.f,
481 2.71828f},
482 {"images/hdrgm.jpg",
483 SkISize::Make(188, 250),
484 0xFFE9E9E9,
485 0xFFAAAAAA,
486 std::exp(-2.209409f),
487 std::exp(2.209409f),
488 1.f,
489 9.110335f},
490 };
491
492 TestStream::Type kStreamTypes[] = {
493 TestStream::Type::kUnseekable,
494 TestStream::Type::kSeekable,
495 TestStream::Type::kMemoryMapped,
496 };
497 for (const auto& streamType : kStreamTypes) {
498 bool useFileStream = streamType != TestStream::Type::kMemoryMapped;
499 for (const auto& rec : recs) {
500 auto stream = GetResourceAsStream(rec.path, useFileStream);
501 REPORTER_ASSERT(r, stream);
502 auto testStream = std::make_unique<TestStream>(streamType, stream.get());
503
504 SkBitmap baseBitmap;
505 SkBitmap gainmapBitmap;
506 SkGainmapInfo gainmapInfo;
507 decode_all(r, std::move(testStream), baseBitmap, gainmapBitmap, gainmapInfo);
508
509 // Spot-check the image size and pixels.
510 REPORTER_ASSERT(r, gainmapBitmap.dimensions() == rec.dimensions);
511 REPORTER_ASSERT(r, gainmapBitmap.getColor(0, 0) == rec.originColor);
513 r,
514 gainmapBitmap.getColor(rec.dimensions.fWidth - 1, rec.dimensions.fHeight - 1) ==
515 rec.farCornerColor);
516
517 // Verify the gainmap rendering parameters.
518 constexpr float kEpsilon = 1e-3f;
519 REPORTER_ASSERT(r, approx_eq(gainmapInfo.fGainmapRatioMin.fR, rec.ratioMin, kEpsilon));
520 REPORTER_ASSERT(r, approx_eq(gainmapInfo.fGainmapRatioMin.fG, rec.ratioMin, kEpsilon));
521 REPORTER_ASSERT(r, approx_eq(gainmapInfo.fGainmapRatioMin.fB, rec.ratioMin, kEpsilon));
522
523 REPORTER_ASSERT(r, approx_eq(gainmapInfo.fGainmapRatioMax.fR, rec.ratioMax, kEpsilon));
524 REPORTER_ASSERT(r, approx_eq(gainmapInfo.fGainmapRatioMax.fG, rec.ratioMax, kEpsilon));
525 REPORTER_ASSERT(r, approx_eq(gainmapInfo.fGainmapRatioMax.fB, rec.ratioMax, kEpsilon));
526
527 REPORTER_ASSERT(r, approx_eq(gainmapInfo.fDisplayRatioSdr, rec.hdrRatioMin, kEpsilon));
528 REPORTER_ASSERT(r, approx_eq(gainmapInfo.fDisplayRatioHdr, rec.hdrRatioMax, kEpsilon));
529 }
530 }
531}
std::unique_ptr< SkStreamAsset > GetResourceAsStream(const char *resource, bool useFileStream)
Definition Resources.cpp:31
uint32_t SkColor
Definition SkColor.h:37
static constexpr double kEpsilon
SkISize dimensions() const
Definition SkBitmap.h:388
SkColor getColor(int x, int y) const
Definition SkBitmap.h:874
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20

◆ DEF_TEST() [3/7]

DEF_TEST ( AndroidCodec_jpegGainmapTranscode  ,
 
)

Definition at line 699 of file JpegGainmapTest.cpp.

699 {
700 const char* path = "images/iphone_13_pro.jpeg";
701 SkBitmap baseBitmap[2];
702 SkBitmap gainmapBitmap[2];
703 SkGainmapInfo gainmapInfo[2];
704
705 // Decode an MPF-based gainmap image.
706 decode_all(r, GetResourceAsStream(path), baseBitmap[0], gainmapBitmap[0], gainmapInfo[0]);
707
708 constexpr float kEpsilon = 1e-2f;
709 {
710 SkDynamicMemoryWStream encodeStream;
711
712 // Transcode to UltraHDR.
713 bool encodeResult = SkJpegGainmapEncoder::EncodeHDRGM(&encodeStream,
714 baseBitmap[0].pixmap(),
716 gainmapBitmap[0].pixmap(),
718 gainmapInfo[0]);
719 REPORTER_ASSERT(r, encodeResult);
720 auto encodeData = encodeStream.detachAsData();
721
722 // Decode the just-encoded image.
723 auto decodeStream = std::make_unique<SkMemoryStream>(encodeData);
724 decode_all(r, std::move(decodeStream), baseBitmap[1], gainmapBitmap[1], gainmapInfo[1]);
725
726 // HDRGM will have the same rendering parameters.
728 r,
730 gainmapInfo[0].fGainmapRatioMin, gainmapInfo[1].fGainmapRatioMin,kEpsilon));
732 r,
734 gainmapInfo[0].fGainmapRatioMax, gainmapInfo[1].fGainmapRatioMax, kEpsilon));
736 r,
738 gainmapInfo[0].fGainmapGamma, gainmapInfo[1].fGainmapGamma, kEpsilon));
740 r,
741 approx_eq(gainmapInfo[0].fEpsilonSdr.fR, gainmapInfo[1].fEpsilonSdr.fR, kEpsilon));
743 r,
744 approx_eq(gainmapInfo[0].fEpsilonHdr.fR, gainmapInfo[1].fEpsilonHdr.fR, kEpsilon));
746 r,
747 approx_eq(
748 gainmapInfo[0].fDisplayRatioSdr,
749 gainmapInfo[1].fDisplayRatioSdr,
750 kEpsilon));
752 r,
753 approx_eq(
754 gainmapInfo[0].fDisplayRatioHdr,
755 gainmapInfo[1].fDisplayRatioHdr,
756 kEpsilon));
757
758 // Render a few pixels and verify that they come out the same. Rendering requires SkSL.
759 const struct Rec {
760 int x;
761 int y;
762 float hdrRatio;
763 SkColor4f expectedColor;
764 SkColorType forcedColorType;
765 } recs[] = {
766 {1446, 1603, 1.05f, {0.984375f, 1.004883f, 1.008789f, 1.f}, kUnknown_SkColorType},
767 {1446, 1603, 100.f, {1.147461f, 1.170898f, 1.174805f, 1.f}, kUnknown_SkColorType},
768 {1446, 1603, 100.f, {1.147461f, 1.170898f, 1.174805f, 1.f}, kGray_8_SkColorType},
769 {1446, 1603, 100.f, {1.147461f, 1.170898f, 1.174805f, 1.f}, kAlpha_8_SkColorType},
770 {1446, 1603, 100.f, {1.147461f, 1.170898f, 1.174805f, 1.f}, kR8_unorm_SkColorType},
771 };
772
773 for (const auto& rec : recs) {
774 SkBitmap gainmapBitmap0;
775 SkASSERT(gainmapBitmap[0].colorType() == kGray_8_SkColorType);
776
777 // Force various different single-channel formats, to ensure that they all work. Note
778 // that when the color type is forced to kAlpha_8_SkColorType, the shader will always
779 // read (0,0,0,1) if the alpha type is kOpaque_SkAlphaType.
780 if (rec.forcedColorType == kUnknown_SkColorType) {
781 gainmapBitmap0 = gainmapBitmap[0];
782 } else {
783 gainmapBitmap0.installPixels(gainmapBitmap[0]
784 .info()
785 .makeColorType(rec.forcedColorType)
786 .makeAlphaType(kPremul_SkAlphaType),
787 gainmapBitmap[0].getPixels(),
788 gainmapBitmap[0].rowBytes());
789 }
791 rec.hdrRatio, baseBitmap[0], gainmapBitmap0, gainmapInfo[0], rec.x, rec.y);
793 rec.hdrRatio, baseBitmap[1], gainmapBitmap[1], gainmapInfo[1], rec.x, rec.y);
794
796 }
797 }
798}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
static bool approx_eq_rgb(const SkColor4f &x, const SkColor4f &y, float epsilon)
static SkColor4f render_gainmap_pixel(float renderHdrRatio, const SkBitmap &baseBitmap, const SkBitmap &gainmapBitmap, const SkGainmapInfo &gainmapInfo, int x, int y)
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkASSERT(cond)
Definition SkAssert.h:116
SkColorType
Definition SkColorType.h:19
@ kR8_unorm_SkColorType
Definition SkColorType.h:54
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition SkColorType.h:21
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
Definition SkColorType.h:35
@ kUnknown_SkColorType
uninitialized
Definition SkColorType.h:20
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
bool installPixels(const SkImageInfo &info, void *pixels, size_t rowBytes, void(*releaseProc)(void *addr, void *context), void *context)
Definition SkBitmap.cpp:323

◆ DEF_TEST() [4/7]

DEF_TEST ( AndroidCodec_jpegNoGainmap  ,
 
)

Definition at line 533 of file JpegGainmapTest.cpp.

533 {
534 // This test image has a large APP16 segment that will stress the various SkJpegSourceMgrs'
535 // data skipping paths.
536 const char* path = "images/icc-v2-gbr.jpg";
537
538 TestStream::Type kStreamTypes[] = {
539 TestStream::Type::kUnseekable,
540 TestStream::Type::kSeekable,
541 TestStream::Type::kMemoryMapped,
542 };
543 for (const auto& streamType : kStreamTypes) {
544 bool useFileStream = streamType != TestStream::Type::kMemoryMapped;
545 auto stream = GetResourceAsStream(path, useFileStream);
546 REPORTER_ASSERT(r, stream);
547 auto testStream = std::make_unique<TestStream>(streamType, stream.get());
548
549 // Decode the base bitmap.
551 std::unique_ptr<SkCodec> baseCodec =
552 SkJpegCodec::MakeFromStream(std::move(testStream), &result);
553 REPORTER_ASSERT(r, baseCodec);
554 SkBitmap baseBitmap;
555 baseBitmap.allocPixels(baseCodec->getInfo());
557 SkCodec::kSuccess == baseCodec->getPixels(baseBitmap.info(),
558 baseBitmap.getPixels(),
559 baseBitmap.rowBytes()));
560
561 std::unique_ptr<SkAndroidCodec> androidCodec =
562 SkAndroidCodec::MakeFromCodec(std::move(baseCodec));
563 REPORTER_ASSERT(r, androidCodec);
564
565 // Try to extract the gainmap info and stream. It should fail.
566 SkGainmapInfo gainmapInfo;
567 std::unique_ptr<SkStream> gainmapStream;
568 REPORTER_ASSERT(r, !androidCodec->getAndroidGainmap(&gainmapInfo, &gainmapStream));
569 }
570}

◆ DEF_TEST() [5/7]

DEF_TEST ( Codec_jpegMultiPicture  ,
 
)

Definition at line 332 of file JpegGainmapTest.cpp.

332 {
333 const char* path = "images/iphone_13_pro.jpeg";
334 auto stream = GetResourceAsStream(path);
335 REPORTER_ASSERT(r, stream);
336
337 // Search and parse the MPF header.
338 std::unique_ptr<SkJpegMultiPictureParameters> mpParams;
339 SkJpegSegment mpParamsSegment;
340 REPORTER_ASSERT(r, find_mp_params_segment(stream.get(), &mpParams, &mpParamsSegment));
341
342 // Verify that we get the same parameters when we re-serialize and de-serialize them
343 {
344 auto mpParamsSerialized = mpParams->serialize();
345 REPORTER_ASSERT(r, mpParamsSerialized);
346 auto mpParamsRoundTripped = SkJpegMultiPictureParameters::Make(mpParamsSerialized);
347 REPORTER_ASSERT(r, mpParamsRoundTripped);
348 REPORTER_ASSERT(r, mpParamsRoundTripped->images.size() == mpParams->images.size());
349 for (size_t i = 0; i < mpParamsRoundTripped->images.size(); ++i) {
350 REPORTER_ASSERT(r, mpParamsRoundTripped->images[i].size == mpParams->images[i].size);
352 r,
353 mpParamsRoundTripped->images[i].dataOffset == mpParams->images[i].dataOffset);
354 }
355 }
356
357 const struct Rec {
358 const TestStream::Type streamType;
359 const bool skipFirstImage;
360 const size_t bufferSize;
361 } recs[] = {
362 {TestStream::Type::kMemoryMapped, false, 1024},
363 {TestStream::Type::kMemoryMapped, true, 1024},
364 {TestStream::Type::kSeekable, false, 1024},
365 {TestStream::Type::kSeekable, true, 1024},
366 {TestStream::Type::kSeekable, false, 7},
367 {TestStream::Type::kSeekable, true, 13},
368 {TestStream::Type::kSeekable, true, 1024 * 1024 * 16},
369 {TestStream::Type::kUnseekable, false, 1024},
370 {TestStream::Type::kUnseekable, true, 1024},
371 {TestStream::Type::kUnseekable, false, 1},
372 {TestStream::Type::kUnseekable, true, 1},
373 {TestStream::Type::kUnseekable, false, 7},
374 {TestStream::Type::kUnseekable, true, 13},
375 {TestStream::Type::kUnseekable, false, 1024 * 1024 * 16},
376 {TestStream::Type::kUnseekable, true, 1024 * 1024 * 16},
377 };
378 for (const auto& rec : recs) {
379 stream->rewind();
380 TestStream testStream(rec.streamType, stream.get());
381 auto sourceMgr = SkJpegSourceMgr::Make(&testStream, rec.bufferSize);
382
383 // Decode the images into bitmaps.
384 size_t numberOfImages = mpParams->images.size();
385 std::vector<SkBitmap> bitmaps(numberOfImages);
386 for (size_t i = 0; i < numberOfImages; ++i) {
387 if (i == 0) {
388 REPORTER_ASSERT(r, mpParams->images[i].dataOffset == 0);
389 continue;
390 }
391 if (i == 1 && rec.skipFirstImage) {
392 continue;
393 }
394 auto imageData = sourceMgr->getSubsetData(
395 SkJpegMultiPictureParameters::GetAbsoluteOffset(mpParams->images[i].dataOffset,
396 mpParamsSegment.offset),
397 mpParams->images[i].size);
398 REPORTER_ASSERT(r, imageData);
399
400 std::unique_ptr<SkCodec> codec =
402 REPORTER_ASSERT(r, codec);
403
404 SkBitmap bm;
405 bm.allocPixels(codec->getInfo());
408 codec->getPixels(bm.info(), bm.getPixels(), bm.rowBytes()));
409 bitmaps[i] = bm;
410 }
411
412 // Spot-check the image size and pixels.
413 if (!rec.skipFirstImage) {
414 REPORTER_ASSERT(r, bitmaps[1].dimensions() == SkISize::Make(1512, 2016));
415 REPORTER_ASSERT(r, bitmaps[1].getColor(0, 0) == 0xFF3B3B3B);
416 REPORTER_ASSERT(r, bitmaps[1].getColor(1511, 2015) == 0xFF101010);
417 }
418 REPORTER_ASSERT(r, bitmaps[2].dimensions() == SkISize::Make(576, 768));
419 REPORTER_ASSERT(r, bitmaps[2].getColor(0, 0) == 0xFF010101);
420 REPORTER_ASSERT(r, bitmaps[2].getColor(575, 767) == 0xFFB5B5B5);
421 }
422}
static bool find_mp_params_segment(SkStream *stream, std::unique_ptr< SkJpegMultiPictureParameters > *outMpParams, SkJpegSegment *outMpParamsSegment)
static std::unique_ptr< SkJpegSourceMgr > Make(SkStream *stream, size_t bufferSize=1024)
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
Definition SkStream.cpp:314
static size_t GetAbsoluteOffset(uint32_t dataOffset, size_t mpSegmentOffset)
static std::unique_ptr< SkJpegMultiPictureParameters > Make(const sk_sp< const SkData > &segmentParameters)

◆ DEF_TEST() [6/7]

DEF_TEST ( Codec_jpegSegmentScan  ,
 
)

Definition at line 112 of file JpegGainmapTest.cpp.

112 {
113 const struct Rec {
114 const char* path;
115 size_t sosSegmentCount;
116 size_t eoiSegmentCount;
117 size_t testSegmentIndex;
118 uint8_t testSegmentMarker;
119 size_t testSegmentOffset;
120 uint16_t testSegmentParameterLength;
121 } recs[] = {
122 {"images/wide_gamut_yellow_224_224_64.jpeg", 11, 15, 10, 0xda, 9768, 12},
123 {"images/CMYK.jpg", 7, 8, 1, 0xee, 2, 14},
124 {"images/b78329453.jpeg", 10, 23, 3, 0xe2, 154, 540},
125 {"images/brickwork-texture.jpg", 8, 28, 12, 0xc4, 34183, 42},
126 {"images/brickwork_normal-map.jpg", 8, 28, 27, 0xd9, 180612, 0},
127 {"images/cmyk_yellow_224_224_32.jpg", 19, 23, 2, 0xed, 854, 2828},
128 {"images/color_wheel.jpg", 10, 11, 2, 0xdb, 20, 67},
129 {"images/cropped_mandrill.jpg", 10, 11, 4, 0xc0, 158, 17},
130 {"images/dog.jpg", 10, 11, 5, 0xc4, 177, 28},
131 {"images/ducky.jpg", 12, 13, 10, 0xc4, 3718, 181},
132 {"images/exif-orientation-2-ur.jpg", 11, 12, 2, 0xe1, 20, 130},
133 {"images/flutter_logo.jpg", 9, 27, 21, 0xda, 5731, 8},
134 {"images/grayscale.jpg", 6, 16, 9, 0xda, 327, 8},
135 {"images/icc-v2-gbr.jpg", 12, 25, 24, 0xd9, 43832, 0},
136 {"images/mandrill_512_q075.jpg", 10, 11, 7, 0xc4, 393, 31},
137 {"images/mandrill_cmyk.jpg", 19, 35, 16, 0xdd, 574336, 4},
138 {"images/mandrill_h1v1.jpg", 10, 11, 1, 0xe0, 2, 16},
139 {"images/mandrill_h2v1.jpg", 10, 11, 0, 0xd8, 0, 0},
140 {"images/randPixels.jpg", 10, 11, 6, 0xc4, 200, 30},
141 {"images/wide_gamut_yellow_224_224_64.jpeg", 11, 15, 10, 0xda, 9768, 12},
142 };
143
144 for (const auto& rec : recs) {
145 auto stream = GetResourceAsStream(rec.path);
146 if (!stream) {
147 continue;
148 }
149
150 // Scan all the way to EndOfImage.
151 auto sourceMgr = SkJpegSourceMgr::Make(stream.get());
152 const auto& segments = sourceMgr->getAllSegments();
153
154 // Verify we got the expected number of segments at EndOfImage
155 REPORTER_ASSERT(r, rec.eoiSegmentCount == segments.size());
156
157 // Verify we got the expected number of segments before StartOfScan
158 for (size_t i = 0; i < segments.size(); ++i) {
159 if (segments[i].marker == kJpegMarkerStartOfScan) {
160 REPORTER_ASSERT(r, rec.sosSegmentCount == i + 1);
161 break;
162 }
163 }
164
165 // Verify the values for a randomly pre-selected segment index.
166 const auto& segment = segments[rec.testSegmentIndex];
167 REPORTER_ASSERT(r, rec.testSegmentMarker == segment.marker);
168 REPORTER_ASSERT(r, rec.testSegmentOffset == segment.offset);
169 REPORTER_ASSERT(r, rec.testSegmentParameterLength == segment.parameterLength);
170 }
171}
static const char marker[]
static constexpr uint8_t kJpegMarkerStartOfScan

◆ DEF_TEST() [7/7]

DEF_TEST ( Codec_multiPictureParams  ,
 
)

Definition at line 194 of file JpegGainmapTest.cpp.

194 {
195 // Little-endian test.
196 {
197 const uint8_t bytes[] = {
198 0x4d, 0x50, 0x46, 0x00, 0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03,
199 0x00, 0x00, 0xb0, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, 0x31, 0x30, 0x30,
200 0x01, 0xb0, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
201 0xb0, 0x07, 0x00, 0x20, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
202 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x20, 0xcf, 0x49, 0x00, 0x00, 0x00, 0x00,
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x28, 0x01, 0x00,
204 0xf9, 0xb7, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
205 };
206 auto mpParams =
208 REPORTER_ASSERT(r, mpParams);
209 REPORTER_ASSERT(r, mpParams->images.size() == 2);
210 REPORTER_ASSERT(r, mpParams->images[0].dataOffset == 0);
211 REPORTER_ASSERT(r, mpParams->images[0].size == 4837152);
212 REPORTER_ASSERT(r, mpParams->images[1].dataOffset == 3979257);
213 REPORTER_ASSERT(r, mpParams->images[1].size == 76014);
214 }
215
216 // Big-endian test.
217 {
218 const uint8_t bytes[] = {
219 0x4d, 0x50, 0x46, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00,
220 0x03, 0xb0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x31, 0x30, 0x30,
221 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0xb0,
222 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00,
223 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x56, 0xda, 0x2f, 0x00, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xc6, 0x01,
225 0x00, 0x55, 0x7c, 0x1f, 0x00, 0x00, 0x00, 0x00,
226 };
227 auto mpParams =
229 REPORTER_ASSERT(r, mpParams);
230 REPORTER_ASSERT(r, mpParams->images.size() == 2);
231 REPORTER_ASSERT(r, mpParams->images[0].dataOffset == 0);
232 REPORTER_ASSERT(r, mpParams->images[0].size == 5691951);
233 REPORTER_ASSERT(r, mpParams->images[1].dataOffset == 5602335);
234 REPORTER_ASSERT(r, mpParams->images[1].size == 1361409);
235 }
236
237 // Three entry test.
238 {
239 const uint8_t bytes[] = {
240 0x4d, 0x50, 0x46, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00,
241 0x03, 0xb0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x31, 0x30, 0x30,
242 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0xb0,
243 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00,
244 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1f, 0x1c, 0xc2, 0x00, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0xb0,
246 0x00, 0x1f, 0x12, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 0x00, 0x96, 0x6b, 0x00, 0x22, 0x18, 0x9c, 0x00, 0x00, 0x00, 0x00,
248 };
249 auto mpParams =
251 REPORTER_ASSERT(r, mpParams);
252 REPORTER_ASSERT(r, mpParams->images.size() == 3);
253 REPORTER_ASSERT(r, mpParams->images[0].dataOffset == 0);
254 REPORTER_ASSERT(r, mpParams->images[0].size == 2038978);
255 REPORTER_ASSERT(r, mpParams->images[1].dataOffset == 2036460);
256 REPORTER_ASSERT(r, mpParams->images[1].size == 198064);
257 REPORTER_ASSERT(r, mpParams->images[2].dataOffset == 2234524);
258 REPORTER_ASSERT(r, mpParams->images[2].size == 38507);
259 }
260
261 // Inserting various corrupt values.
262 {
263 const uint8_t bytes[] = {
264 0x4d, 0x50, 0x46, 0x00, // 0: {'M', 'P', 'F', 0} signature
265 0x4d, 0x4d, 0x00, 0x2a, // 4: {'M', 'M', 0, '*'} big-endian
266 0x00, 0x00, 0x00, 0x08, // 8: Index IFD offset
267 0x00, 0x03, // 12: Number of tags
268 0xb0, 0x00, // 14: Version tag
269 0x00, 0x07, // 16: Undefined type
270 0x00, 0x00, 0x00, 0x04, // 18: Size
271 0x30, 0x31, 0x30, 0x30, // 22: Value
272 0xb0, 0x01, // 26: Number of images
273 0x00, 0x04, // 28: Unsigned long type
274 0x00, 0x00, 0x00, 0x01, // 30: Count
275 0x00, 0x00, 0x00, 0x02, // 34: Value
276 0xb0, 0x02, // 38: MP entry tag
277 0x00, 0x07, // 40: Undefined type
278 0x00, 0x00, 0x00, 0x20, // 42: Size
279 0x00, 0x00, 0x00, 0x32, // 46: Value (offset)
280 0x00, 0x00, 0x00, 0x00, // 50: Next IFD offset (null)
281 0x20, 0x03, 0x00, 0x00, // 54: MP Entry 0 attributes
282 0x00, 0x56, 0xda, 0x2f, // 58: MP Entry 0 size (5691951)
283 0x00, 0x00, 0x00, 0x00, // 62: MP Entry 0 offset (0)
284 0x00, 0x00, 0x00, 0x00, // 66: MP Entry 0 dependencies
285 0x00, 0x00, 0x00, 0x00, // 70: MP Entry 1 attributes.
286 0x00, 0x14, 0xc6, 0x01, // 74: MP Entry 1 size (1361409)
287 0x00, 0x55, 0x7c, 0x1f, // 78: MP Entry 1 offset (5602335)
288 0x00, 0x00, 0x00, 0x00, // 82: MP Entry 1 dependencies
289 };
290
291 // Verify the offsets labeled above.
292 REPORTER_ASSERT(r, bytes[22] == 0x30);
293 REPORTER_ASSERT(r, bytes[26] == 0xb0);
294 REPORTER_ASSERT(r, bytes[38] == 0xb0);
295 REPORTER_ASSERT(r, bytes[54] == 0x20);
296 REPORTER_ASSERT(r, bytes[81] == 0x1f);
297
298 {
299 // Change the version to {'0', '1', '0', '1'}.
300 auto bytesInvalid = SkData::MakeWithCopy(bytes, sizeof(bytes));
301 REPORTER_ASSERT(r, bytes[25] == '0');
302 reinterpret_cast<uint8_t*>(bytesInvalid->writable_data())[25] = '1';
303 REPORTER_ASSERT(r, SkJpegMultiPictureParameters::Make(bytesInvalid) == nullptr);
304 }
305
306 {
307 // Change the number of images to be undefined type instead of unsigned long type.
308 auto bytesInvalid = SkData::MakeWithCopy(bytes, sizeof(bytes));
309 REPORTER_ASSERT(r, bytes[29] == 0x04);
310 reinterpret_cast<uint8_t*>(bytesInvalid->writable_data())[29] = 0x07;
311 REPORTER_ASSERT(r, SkJpegMultiPictureParameters::Make(bytesInvalid) == nullptr);
312 }
313
314 {
315 // Make the MP entries point off of the end of the buffer.
316 auto bytesInvalid = SkData::MakeWithCopy(bytes, sizeof(bytes));
317 REPORTER_ASSERT(r, bytes[49] == 0x32);
318 reinterpret_cast<uint8_t*>(bytesInvalid->writable_data())[49] = 0xFE;
319 REPORTER_ASSERT(r, SkJpegMultiPictureParameters::Make(bytesInvalid) == nullptr);
320 }
321
322 {
323 // Make the MP entries too small.
324 auto bytesInvalid = SkData::MakeWithCopy(bytes, sizeof(bytes));
325 REPORTER_ASSERT(r, bytes[45] == 0x20);
326 reinterpret_cast<uint8_t*>(bytesInvalid->writable_data())[45] = 0x1F;
327 REPORTER_ASSERT(r, SkJpegMultiPictureParameters::Make(bytesInvalid) == nullptr);
328 }
329 }
330}
static sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
Definition SkData.h:116
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition SkData.cpp:111

◆ find_mp_params_segment()

static bool find_mp_params_segment ( SkStream stream,
std::unique_ptr< SkJpegMultiPictureParameters > *  outMpParams,
SkJpegSegment outMpParamsSegment 
)
static

Definition at line 173 of file JpegGainmapTest.cpp.

175 {
176 auto sourceMgr = SkJpegSourceMgr::Make(stream);
177 for (const auto& segment : sourceMgr->getAllSegments()) {
178 if (segment.marker != kMpfMarker) {
179 continue;
180 }
181 auto parameterData = sourceMgr->getSegmentParameters(segment);
182 if (!parameterData) {
183 continue;
184 }
185 *outMpParams = SkJpegMultiPictureParameters::Make(parameterData);
186 if (*outMpParams) {
187 *outMpParamsSegment = segment;
188 return true;
189 }
190 }
191 return false;
192}
static constexpr uint32_t kMpfMarker

◆ render_gainmap()

static SkBitmap render_gainmap ( const SkImageInfo renderInfo,
float  renderHdrRatio,
const SkBitmap baseBitmap,
const SkBitmap gainmapBitmap,
const SkGainmapInfo gainmapInfo,
int  x,
int  y 
)
static

Definition at line 638 of file JpegGainmapTest.cpp.

644 {
645 SkRect baseRect = SkRect::MakeXYWH(x, y, renderInfo.width(), renderInfo.height());
646
647 float scaleX = gainmapBitmap.width() / static_cast<float>(baseBitmap.width());
648 float scaleY = gainmapBitmap.height() / static_cast<float>(baseBitmap.height());
649 SkRect gainmapRect = SkRect::MakeXYWH(baseRect.x() * scaleX,
650 baseRect.y() * scaleY,
651 baseRect.width() * scaleX,
652 baseRect.height() * scaleY);
653
654 SkRect dstRect = SkRect::Make(renderInfo.dimensions());
655
656 sk_sp<SkImage> baseImage = SkImages::RasterFromBitmap(baseBitmap);
657 sk_sp<SkImage> gainmapImage = SkImages::RasterFromBitmap(gainmapBitmap);
658 sk_sp<SkShader> shader = SkGainmapShader::Make(baseImage,
659 baseRect,
661 gainmapImage,
662 gainmapRect,
664 gainmapInfo,
665 dstRect,
666 renderHdrRatio,
667 renderInfo.refColorSpace());
668
670 result.allocPixels(renderInfo);
671 result.eraseColor(SK_ColorTRANSPARENT);
672 SkCanvas canvas(result);
673
675 paint.setShader(shader);
676 canvas.drawRect(dstRect, paint);
677
678 return result;
679}
constexpr SkColor SK_ColorTRANSPARENT
Definition SkColor.h:99
int width() const
Definition SkBitmap.h:149
int height() const
Definition SkBitmap.h:158
static sk_sp< SkShader > Make(const sk_sp< const SkImage > &baseImage, const SkRect &baseRect, const SkSamplingOptions &baseSamplingOptions, const sk_sp< const SkImage > &gainmapImage, const SkRect &gainmapRect, const SkSamplingOptions &gainmapSamplingOptions, const SkGainmapInfo &gainmapInfo, const SkRect &dstRect, float dstHdrRatio, sk_sp< SkColorSpace > dstColorSpace)
const Paint & paint
SK_API sk_sp< SkImage > RasterFromBitmap(const SkBitmap &bitmap)
sk_sp< SkColorSpace > refColorSpace() const
SkISize dimensions() const
int width() const
int height() const
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
constexpr float x() const
Definition SkRect.h:720
constexpr float y() const
Definition SkRect.h:727
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659
constexpr float height() const
Definition SkRect.h:769
constexpr float width() const
Definition SkRect.h:762

◆ render_gainmap_pixel()

static SkColor4f render_gainmap_pixel ( float  renderHdrRatio,
const SkBitmap baseBitmap,
const SkBitmap gainmapBitmap,
const SkGainmapInfo gainmapInfo,
int  x,
int  y 
)
static

Definition at line 682 of file JpegGainmapTest.cpp.

687 {
688 SkImageInfo testPixelInfo = SkImageInfo::Make(
689 /*width=*/1,
690 /*height=*/1,
694 SkBitmap testPixelBitmap = render_gainmap(
695 testPixelInfo, renderHdrRatio, baseBitmap, gainmapBitmap, gainmapInfo, x, y);
696 return testPixelBitmap.getColor4f(0, 0);
697}
static SkBitmap render_gainmap(const SkImageInfo &renderInfo, float renderHdrRatio, const SkBitmap &baseBitmap, const SkBitmap &gainmapBitmap, const SkGainmapInfo &gainmapInfo, int x, int y)
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition SkColorType.h:38
SkColor4f getColor4f(int x, int y) const
Definition SkBitmap.h:893
static sk_sp< SkColorSpace > MakeSRGB()
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)