diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml
index 2c1642af..a8bbbbeb 100755
--- a/.github/workflows/CI.yaml
+++ b/.github/workflows/CI.yaml
@@ -199,7 +199,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- node: ['14', '16', '18']
+ node: ['18']
runs-on: ubuntu-latest
steps:
@@ -324,7 +324,7 @@ jobs:
run: ls -R .
shell: bash
- name: Test bindings
- run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-slim yarn test
+ run: docker run --rm -v /usr/share/fonts:/usr/share/fonts -v $(pwd):/build -w /build node:${{ matrix.node }}-slim yarn test
test-linux-x64-musl-binding:
name: Test bindings on x86_64-unknown-linux-musl - node@${{ matrix.node }}
needs:
@@ -363,7 +363,7 @@ jobs:
run: ls -R .
shell: bash
- name: Test bindings
- run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-alpine yarn test
+ run: docker run --rm -v /usr/share/fonts:/usr/share/fonts -v $(pwd):/build -w /build node:${{ matrix.node }}-alpine yarn test
test-linux-aarch64-gnu-binding:
name: Test bindings on aarch64-unknown-linux-gnu - node@${{ matrix.node }}
needs:
@@ -401,11 +401,12 @@ jobs:
uses: addnab/docker-run-action@v3
with:
image: ghcr.io/napi-rs/napi-rs/nodejs:aarch64-${{ matrix.node }}
- options: '-v ${{ github.workspace }}:/build -w /build'
+ options: '-v /usr/share/fonts:/usr/share/fonts -v ${{ github.workspace }}:/build -w /build'
run: |
set -e
- yarn test
+ find /usr/share/fonts -name *.ttf
ls -la
+ yarn test
test-linux-aarch64-musl-binding:
name: Test bindings on aarch64-unknown-linux-musl - node@${{ matrix.node }}
needs:
@@ -436,9 +437,10 @@ jobs:
uses: addnab/docker-run-action@v3
with:
image: multiarch/alpine:aarch64-latest-stable
- options: '-v ${{ github.workspace }}:/build -w /build'
+ options: '-v /usr/share/fonts:/usr/share/fonts -v ${{ github.workspace }}:/build -w /build'
run: |
set -e
+ find /usr/share/fonts -name *.ttf
apk add nodejs npm yarn
yarn test
test-linux-arm-gnueabihf-binding:
@@ -477,11 +479,12 @@ jobs:
uses: addnab/docker-run-action@v3
with:
image: ghcr.io/napi-rs/napi-rs/nodejs:armhf-${{ matrix.node }}
- options: '-v ${{ github.workspace }}:/build -w /build'
+ options: '-v /usr/share/fonts:/usr/share/fonts -v ${{ github.workspace }}:/build -w /build'
run: |
set -e
- yarn test
+ find /usr/share/fonts -name *.ttf
ls -la
+ yarn test
publish:
name: Publish
diff --git a/__test__/index.spec.ts b/__test__/index.spec.ts
index 7e9f42bc..25df3650 100755
--- a/__test__/index.spec.ts
+++ b/__test__/index.spec.ts
@@ -224,6 +224,100 @@ test('Load custom font', async (t) => {
t.is(result.getHeight(), 687)
})
+test('should be load custom fontFiles(no defaultFontFamily option)', (t) => {
+ const svg = `
+
+ `
+ const resvg = new Resvg(svg, {
+ font: {
+ fontFiles: ['./example/SourceHanSerifCN-Light-subset.ttf'],
+ loadSystemFonts: false,
+ // defaultFontFamily: 'Source Han Serif CN Light',
+ },
+ logLevel: 'debug',
+ })
+ const pngData = resvg.render()
+ const originPixels = pngData.pixels.toJSON().data
+
+ // Find the number of blue `rgb(0,255,255)`pixels
+ t.is(originPixels.join(',').match(/0,0,255/g)?.length, 1726)
+})
+
+test('should be load custom fontDirs(no defaultFontFamily option)', (t) => {
+ const svg = `
+
+ `
+ const resvg = new Resvg(svg, {
+ font: {
+ fontDirs: ['./example/'],
+ // loadSystemFonts: false,
+ // defaultFontFamily: 'Source Han Serif CN Light',
+ },
+ logLevel: 'debug',
+ })
+ const pngData = resvg.render()
+ const originPixels = pngData.pixels.toJSON().data
+
+ // Find the number of blue `rgb(0,255,255)`pixels
+ t.is(originPixels.join(',').match(/0,0,255/g)?.length, 1726)
+})
+
+test('The defaultFontFamily is not found in the OS and needs to be fallback', (t) => {
+ const svg = `
+
+ `
+ const resvg = new Resvg(svg, {
+ font: {
+ loadSystemFonts: true,
+ fontDirs: ['/usr/share/fonts/'], // 防止在 CI 的 Docker 环境找不到字体
+ defaultFontFamily: 'this-is-a-non-existent-font-family',
+ },
+ logLevel: 'debug',
+ })
+ const pngData = resvg.render()
+ const originPixels = pngData.pixels.toJSON().data
+ // Find the number of blue `rgb(0,255,255)`pixels
+ const matchPixels = originPixels.join(',').match(/0,0,255/g)
+ t.true(matchPixels !== null) // If the font is not matched, there are no blue pixels.
+ t.true((matchPixels?.length ?? 0) > 1500)
+})
+
+test('Test defaultFontFamily', (t) => {
+ const svg = `
+
+ `
+ const resvg = new Resvg(svg, {
+ font: {
+ loadSystemFonts: false,
+ fontDirs: ['./example'],
+ defaultFontFamily: 'Source Han Serif CN Light', // 指定中文字体,期望自动 fallback 到英文 字体 Pacifico.
+ },
+ logLevel: 'debug',
+ })
+ const pngData = resvg.render()
+ const originPixels = pngData.pixels.toJSON().data
+ // Find the number of blue `rgb(0,255,255)`pixels
+ const matchPixels = originPixels.join(',').match(/0,0,255/g)
+ t.true(matchPixels !== null) // If the font is not matched, there are no blue pixels.
+ t.true((matchPixels?.length ?? 0) > 1500)
+})
+
test('Async rendering', async (t) => {
const filePath = '../example/text.svg'
const svg = await fs.readFile(join(__dirname, filePath))
@@ -249,7 +343,7 @@ test('Async rendering', async (t) => {
const MaybeTest = typeof AbortController !== 'undefined' ? test : test.skip
MaybeTest('should be able to abort queued async rendering', async (t) => {
- // fill the task queue
+ // Fill the task queue
for (const _ of Array.from({ length: 100 })) {
process.nextTick(() => {})
}
@@ -449,27 +543,27 @@ test('should return undefined if bbox is invalid', (t) => {
t.is(resvg.innerBBox(), undefined)
})
-test('should be load custom fonts', (t) => {
- const svg = `
-
- `
+test('should render using font buffer provided by options', async (t) => {
+ const svg = ``
+
+ const expectedResultBuffer = await fs.readFile(join(__dirname, './options_font_buffer_expected_result.png'))
+
const resvg = new Resvg(svg, {
font: {
- fontFiles: ['./example/SourceHanSerifCN-Light-subset.ttf'],
+ fontFiles: ['./__test__/Pacifico-Regular.ttf'],
loadSystemFonts: false,
- defaultFontFamily: 'Source Han Serif CN Light',
+ defaultFontFamily: '',
},
logLevel: 'debug',
})
- const pngData = resvg.render()
- const originPixels = pngData.pixels.toJSON().data
+ const renderedResult = resvg.render().asPng()
- // Find the number of blue `rgb(0,255,255)`pixels
- t.is(originPixels.join(',').match(/0,0,255/g)?.length, 1726)
+ const expectedResult = await jimp.read(Buffer.from(expectedResultBuffer.buffer))
+ const actualPng = await jimp.read(Buffer.from(renderedResult))
+
+ t.is(jimp.diff(expectedResult, actualPng, 0.01).percent, 0) // 0 means similar, 1 means not similar
})
test('should throw because invalid SVG attribute (width attribute is 0)', (t) => {
diff --git a/__test__/wasm.spec.ts b/__test__/wasm.spec.ts
index 4e894967..09c35711 100755
--- a/__test__/wasm.spec.ts
+++ b/__test__/wasm.spec.ts
@@ -206,6 +206,65 @@ test('Set the background without alpha by hsla()', async (t) => {
t.is(result.hasAlpha(), false)
})
+test('Load custom font(use fontsBuffers option)', async (t) => {
+ const filePath = '../example/text.svg'
+ const svg = await fs.readFile(join(__dirname, filePath))
+ const fontBuffer = await fs.readFile(join(__dirname, '../example/SourceHanSerifCN-Light-subset.ttf'))
+ const resvg = new Resvg(svg.toString('utf-8'), {
+ font: {
+ fontsBuffers: [fontBuffer], // Load custom fonts.
+ },
+ })
+ const pngBuffer = resvg.render().asPng()
+ const result = await jimp.read(Buffer.from(pngBuffer))
+
+ t.is(result.getWidth(), 1324)
+ t.is(result.getHeight(), 687)
+})
+
+test('should be load custom font(no defaultFontFamily option)', async (t) => {
+ const svg = `
+
+ `
+ const fontBuffer = await fs.readFile(join(__dirname, '../example/SourceHanSerifCN-Light-subset.ttf'))
+ const resvg = new Resvg(svg, {
+ font: {
+ fontsBuffers: [fontBuffer],
+ // defaultFontFamily: 'Source Han Serif CN Light',
+ },
+ })
+ const pngData = resvg.render()
+ const originPixels = Array.from(pngData.pixels)
+
+ // Find the number of blue `rgb(0,255,255)`pixels
+ t.is(originPixels.join(',').match(/0,0,255/g)?.length, 1726)
+})
+
+test('should be load custom fontsBuffers(no defaultFontFamily option)', async (t) => {
+ const svg = `
+
+ `
+ const fontBuffer = await fs.readFile(join(__dirname, '../example/SourceHanSerifCN-Light-subset.ttf'))
+ const resvg = new Resvg(svg, {
+ font: {
+ fontsBuffers: [fontBuffer],
+ },
+ })
+ const pngData = resvg.render()
+ const originPixels = Array.from(pngData.pixels)
+
+ // Find the number of blue `rgb(0,255,255)`pixels
+ t.is(originPixels.join(',').match(/0,0,255/g)?.length, 1726)
+})
+
test('should generate a 80x80 png and opaque', async (t) => {
const svg = `