Как создать Javascript WritableStream в памяти (например, fs.creareWriteStream)

Я пытаюсь использовать некоторую библиотеку JS с ServiceWorker без доступа к функциям файловой системы Node.JS. Результат экспорта исходной библиотеки такой же.

Import * as fs from 'fs'
...
JsLib.export(result, fs.createWriteStream("res.pdf")) 

Мне нужен тот же экспорт, но экспорт в байтовый массив без файловой системы. Я создал массив таким же образом

 const Out = (Array as any).create("byte", mysize)

и если я вручную заполняю этот массив байтов тестовыми данными, мой алгоритм дальше работает нормально.
Но я не понимаю, как правильно создать такой же поток, как созданный Node.JS, но в памяти, в моем массиве «Out».
В MDN есть несколько примеров с WritableStream, но я не уверен, как эти примеры связаны с этой задачей. Возможно, есть дешевое решение, например

JsLib.export(result, ...Out) 

Или это решение не эмулирует fs.createWriteStream? Непосредственное использование синтаксиса распространения невозможно: «Аргумент распространения должен либо иметь тип кортежа, либо быть передан в параметр rest». Но как правильно решить этот квест?

Обновление. Это ответ @l3l_aze с очень простым тестом, к сожалению, это решение не работает.

Было бы хорошо указать хотя бы название библиотеки, которую вы используете. NodeJS гораздо более низкий уровень, чем JS в веб-браузере, поэтому, несмотря на то, что оба имеют потоки, они не обязательно эквивалентны. Соответствующий вопрос; видимо потоки похожи.

l3l_aze 08.04.2024 23:38

@l3l_aze, это моя общая проблема при работе с сервис-воркером. В данном случае мне нужно решить эту проблему с помощью библиотеки pureimage.

Viacheslav 09.04.2024 08:02

Можете ли вы включить больше кода? Это должно быть просто, но нам нужно знать, как вы получаете данные. Последний пример в README pureimage (чуть выше «Устранение неполадок») использует буфер, который выглядит примерно так, как вам хотелось бы. В JS мы бы использовали ArrayBuffer . Затем используйте DataView, чтобы проверить магическое значение/маску файла.

l3l_aze 10.04.2024 00:22

IDK TS или pureimage, но, возможно, стоит попробовать JsLib.export(result, new ArrayBuffer(Out)).

l3l_aze 10.04.2024 01:40

@l3l_aze, спасибо, я добавляю очень простой тест, к сожалению, arrayBuffer не может заменить поток выходной памяти

Viacheslav 10.04.2024 20:11
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
0
5
123
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как я уже сказал выше, я не знаю TS, так что это просто NodeJS/ванильный JS. Настоятельно рекомендую изучить это больше, чем пару часов, которые я потратил, поскольку, возможно, поток не закрывается должным образом, и, очевидно, не предусмотрена обработка ошибок.

Однако на выходе получается красный квадрат в формате PNG. Чтобы визуально подтвердить тест, я скопировал выходные данные и использовал расширение VSCode Hex Editor, чтобы вставить их в существующий file.png с выбранной опцией base64. Затем пришлось удалить (Del, а не Backspace) оставшиеся байты из предыдущих данных, которыми мне пришлось их заполнить, чтобы шестнадцатеричный редактор позволял вставить. Ржу не могу.

'use strict'

import * as PImage from 'pureimage'
import Stream from 'stream'

const width = 32
const height = 32
const img1 = PImage.make(width, height)

const ctx = img1.getContext('2d')

ctx.fillStyle = 'red'
ctx.fillRect(0, 0, width, height)

const pngData = []

const dest = new Stream()
dest.writable = true

dest.write = function (data) {
  for (let i = 0; i < data.length; i++) {
    dest.emit('data', data[i])
  }
}

// Act like a passThrough stream; in one ear and out the other.
dest.on('data', (chunk) => {
  pngData.push(chunk)
})

dest.on('end', () => {})

// For
// https://github.com/joshmarinacci/node-pureimage/blob/6775bc3dedfd4247c0ee11382e1aebdf2703ca45/src/image.ts#L57
dest.end = function () {
  dest.emit('finish')
}

dest.close = function () {
  dest.emit('close')
}

function assert (a, b) {
  if (a !== b) {
    throw new Error(`${a} !== ${b}`)
  } else {
    return true
  }
}

const buf = await PImage.encodePNGToStream(img1, dest).then(() => {
  return new Uint8Array(pngData)
})

if (assert(buf[0], 0x89) &&
    assert(buf[1], 0x50) &&
    assert(buf[2], 0x4e) &&
    assert(buf[3], 0x47)) {
  console.info('buffer contains png header')

  const ascii = Array.from(buf).map((b) => String.fromCharCode(b))
  const b64 = btoa(ascii.join(''))

  console.info(b64)
  // iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAklEQVR4AewaftIAAABBSURBVMXBAQEAAAiDMKR/5xuD7QYjJDGJSUxiEpOYxCQmMYlJTGISk5jEJCYxiUlMYhKTmMQkJjGJSUxiEpOYxB4w4wI+EhsQ6
AAAAABJRU5ErkJggg==
}

Другие вопросы по теме