Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Feature request: Create render API that returns byte array #11142

Open
sbressler opened this Issue Mar 15, 2013 · 9 comments

Comments

Projects
None yet
4 participants

This change provides a render API to get a screenshot as a base64 string. Can we add an even simpler API to get a byte array of image data? Would be useful to stream a rendered page back as it's generated.

I'm also interested in support for returning the rendered data as a stream, particularly if I can I pipe to other node modules, such as streaming the result to S3 for storage. Not sure if that would work in the context of PhantomJS.

And I'm also... What if I want to optimize image using another tools like pngquant?
It would be great for build scripts without transient writes to disk.
All the solutions I seen creating a temporary file.

Any news about this feature?

@koutsenko Regarding writing to disk, you could always use an in-memory file system if you are concerned about the performance of disk access. Ubuntu Linux provides /dev/shm for this purpose: http://www.cyberciti.biz/tips/what-is-devshm-and-its-practical-usage.html

+1.

I'm writing a web server endpoint that takes a POST request containing HTML and returns a PNG as the response body (Content-Type: image/png). Currently, I have to resort to this:

var imageFile = "/tmp/" + randomString(8) + ".png";
page.render(imageFile);
var imageBytes = fs.read(imageFile, { mode: "b" }); // binary mode
fs.remove(imageFile);

which is not ideal, since I want the service to be as fast as possible.

@ismasan several Linux distros provided /dev/shm as a RAM disk. If you replace /tmp in your code with /dev/shm, you can write to memory instead of disk. You can likely create your own ramdisk if your OS doesn't provide one.

I'm developing on OS X. I could create a RAM disk for my system, but I'd rather not make that a requirement for everyone else on my team.

I did find a better way to do this that doesn't require a temp file:

var imageBytes = atob(page.renderBase64("png"));

It's still not ideal, because it encodes to base64 and then decodes back to bytes, but it's definitely better than using a temp file.

Any chance PhantomJS can add an API that looks something like this:

var imageBytes = page.renderBytes();

?

@ispringer the temp dir could be a configuration variable that is set to /tmp for local development, where it doesn't matter if it's a fraction of a second slower, and then then /dev/shm for production.

Having an option to get back just the bytes is nice, but something needs to control the upper-bound of the size, to prevent malicious requests that exhaust memory. Along with the feature to get back just the bytes, it would then also be helpful add some kind of "max bytes" configuration option to Phantom with sane default, to avoid trying to fit extra huge renders into memory.

@markstos, that's a good idea. Thanks. I may go with that until renderBytes is added, since /dev/shm will likely be faster than the base64 roundtrip.

@ispringer I have used /dev/shm to solve the same kind of problem in production before. The only downside is if there's a "leak" in the cleanup process somehow, causing the tmp files to accumulate in memory. There's a slight race-condition of files getting stuck there if the server unexpectedly terminates while the file has been written there, but not yet deleted. In practice, it seems unlikely to be a problem, but worth mentioning.

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