Skip to content

Instantly share code, notes, and snippets.

@sspencer
Created October 31, 2010 22:27
Show Gist options
  • Save sspencer/657246 to your computer and use it in GitHub Desktop.
Save sspencer/657246 to your computer and use it in GitHub Desktop.
Serve a transparent GIF from NodeJS
// Two ways to serve transparent GIF
var buf = new Buffer([
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00,
0x80, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x2c,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02,
0x02, 0x44, 0x01, 0x00, 0x3b]);
res.send(buf, { 'Content-Type': 'image/gif' }, 200);
// --- OR ----
var buf = new Buffer(35);
buf.write("R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=", "base64");
res.send(buf, { 'Content-Type': 'image/gif' }, 200);
@zimdo
Copy link

zimdo commented Mar 19, 2012

btw. the smallest transparent gif is actually 35 pixels :)

char EMPTY_GIF[] = {
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0x80, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3b
};

@sspencer
Copy link
Author

Thanks - now serves transparent GIF in 35 bytes instead of 43.

@zimdo
Copy link

zimdo commented Mar 19, 2012

:o :)

@bobgrigoryan
Copy link

and these 35 bytes actually represent 1x1 white pixel GIF, not transparent.

@primaryobjects
Copy link

To have the browser render an inline image, rather than forcing a download of the file, try the following to serve the image:

res.writeHead(200, {'Content-Type': 'image/gif' });
res.end(img, 'binary');

@NoelBaron
Copy link

Thanks. @primaryobjects update worked well for displaying inline.

@mikeifomin
Copy link

@primaryobjects thank you!

@adriaandotcom
Copy link

and these 35 bytes actually represent 1x1 white pixel GIF, not transparent.

This is true, the 35 bytes are not a transparent pixel:

@elhardoum
Copy link

elhardoum commented Feb 17, 2019

Buffer constructor is now deprecated (Node 10), suggested to use Buffer.alloc.

let buffer = Buffer.alloc(35)
buffer.write('R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=', 'base64')
res.writeHead(200, {'Content-Type': 'image/gif'})
res.end(buffer, 'binary')

Edit - thanks Chris for pointing out the transparency issue with the base64 image from this gist - use theirs or the following snippet instead:

const b64blob = 'R0lGODlhAQABAPAAAAAAAAAAACH5BAUKAAAALAAAAAABAAEAQAICRAEAOw=', buffer = Buffer.alloc(b64blob.length)
buffer.write(b64blob, 'base64')
res.writeHead(200, {'Content-Type': 'image/gif'})
res.end(buffer, 'binary')

@eliseumds
Copy link

eliseumds commented Mar 12, 2019

const TRANSPARENT_GIF_BUFFER = Buffer.from('R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=', 'base64');

function someHandler(req, res) {
  res.writeHead(200, { 'Content-Type': 'image/gif' });
  res.end(TRANSPARENT_GIF_BUFFER, 'binary');
}

@chrisspiegl
Copy link

@elhardoum and @eliseumds:

I tried both of your versions, but on a 100% black background both of them do not show up as transparent but white (in Google Chrome). See the white dot on the screenshot:

Capture 2022-02-14 at 15 31 47

I ended up using the suggestions from the top with a buffer size of 43 (which can also be set with a const buffer instead of a let since the assignment actually does not change):

import { Buffer } from 'node:buffer'
const buffer = Buffer.alloc(43)
buffer.write('R0lGODlhAQABAIAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=', 'base64')
response.writeHead(200, { 'Content-Type': 'image/gif' })
response.end(buffer, 'binary')

@elhardoum
Copy link

@chrisspiegl chrome, since not so long ago, started adding grey backgrounds to their image viewer. If you inspect the img tag, you'll see it adds these inline styles, one of them is a grey background:

-webkit-user-select: none;
margin: auto;
background-color: hsl(0, 0%, 90%);
transition: background-color 300ms;

@chrisspiegl
Copy link

@elhardoum Not sure where you got these from. I don't see those stylings in the most recent version of Chrome 98.0.4758.80.

When I inspect the img element they don't show up (even when ticking the Show all checkbox).

But the 35 byte one shows up as a white pixel and the 43 byte one is transparent and invisible on a black background.

@elhardoum
Copy link

elhardoum commented Feb 14, 2022

@chrisspiegl my bad, didn't pay close attention - the image is shown on a website not the standard chrome image viewer page. I'll improve my answer, ty

@jjolmo
Copy link

jjolmo commented Nov 23, 2023

@chrisspiegl solution worked like a charm. Displays perfectly transparent. Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment