Skip to content

Commit a54cd33

Browse files
authored
fix: drawImage with exif orientation (#814)
1 parent 11ab7e2 commit a54cd33

File tree

5 files changed

+54
-8
lines changed

5 files changed

+54
-8
lines changed

__test__/fixtures/with-exif.jpg

131 KB
Loading

__test__/image.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,24 @@ test('alt state should be ok', (t) => {
4848
t.is(image.alt, 'hello')
4949
})
5050

51+
test('with-exif image width and height should be correct', async (t) => {
52+
const file = await fs.readFile(join(__dirname, 'fixtures', 'with-exif.jpg'))
53+
const image = new Image()
54+
image.src = file
55+
t.is(image.width, 450)
56+
t.is(image.height, 600)
57+
})
58+
59+
test('draw-image-exif', async (t) => {
60+
const file = await fs.readFile(join(__dirname, 'fixtures', 'with-exif.jpg'))
61+
const image = new Image()
62+
image.src = file
63+
const canvas = createCanvas(800, 800)
64+
const ctx = canvas.getContext('2d')
65+
ctx.drawImage(image, 0, 0)
66+
await snapshotImage(t, { canvas })
67+
})
68+
5169
test('properties should be readonly', (t) => {
5270
const image = new Image()
5371
const expectation = {
618 KB
Loading

load-image.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ const { Readable } = require('stream')
44

55
let http, https
66

7-
const MAX_REDIRECTS = 20,
8-
REDIRECT_STATUSES = new Set([301, 302]),
9-
DATA_URI = /^\s*data:/
7+
const MAX_REDIRECTS = 20
8+
const REDIRECT_STATUSES = new Set([301, 302])
109

1110
/**
1211
* Loads the given source into canvas Image
@@ -23,7 +22,7 @@ module.exports = async function loadImage(source, options = {}) {
2322
// if the source is Image instance, copy the image src to new image
2423
if (source instanceof Image) return createImage(source.src, options.alt)
2524
// if source is string and in data uri format, construct image using data uri
26-
if (typeof source === 'string' && DATA_URI.test(source)) {
25+
if (typeof source === 'string' && source.trimStart().startsWith('data:')) {
2726
const commaIdx = source.indexOf(',')
2827
const encoding = source.lastIndexOf('base64', commaIdx) < 0 ? 'utf-8' : 'base64'
2928
const data = Buffer.from(source.slice(commaIdx + 1), encoding)

skia-c/skia_c.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,13 +1482,42 @@ extern "C"
14821482
auto data = SkData::MakeWithoutCopy(reinterpret_cast<const void *>(ptr), size);
14831483
auto codec = SkCodec::MakeFromData(data);
14841484
auto info = codec->getInfo();
1485-
auto row_bytes = info.width() * info.bytesPerPixel();
1485+
auto row_bytes = info.minRowBytes();
14861486
auto bitmap = new SkBitmap();
14871487
bitmap->allocPixels(info);
14881488
codec->getPixels(info, bitmap->getPixels(), row_bytes);
1489-
bitmap_info->bitmap = reinterpret_cast<skiac_bitmap *>(bitmap);
1490-
bitmap_info->width = info.width();
1491-
bitmap_info->height = info.height();
1489+
auto dimension = codec->dimensions();
1490+
auto origin = codec->getOrigin();
1491+
auto width = dimension.width();
1492+
auto height = dimension.height();
1493+
// https://github.com/chromium/chromium/blob/126.0.6423.1/third_party/blink/renderer/platform/graphics/image.cc#L124
1494+
// need to create a new bitmap with the correct orientation
1495+
if (origin != SkEncodedOrigin::kTopLeft_SkEncodedOrigin) {
1496+
if (
1497+
origin == SkEncodedOrigin::kLeftTop_SkEncodedOrigin ||
1498+
origin == SkEncodedOrigin::kRightTop_SkEncodedOrigin ||
1499+
origin == SkEncodedOrigin::kRightBottom_SkEncodedOrigin ||
1500+
origin == SkEncodedOrigin::kLeftBottom_SkEncodedOrigin
1501+
)
1502+
{
1503+
width = height;
1504+
height = dimension.width();
1505+
}
1506+
auto oriented_bitmap = new SkBitmap();
1507+
auto oriented_bitmap_info = SkImageInfo::Make(width, height, info.colorType(), info.alphaType());
1508+
oriented_bitmap->allocPixels(oriented_bitmap_info);
1509+
auto canvas = new SkCanvas(*oriented_bitmap);
1510+
auto matrix = SkEncodedOriginToMatrix(origin, width, height);
1511+
canvas->setMatrix(matrix);
1512+
auto image = SkImages::RasterFromBitmap(*bitmap);
1513+
canvas->drawImage(image, 0, 0);
1514+
bitmap_info->bitmap = reinterpret_cast<skiac_bitmap *>(oriented_bitmap);
1515+
delete bitmap;
1516+
} else {
1517+
bitmap_info->bitmap = reinterpret_cast<skiac_bitmap *>(bitmap);
1518+
}
1519+
bitmap_info->width = width;
1520+
bitmap_info->height = height;
14921521
}
14931522

14941523
void skiac_bitmap_make_from_svg(const uint8_t *data, size_t length, float width, float height, skiac_bitmap_info *bitmap_info, skiac_font_collection *c_collection, uint8_t cs)

0 commit comments

Comments
 (0)