PhantomJS: Eksport PDF do stdout

Czy istnieje sposób na uruchomienie funkcji eksportu PDF w PhantomJS bez określania pliku wyjściowego za pomocą .rozszerzenie pdf? Chcemy użyć stdout do wyświetlenia pliku PDF.

Author: Pooria Azimi, 2012-07-10

4 answers

Jak zauważył Niko, możesz użyć renderBase64(), aby renderować stronę internetową do bufora obrazu i zwrócić wynik jako zakodowany łańcuch base64.
ale na razie będzie to działać tylko dla PNG, JPEG i GIF.

Aby napisać coś ze skryptu phantomjs na stdout wystarczy użyć API systemu plików.

Używam czegoś takiego do zdjęć:

var base64image = page.renderBase64('PNG');
var fs = require("fs");
fs.write("/dev/stdout", base64image, "w");

Nie wiem, czy Format PDF dla renderBase64() będzie w przyszłej wersji phanthomjs, ale jako obejście coś w tym stylu może praca dla Ciebie:

page.render(output);
var fs = require("fs");
var pdf = fs.read(output);
fs.write("/dev/stdout", pdf, "w");
fs.remove(output);

Gdzie output jest ścieżką do pliku pdf.

 13
Author: Enrico Mischorr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-16 15:58:16

Możesz wypisać bezpośrednio na stdout bez potrzeby używania pliku tymczasowego.

page.render('/dev/stdout', { format: 'pdf' });

Zobacz tutaj aby dowiedzieć się, kiedy to zostało dodane.

Jeśli chcesz pobrać HTML ze standardowego wejścia i wysłać plik PDF do standardowego wyjścia, zobacz tutaj

 19
Author: philfreo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:40

Przepraszam za niezwykle długą odpowiedź; mam wrażenie, że będę musiał odwoływać się do tej metody kilkadziesiąt razy w życiu, więc napiszę "jedna odpowiedź, aby rządzić nimi wszystkimi". Najpierw będę paplał trochę o plikach, deskryptorach plików, (nazwanych) rurach i przekierowaniu wyjścia, a następnie odpowiem na twoje pytanie.


Rozważ ten prosty program C99:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{

  if (argc < 2) {
    printf("Usage: %s file_name\n", argv[0]);
    return 1;
  }

  FILE* file = fopen(argv[1], "w");
  if (!file) {
    printf("No such file: %s\n", argv[1]);
    return 2;
  }

  fprintf(file, "some text...");

  fclose(file); 

  return 0;
}
Bardzo proste. Pobiera argument (nazwę pliku) i drukuje do niego tekst. Couldn ' t be any prościej.

Skompiluj go z clang write_to_file.c -o write_to_file.o lub gcc write_to_file.c -o write_to_file.o.

Teraz uruchom ./write_to_file.o some_file (który wyświetla się w some_file). Następnie uruchom cat some_file. Wynik, zgodnie z oczekiwaniami, to some text...

Teraz bądźmy bardziej wyszukani. Wpisz (./write_to_file.o /dev/stdout) > some_file w terminalu. Prosimy program o zapis na jego standardowe wyjście (zamiast zwykłego pliku), a następnie przekierowujemy stdout na some_file (używając > some_file). Aby to osiągnąć, mogliśmy użyć dowolnego z następujących elementów:]}

  • (./write_to_file.o /dev/stdout) > some_file, które oznacza " użycie stdout"

  • (./write_to_file.o /dev/stderr) 2> some_file, co oznacza " użyj stderr, i przekieruj go za pomocą 2>"

  • (./write_to_file.o /dev/fd/2) 2> some_file, który jest taki sam jak powyżej; {[30] } jest trzecim deskryptorem pliku przypisanym domyślnie do procesów uniksowych (po stdin i stdout)

  • (./write_to_file.o /dev/fd/5) 5> some_file, co oznacza " użyj szóstego deskryptora pliku i przekieruj go do some_file"

W przypadku, gdy nie jest jasne, używamy uniksowego potoku zamiast rzeczywistego pliku (wszystko jest plikiem w Unix przecież). Możemy robić różne fantazyjne rzeczy za pomocą tego potoku: zapisywać go do pliku lub zapisywać do nazwanego potoku i udostępniać go między różnymi procesami.


Teraz stwórzmy nazwaną rurę:

mkfifo my_pipe

Jeśli wpiszeszls -l teraz zobaczysz:

total 32
prw-r--r--  1 pooriaazimi  staff     0 Jul 15 09:12 my_pipe
-rw-r--r--  1 pooriaazimi  staff   336 Jul 15 08:29 write_to_file.c
-rwxr-xr-x  1 pooriaazimi  staff  8832 Jul 15 08:34 write_to_file.o

Zwróć uwagę na p na początku drugiej linii. Oznacza to, że my_pipe jest (nazwaną) rurą.

A teraz określ, co chcemy zrobić z naszą rurą:

gzip -c < my_pipe > out.gz &

To znaczy: gzip to, co umieściłem wewnątrz {[39] } i zapisz wyniki w out.gz. & na końcu prosi powłokę o uruchomienie tego polecenia w tle. Dostaniesz coś w stylu [1] 10449 i kontrola wróci do terminala.

Następnie, po prostu przekieruj wyjście naszego programu C do tej rury:

(./write_to_file.o /dev/fd/5) 5> my_pipe

Lub

./write_to_file.o my_pipe

Dostaniesz

[1]+  Done                    gzip -c < my_pipe > out.gz

Co oznacza, że komenda gzip została zakończona.

Teraz zrób jeszcze jedno ls -l:

total 40
prw-r--r--  1 pooriaazimi  staff     0 Jul 15 09:14 my_pipe
-rw-r--r--  1 pooriaazimi  staff    32 Jul 15 09:14 out.gz
-rw-r--r--  1 pooriaazimi  staff   336 Jul 15 08:29 write_to_file.c
-rwxr-xr-x  1 pooriaazimi  staff  8832 Jul 15 08:34 write_to_file.o

Udało nam się gzip SMS!

Wykonaj gzip -d out.gz aby zdekompresować ten plik gzip ed. Zostanie on usunięty i utworzony nowy plik (out). cat out dostaje nas:

some text...
Tego się spodziewaliśmy.

Nie zapomnij wyjąć rury rm my_pipe!


Teraz wracamy do PhantomJS.

Jest to prosty skrypt PhantomJS (render.coffee, napisany w CoffeeScript), który pobiera dwa argumenty: adres URL i nazwę pliku. Ładuje adres URL, renderuje go i zapisuje do podanego pliku nazwa:

system = require 'system'

renderUrlToFile = (url, file, callback) ->
  page = require('webpage').create()
  page.viewportSize = { width: 1024, height : 800 }
  page.settings.userAgent = 'Phantom.js bot'

  page.open url, (status) ->
    if status isnt 'success'
      console.log "Unable to render '#{url}'"
    else
      page.render file

    delete page
    callback url, file


url         = system.args[1]
file_name   = system.args[2]

console.log "Will render to #{file_name}"
renderUrlToFile "http://#{url}", file_name, (url, file) ->
  console.log "Rendered '#{url}' to '#{file}'"
  phantom.exit()

Teraz wpisz phantomjs render.coffee news.ycombinator.com hn.png W Terminalu, aby renderować pierwszą stronę Wiadomości hakerskich do pliku hn.png. Działa zgodnie z oczekiwaniami. Tak jak phantomjs render.coffee news.ycombinator.com hn.pdf.

Powtórzmy to, co zrobiliśmy wcześniej z naszym programem C:]}
(phantomjs render.coffee news.ycombinator.com /dev/fd/5) 5> hn.pdf
To nie działa... : (Dlaczego? Ponieważ, jak stwierdzono w instrukcji PhantomJS :

Render (nazwa pliku)

Renderuje stronę internetową do bufora obrazu i zapisuje ją jako określony plik.

Obecnie format wyjściowy jest automatycznie ustawiany na podstawie pliku przedłużenie. Obsługiwane formaty to PNG, JPEG i PDF.

Nie udaje się, po prostu dlatego, że ani /dev/fd/2, ani /dev/stdout nie kończą się na .PNG, itd.

Ale bez strachu, nazwane rury mogą Ci pomóc!

Utwórz inną nazwę rury, ale tym razem użyj rozszerzenia .pdf:

mkfifo my_pipe.pdf

Teraz powiedz to po prostu cat its inout to hn.pdf:

cat < my_pipe.pdf > hn.pdf &

Następnie uruchom:

phantomjs render.coffee news.ycombinator.com my_pipe.pdf 

I oto piękna hn.pdf!

Oczywiście chcesz zrobić coś bardziej wyrafinowanego, co po prostu catw wyjściu, ale jestem pewien, że teraz jest jasne, co powinieneś zrobić:)


TL; DR:

  1. Utwórz nazwaną rurę, używając ".rozszerzenie pliku pdf " (tak aby PhantomJS myślał, że jest to plik PDF):

    mkfifo my_pipe.pdf
    
  2. Rób co chcesz z zawartością pliku, na przykład:

    cat < my_pipe.pdf > hn.pdf
    

    Które po prostu catS to do hn.pdf

  3. W PhantomJS render do tego pliku / rury.

  4. Później powinieneś usunąć rurę:

    rm my_pipe.pdf
    
 19
Author: Pooria Azimi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-28 00:35:24

Nie wiem, czy to rozwiąże twój problem, ale możesz również sprawdzić nową metodę renderBase64() dodaną do PhantomJS 1.6: https://github.com/ariya/phantomjs/blob/master/src/webpage.cpp#L623

Niestety, funkcja nie jest jeszcze udokumentowana na wiki: /

 2
Author: NiKo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-15 09:07:24