momente şi schiţe de informatică şi matematică
To attain knowledge, write. To attain wisdom, rewrite.

Experimente cu PDF-uri, iframe şi Google Drive

Firefox | Google Drive | PDF | jQuery
2013 jul

În [1] şi [2] am demarat aplicaţia //bacmath: există o bază de date conţinând enunţuri de probleme testate de câţiva ani pentru pregătirea examenului de bacalaureat la "matematică"; utilizatorului îi este prezentat un formular prin care va putea obţine în browserul său, enunţurile corespunzătoare unei anumite "variante", "subiect", sau "tip" de problemă.

Trebuie să subliniem că enunţurile respective nu sunt obiecte grafice (dintre cele specifice formatului PDF, de exemplu) şi nici imagini - ci sunt de natura textului obişnuit (expresiile matematice fiind scrise conform limbajului LaTeX), fiind astfel uşor de editat, de transferat, sau de analizat de către vreun program de conversie (între LaTeX şi alte limbaje de marcare matematică).

Este de dorit ca baza de date să conţină din start problemele din setul de 100 "variante de subiecte de bacalaureat" creat în 2009 de către specialişti în evaluare şi examinare; acest set poate fi obţinut ca fişier PDF, de la diverse site-uri de tip "furnizor de documente".

Dar pentru aceste PDF-uri nu avem cum să convertim formatul PDF la formatul textual obişnuit (mai ales, în cazul expresiilor matematice). Astfel că rămâne să edităm manual, enunţurile de înscris în baza de date; în [2] am prezentat o interfaţă care uşurează această muncă: utilizatorul autentificat are într-o aceeaşi fereastră a browserului său, atât un element <iframe> care expune PDF-ul corespunzător unei anumite variante, cât şi un <textarea> în care el poate scrie enunţurile pe măsură ce le citeşte din prima casetă (plus un buton de salvare finală, în baza de date).

În [2] am ilustrat faptul că dacă PDF-ul respectiv nu încorporează un anumit font utilizat de autor, atunci se poate întâmpla ca vizualizatorul folosit să nu-l redea corect (fontul respectiv nefiind instalat pe calculatorul gazdă şi negăsind un font "asemănător").

Este drept însă că pentru redarea într-un <iframe> nu se foloseşte "Document Viewer"-ul uzual de pe calculatorul utilizatorului (program extern browserului), ci se foloseşte eventual un vizualizator încorporat în browser - iar acesta poate reda corect (cu excepţii, de la un browser la altul) şi acel PDF pe care vizualizatorul extern îl redă trunchiat.

Din aceste motive, am preferat angajarea unui PDF - "Variante_Matematica_MT1_BAC_2009.pdf" (Author: Blader2k) - faţă de care nu se pune problema fonturilor, dat fiind că este compus numai din obiecte-imagine (rezultând în fond, în urma scanării unor pagini tipărite); prin urmare (teoretic), acest PDF va putea fi redat "corect" de către oricare vizualizator.

Cum este redat PDF-ul, în browser

Ar fi de văzut şi cum este redat. Pentru aceasta, să adăugăm într-o pagină HTML accesibilă din //bacmath următoarea definiţie (aici, cu un URL constituit ad-hoc):

<iframe src="http://bacmath.loc/var_015.pdf" width="700px" height="300px"></iframe>

Accesând //bacmath şi pagina respectivă din browserul Firefox, în <iframe> apare PDF-ul indicat, sub o bară de instrumente (avem aici, mărime=90%):

Firefox vizualizează PDF-urile prin biblioteca Javascript încorporată, Mozilla PDF Reader. Aici, dungile care taie echidistant pagina separă imaginile scanate (vezi în [2], fişierele "bitmap" corespunzătoare acestor imagini) şi se estompează prin mărire (acţionând "+" de pe bara de instrumente); ele nu apar în cazul unui vizualizator extern obişnuit.

Dar dacă accesăm pagina respectivă folosind alt browser, se poate ca PDF-ul respectiv să nu mai fie vizualizat; de exemplu, Opera (şi analog, Chrome) furnizează această casetă de dialog (în loc de a "afişa" PDF-ul în <iframe>):

Acest mic experiment dezvăluie încă o problemă "irezolvabilă". Putem avea un utilizator autentificat pe //bacmath - binevoitor să înscrie o nouă variantă în baza de date, folosind interfaţa descrisă mai sus (cu <iframe> şi <textarea>); dar PDF-ul mizat de această interfaţă va apărea sau nu în <iframe>, în funcţie de browserul folosit şi eventual, în funcţie de prezenţa sau absenţa anumitor plugin-uri sau extensii ale acelui browser.

Rezultă în fond că va trebui să cerem acestui utilizator să folosească browserul Firefox, pentru a accesa interfaţa de lucru vizată mai sus (caz în care - în mod sigur - PDF-ul va fi redat în <iframe>, cum tocmai am arătat).

O rezolvare bazată pe conturi Google (folosind Google Drive)

Avem şi altă soluţie, în loc de a "obliga" la Firefox pe utilizatorul deprins să zicem cu Chrome, sau cu Opera; este drept că şi aceasta, cere ceva utilizatorului: să aibă, sau să-şi creeze un cont Google - însă această cerinţă nu poate să fie decât benefică, pentru orice utilizator de Internet.

Ideea este de a stoca fişierele PDF care vor trebui deschise în <iframe>, pe "Google Drive"-ul propriu (de care beneficiez, ca posesor de cont Google), declarându-le ca fiind "publice" (accesibile oricui deţine un cont Google); apoi, setând elementul <iframe> ca în acest exemplu:

<iframe src="https://docs.google.com/file/d/0B5Rpn1ZXSEfrTnR5NEQ3Y3dkZTQ/preview" 
        width="700px" height="300px"></iframe>

asigurăm că utilizatorul care are cont Google - aproape indiferent de browserul folosit pentru a accesa //bacmath şi pagina care conţine acel <iframe> - va primi "corect" PDF-ul - de pe "Drive"-ul meu - identificat în atributul "src" (prin secvenţa de 28 caractere care precede "/preview"). "Va primi corect" PDF-ul, fiindcă în cazul fişierelor originate din Google Drive, Google implică un vizualizator propriu (analog celui încorporat în Firefox pentru PDF).

Să ne amintim ca PDF-ul pe care l-am angajat - îl redenumim "mt1_09.pdf" - conţine 100 de pagini, fiecare redând câte o "variantă" (10 probleme, grupate după "subiect"). Pentru a oferi în interfaţa vizată mai sus, câte o singură variantă (dintre cele care încă n-au fost înregistrate în baza de date //bacmath) - separăm din "mt1_09.pdf" cele 100 de pagini, folosind pdftk:

vb@vb:~/bacmath/DOC/MT1/2009$ pdftk  mt1_09.pdf  burst  output var_%03d.pdf

Rezultă fişierele "var_001.pdf", "var_002.pdf" ş.a.m.d.; specificatorul %03d ne-a permis să denumim fişierele astfel încât acestea să fie listate în ordinea crecătoare a variantelor. Am creat pe "Google Drive"-ul propriu structura de "foldere" MT1/2009/ şi am uploadat cele 100 de fişiere; apoi, am accesat "Share" pentru a seta "acces public":

Am copiat şi am salvat conţinutul casetei marcate în imaginea de mai sus, constând în cele 100 de link-uri "publice" ale fişierelor PDF. Apoi am făcut o verificare simplă: am copiat primul link şi l-am pastat în bara de adresă a browserului (înlocuind totuşi "/edit" cu "/preview"):

Constatăm că primul link din listă corespunde paginii "var_067.pdf" (şi nu variantei 1, cum speram); aceasta înseamnă că avem cele 100 de link-uri (dintre care va trebui să indicăm unul lui <iframe>), dar nu ştim cărei variante corespunde fiecare (fiind redate într-o "ordine aleatorie").

N-avem decât să ne bucurăm: avem o nouă problemă…

Ordonarea listei de link-uri de pe Google Drive

Lista de link-uri produsă de Google Drive în fereastra de dialog "Sharing settings" nu este ordonată după numele fişierelor - şi aceasta, în mod "voit": dacă vom reaccesa ulterior dialogul respectiv, vom constata o altă ordine a link-urilor (ceea ce este specific lucrului în siguranţă cu obiecte dinamice, precum "hash"-urile Perl, sau dicţionarele Python).

Prin Google Drive SDK aş fi putut obţine - şi încă "on-line", fără efort personal - o listă care explicitează link-urile, "legând" ID-ul fişierului de numele său:

    {
        "id": "0B5Rpn1ZXSEfrcndOUGRFcXByMWs",
        "title": "var_067.pdf"
    }

dar până să văd această posibilitate… m-am "gândit" imediat că pot refolosi interfaţa vizată mai sus (vezi şi [2]). Prin urmare am putut adopta imediat această soluţie de natură "muncitorească":

Faţă de interfaţa menţionată, am adăugat un element <a> "Get from..." şi acest <script>:

var gdrive = [ // Lista de link-uri din dialogul "Sharing settings" de pe Google Drive
"https://docs.google.com/file/d/0B5Rpn1ZXSEfrTnR5NEQ3Y3dkZTQ/edit", // Primul link
"https://docs.google.com/file/d/0B5Rpn1ZXSEfrUkxDUDMxSXYyZXc/edit",
// ş.a.m.d.
"https://docs.google.com/file/d/0B5Rpn1ZXSEfrZkFmVTdTQWJUUUE/edit", // al 100-lea link
];
var i = 0; // rangul link-ului curent
$(function() { // se foloseşte biblioteca jQuery
    $('#from-gdrive').click(function() { // la click pe "Get from GoogleDrive"
        $('#iframe-id').attr('src', gdrive[i]); // setează link-ul curent în iframe
        if(i < 100) i += 1; // Primul link, al doilea, ş.a.m.d.
        $(this).next().text('i = ' + i);
        return false;
    });
});

Click-ul pe "Get from GoogleDrive" înscrie în atributul "src" al elementului <iframe> link-ul următor din lista de link-uri salvată anterior şi afişează alături rangul "i" al acestuia; citesc numele fişierului ajuns astfel în <iframe> şi înscriu în <textarea> numărul variantei. Pe imaginea reprodusă mai sus se vede că primele patru link-uri din listă corespund respectiv variantelor 29, 87, 38, 15.

Este drept că a trebuit să clickez astfel şi să înscriu în casetă (cu mare atenţie), până când "i" ajunge la 100… Parcă este preferabil (şi uneori "benefic"!) să citeşti mai atent documentaţiile (în cazul de faţă - pe cea de la Google Drive SDK).

vezi Cărţile mele (de programare)

docerpro | Prev | Next