| /* |
| * Copyright 2018 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "gm/gm.h" |
| #include "include/codec/SkEncodedOrigin.h" |
| #include "include/core/SkBlurTypes.h" |
| #include "include/core/SkCanvas.h" |
| #include "include/core/SkFont.h" |
| #include "include/core/SkImage.h" |
| #include "include/core/SkMaskFilter.h" |
| #include "include/core/SkRefCnt.h" |
| #include "include/core/SkSize.h" |
| #include "include/core/SkString.h" |
| #include "include/core/SkSurface.h" |
| #include "tools/DecodeUtils.h" |
| #include "tools/EncodeUtils.h" |
| #include "tools/Resources.h" |
| #include "tools/ToolUtils.h" |
| #include "tools/fonts/FontToolUtils.h" |
| |
| static constexpr int kImgW = 100; |
| static constexpr int kImgH = 80; |
| |
| /** |
| This function was used to create the images used by these test. It saves them as PNGs (so they |
| are lossless). Then the following bash script was used to create the oriented JPGs with |
| imagemagick and exiftool: |
| #!/bin/bash |
| |
| for s in 444 422 420 440 411 410; do |
| for i in {1..8}; do |
| magick convert $i.png -sampling-factor ${s:0:1}:${s:1:1}:${s:2:1} $i\_$s.jpg; |
| exiftool -orientation=$i -n -m -overwrite_original $i\_$s.jpg; |
| done |
| done |
| |
| */ |
| static void make_images() { |
| for (int i = 1; i <= 8; ++i) { |
| SkISize size{kImgW, kImgH}; |
| SkEncodedOrigin origin = static_cast<SkEncodedOrigin>(i); |
| // We apply the inverse transformation to the PNG we generate, convert the PNG to a |
| // a JPEG using magick, then modify the JPEG's tag using exiftool (without modifying the |
| // stored JPEG data). |
| if (origin >= kLeftTop_SkEncodedOrigin) { |
| // The last four SkEncodedOrigin values involve 90 degree rotations |
| using std::swap; |
| swap(size.fWidth, size.fHeight); |
| } |
| using std::swap; |
| auto surf = SkSurfaces::Raster( |
| SkImageInfo::Make(size, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); |
| auto* canvas = surf->getCanvas(); |
| SkMatrix m = SkEncodedOriginToMatrix(origin, kImgW, kImgH); |
| SkAssertResult(m.invert(&m)); |
| canvas->concat(m); |
| canvas->clear(SK_ColorBLACK); |
| SkPaint paint; |
| paint.setColor(SK_ColorRED); |
| SkScalar midX = kImgW / 2.f; |
| SkScalar midY = kImgH / 2.f; |
| SkScalar w = midX - 1; |
| SkScalar h = midY - 1; |
| canvas->drawRect(SkRect::MakeXYWH(1, 1, w, h), paint); |
| paint.setColor(SK_ColorBLUE); |
| canvas->drawRect(SkRect::MakeXYWH(midX, 1, w, h), paint); |
| paint.setColor(SK_ColorGREEN); |
| canvas->drawRect(SkRect::MakeXYWH(1, midY, w, h), paint); |
| paint.setColor(SK_ColorYELLOW); |
| canvas->drawRect(SkRect::MakeXYWH(midX, midY, w, h), paint); |
| SkFont font(ToolUtils::DefaultPortableTypeface(), kImgH / 4.f); |
| |
| SkPaint blurPaint; |
| blurPaint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, .75f)); |
| blurPaint.setColor(SK_ColorBLACK); |
| paint.setColor(SK_ColorWHITE); |
| |
| auto drawLabel = [&](const char* string, SkScalar x, SkScalar y) { |
| canvas->save(); |
| canvas->translate(1, 1); |
| canvas->drawString(string, x, y, font, blurPaint); |
| canvas->restore(); |
| canvas->drawString(string, x, y, font, paint); |
| }; |
| |
| auto measure = [&font](const char* text) { |
| SkRect bounds; |
| font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds); |
| return bounds; |
| }; |
| |
| static constexpr SkScalar kPad = 3.f; |
| SkRect bounds; |
| |
| bounds = measure("top"); |
| drawLabel("top", midX - bounds.centerX(), -bounds.top() + kPad); |
| |
| bounds = measure("bottom"); |
| drawLabel("bottom", midX - bounds.centerX(), kImgH - kPad - bounds.bottom()); |
| |
| // It looks weird if "left" and "right" and the number at the center aren't vertically |
| // aligned. |
| SkScalar baseY = midY - measure("leftright").centerY(); |
| bounds = measure("left"); |
| drawLabel("left", kPad - bounds.left(), baseY); |
| |
| bounds = measure("right"); |
| drawLabel("right", kImgW - kPad - bounds.right(), baseY); |
| |
| SkString num = SkStringPrintf("%d", i); |
| bounds = measure(num.c_str()); |
| drawLabel(num.c_str(), midX - bounds.centerX(), baseY); |
| num.append(".png"); |
| SkPixmap pm; |
| surf->makeImageSnapshot()->peekPixels(&pm); |
| ToolUtils::EncodeImageToPngFile(num.c_str(), pm); |
| } |
| } |
| |
| // This gm draws 8 images that are mostly the same when respecting the |
| // EXIF orientation tag. Each one has four quadrants (red, blue, green, |
| // yellow), and labels on the left, top, right and bottom. The only |
| // visual difference is a number in the middle corresponding to the |
| // EXIF tag for that image's jpg file. |
| static void draw(SkCanvas* canvas, const char* suffix) { |
| // Avoid unused function warning. |
| if ((false)) { |
| make_images(); |
| } |
| canvas->save(); |
| for (char i = '1'; i <= '8'; i++) { |
| SkString path = SkStringPrintf("images/orientation/%c%s.jpg", i, suffix); |
| auto image = ToolUtils::GetResourceAsImage(path.c_str()); |
| if (!image) { |
| continue; |
| } |
| canvas->drawImage(image, 0, 0); |
| if ('4' == i) { |
| canvas->restore(); |
| canvas->translate(0, image->height()); |
| } else { |
| canvas->translate(image->width(), 0); |
| } |
| } |
| } |
| |
| #define MAKE_GM(subsample) DEF_SIMPLE_GM(orientation_##subsample, canvas, 4*kImgW, 2*kImgH) { \ |
| draw(canvas, "_" #subsample); \ |
| } |
| |
| MAKE_GM(410) |
| MAKE_GM(411) |
| MAKE_GM(420) |
| MAKE_GM(422) |
| MAKE_GM(440) |
| MAKE_GM(444) |