Hi! I would like to propose moving image processing out of Baileys core so Baileys no longer imports image libraries such as Sharp or Jimp itself.
Current behavior
Baileys currently dynamically imports sharp and jimp in src/Utils/messages-media.ts / lib/Utils/messages-media.js, prefers Sharp when present, falls back to Jimp, and throws when neither is available.
The actual image operations Baileys needs are narrow:
- image message thumbnails: resize to small JPEG, default width 32, quality 50
- link preview thumbnails: resize to JPEG, default width 192
- profile picture updates: resize to JPEG, default 640x640, quality 50
- image thumbnails also return original width/height when available
For applications that already have their own image pipeline, pulling another image library only for these small transformations is expensive. In our install, the sizes are roughly:
- Sharp active macOS arm64 stack: about 16 MB
sharp: 596 KB
@img/sharp-darwin-arm64: 280 KB
@img/sharp-libvips-darwin-arm64: 15 MB
- Jimp stack: about 102 MB
jimp: 3.3 MB
@jimp/*: 88 MB
- codec/plugin deps such as
gifwrap, image-q, pngjs, jpeg-js, omggif, utif2, etc.
- Another image library already used by the application,
@silvia-odwyer/photon-node, is about 2.2 MB.
Jimp is especially problematic here: although it avoids native dependencies, its full plugin/codec dependency tree is very large, and it is only needed as Baileys' fallback for generating tiny JPEG thumbnails/profile pictures.
Node does not provide enough built-in image processing for this
For these operations, Baileys really does need either an image library or a caller-provided implementation. Node core does not provide a portable built-in JPEG/PNG/WebP decode + resize + JPEG encode pipeline. So the clean split seems to be:
- Baileys core: no image library imports
- application: provides image processing when it wants generated thumbnails/profile pictures
- no processor: Baileys skips optional generated thumbnails, or throws a targeted error only for operations that truly require processing
Proposal
Add a small optional image processor interface and stop auto-importing Sharp/Jimp from Baileys core.
Possible API shape:
export type BaileysImageProcessor = {
makeImageThumbnail(input: Buffer | string | Readable, options?: {
width?: number;
quality?: number;
}): Promise<{
jpeg: Buffer;
original?: { width?: number; height?: number };
}>;
makeProfilePicture(input: Buffer | string | Readable, options?: {
width?: number;
height?: number;
quality?: number;
}): Promise<{
jpeg: Buffer;
}>;
};
Then expose it on socket config and/or message generation options:
makeWASocket({
...config,
imageProcessor,
});
await sock.sendMessage(jid, content, {
imageProcessor,
});
Suggested behavior without a processor
- If an image/video message already has
jpegThumbnail, use it as today.
- If an image/link preview has no
jpegThumbnail and no imageProcessor, send without an auto-generated thumbnail.
- If width/height are provided by the caller, use them.
- If dimensions are not provided, either omit them or use cheap header parsing where Baileys already has enough data; avoid pulling a full image library just for dimensions.
- For
updateProfilePicture, either accept an already-prepared JPEG or throw a targeted error such as: No imageProcessor configured; pass a processed JPEG or configure imageProcessor.
Upgrade path
To avoid surprising existing users, this could be staged:
- Add
imageProcessor.
- Keep Sharp/Jimp auto-import temporarily behind a legacy compatibility option.
- Warn once when Baileys auto-imports Sharp/Jimp: automatic image library discovery is deprecated; pass
imageProcessor instead.
- In the next major/stable boundary, default to no auto-imports.
- Remove Sharp/Jimp peer dependencies and built-in discovery.
If v7 is still allowed to make this change before stable, an even cleaner path would be to remove auto-imports now and document the optional processor contract.
Expected benefits
- Baileys core no longer imports or peer-depends on image libraries.
- Applications that already have image processing can use Sharp, Jimp, Photon, platform-native APIs, or their existing media pipeline.
- Applications that do not care about generated thumbnails do not pay for image processing at all.
- The public contract stays focused on Baileys' real needs: produce small JPEG thumbnails/profile pictures and optionally original dimensions.
- No need to expose library-specific concepts like Sharp instances, Jimp objects, PNG handling, HEIC support,
limitInputPixels, etc.
Would you be open to moving image processing behind an injected interface like this? I am happy to help with a PR if the direction sounds acceptable.
Hi! I would like to propose moving image processing out of Baileys core so Baileys no longer imports image libraries such as Sharp or Jimp itself.
Current behavior
Baileys currently dynamically imports
sharpandjimpinsrc/Utils/messages-media.ts/lib/Utils/messages-media.js, prefers Sharp when present, falls back to Jimp, and throws when neither is available.The actual image operations Baileys needs are narrow:
For applications that already have their own image pipeline, pulling another image library only for these small transformations is expensive. In our install, the sizes are roughly:
sharp: 596 KB@img/sharp-darwin-arm64: 280 KB@img/sharp-libvips-darwin-arm64: 15 MBjimp: 3.3 MB@jimp/*: 88 MBgifwrap,image-q,pngjs,jpeg-js,omggif,utif2, etc.@silvia-odwyer/photon-node, is about 2.2 MB.Jimp is especially problematic here: although it avoids native dependencies, its full plugin/codec dependency tree is very large, and it is only needed as Baileys' fallback for generating tiny JPEG thumbnails/profile pictures.
Node does not provide enough built-in image processing for this
For these operations, Baileys really does need either an image library or a caller-provided implementation. Node core does not provide a portable built-in JPEG/PNG/WebP decode + resize + JPEG encode pipeline. So the clean split seems to be:
Proposal
Add a small optional image processor interface and stop auto-importing Sharp/Jimp from Baileys core.
Possible API shape:
Then expose it on socket config and/or message generation options:
Suggested behavior without a processor
jpegThumbnail, use it as today.jpegThumbnailand noimageProcessor, send without an auto-generated thumbnail.updateProfilePicture, either accept an already-prepared JPEG or throw a targeted error such as:No imageProcessor configured; pass a processed JPEG or configure imageProcessor.Upgrade path
To avoid surprising existing users, this could be staged:
imageProcessor.imageProcessorinstead.If v7 is still allowed to make this change before stable, an even cleaner path would be to remove auto-imports now and document the optional processor contract.
Expected benefits
limitInputPixels, etc.Would you be open to moving image processing behind an injected interface like this? I am happy to help with a PR if the direction sounds acceptable.