Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/common/type-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ function serializeNativeImage (image: Electron.NativeImage) {
if (scaleFactors.length === 1) {
const scaleFactor = scaleFactors[0];
const size = image.getSize(scaleFactor);
const buffer = image.toBitmap({ scaleFactor });
// A raw bitmap is read back using `size`, which is in DIPs, so it only
// round-trips at scale factor 1. Otherwise send a PNG, which carries its
// own pixel dimensions.
const buffer = scaleFactor === 1
? image.toBitmap({ scaleFactor })
: image.toPNG({ scaleFactor });
representations.push({ scaleFactor, size, buffer });
} else {
// Construct from dataURLs to ensure that they are not lost in creation.
Expand Down
86 changes: 86 additions & 0 deletions test/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,20 @@ function makeEachWindow () {
return () => w
}

// Builds a single-representation image whose pixels are all distinct, so that
// any change in dimensions or row stride shows up as a pixel mismatch.
function makeScaledImage (scaleFactor: number) {
const width = 200
const height = 200
const buffer = Buffer.alloc(width * height * 4)
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
buffer.writeUInt32LE((0xff000000 | (x << 8) | y) >>> 0, (y * width + x) * 4)
}
}
return nativeImage.createFromBitmap(buffer, { width, height, scaleFactor })
}

describe('typeUtils serialization/deserialization', () => {
it('serializes and deserializes an empty NativeImage', () => {
const image = nativeImage.createEmpty()
Expand Down Expand Up @@ -145,6 +159,17 @@ describe('typeUtils serialization/deserialization', () => {
expect(nonEmpty.toDataURL()).to.not.be.empty()
})

for (const scaleFactor of [1.5, 2.0]) {
it(`serializes and deserializes a NativeImage with a single representation at scale factor ${scaleFactor}`, () => {
const image = makeScaledImage(scaleFactor)
const deserialized = deserialize(serialize(image))

expect(deserialized.getScaleFactors()).to.deep.equal([scaleFactor])
expect(deserialized.getSize(scaleFactor)).to.deep.equal(image.getSize(scaleFactor))
expect(deserialized.toBitmap({ scaleFactor }).equals(image.toBitmap({ scaleFactor }))).to.be.true()
})
}

it('serializes and deserializes an Array', () => {
const array = [1, 2, 3, 4, 5]
const serialized = serialize(array)
Expand Down Expand Up @@ -415,6 +440,67 @@ describe('remote module', () => {
})).to.eventually.deep.equal({ width: 2, height: 2 })
})

for (const scaleFactor of [1.5, 2.0]) {
it(`preserves a nativeImage at scale factor ${scaleFactor} from renderer to main`, async () => {
const expected = makeScaledImage(scaleFactor)
const checkImage = (img: NativeImage) => ({
scaleFactors: img.getScaleFactors(),
size: img.getSize(scaleFactor),
identical: img.toBitmap({ scaleFactor }).equals(expected.toBitmap({ scaleFactor }))
})

w().webContents.once('remote-get-global' as any, (event: any) => {
event.returnValue = checkImage
})

await expect(remotely((scaleFactor: number) => {
const { nativeImage } = require('electron')
const remote = require('./renderer')
const buffer = Buffer.alloc(200 * 200 * 4)
for (let y = 0; y < 200; y++) {
for (let x = 0; x < 200; x++) {
buffer.writeUInt32LE((0xff000000 | (x << 8) | y) >>> 0, (y * 200 + x) * 4)
}
}
const image = nativeImage.createFromBitmap(buffer, { width: 200, height: 200, scaleFactor })
return remote.getGlobal('someFunction')(image)
}, scaleFactor)).to.eventually.deep.equal({
scaleFactors: [scaleFactor],
size: expected.getSize(scaleFactor),
identical: true
})
})

it(`preserves a nativeImage at scale factor ${scaleFactor} from main to renderer`, async () => {
const expected = makeScaledImage(scaleFactor)

w().webContents.once('remote-get-global' as any, (event: any) => {
event.returnValue = makeScaledImage(scaleFactor)
})

await expect(remotely((scaleFactor: number) => {
const { nativeImage } = require('electron')
const image = require('./renderer').getGlobal('someFunction')
const buffer = Buffer.alloc(200 * 200 * 4)
for (let y = 0; y < 200; y++) {
for (let x = 0; x < 200; x++) {
buffer.writeUInt32LE((0xff000000 | (x << 8) | y) >>> 0, (y * 200 + x) * 4)
}
}
const original = nativeImage.createFromBitmap(buffer, { width: 200, height: 200, scaleFactor })
return {
scaleFactors: image.getScaleFactors(),
size: image.getSize(scaleFactor),
identical: image.toBitmap({ scaleFactor }).equals(original.toBitmap({ scaleFactor }))
}
}, scaleFactor)).to.eventually.deep.equal({
scaleFactors: [scaleFactor],
size: expected.getSize(scaleFactor),
identical: true
})
})
}

it('can properly create a menu with an nativeImage icon in the renderer', async () => {
await expect(remotely(() => {
const { nativeImage } = require('electron')
Expand Down
Loading