{"id":409,"date":"2016-02-03T20:21:41","date_gmt":"2016-02-03T20:21:41","guid":{"rendered":"http:\/\/www.colorwave.it\/blog\/?p=409"},"modified":"2016-02-03T21:11:56","modified_gmt":"2016-02-03T21:11:56","slug":"la-stampa-di-un-documento-di-colibri","status":"publish","type":"post","link":"https:\/\/www.colorwave.it\/blog\/uncategorized\/la-stampa-di-un-documento-di-colibri\/admin\/2016\/02\/","title":{"rendered":"La stampa di un documento di Colibri"},"content":{"rendered":"<p>I processi di stampa in Colibri sono gestiti attraverso un insieme di classi:<\/p>\n<p><strong>PRINTER_DRIVER:<\/strong> classe base per la strutturazione\u00a0dei driver delle stampanti.<\/p>\n<p>La classe mette a disposizione un insieme di metodi e funzioni per la configurazione dell&#8217;hardware. Da questa derivano tutti i driver delle stampanti; ad esempio la\u00a0PRINTER_DRIVER_XF640 che permette di comunicare con la stampante Roland XF640.<\/p>\n<p><strong>PRINTER:<\/strong> questa classe \u00e8 l&#8217;interfaccia standard\u00a0fra l&#8217;applicazione e le stampanti; In pratica un processo di stampa avviene sempre accedendo ad una istanza di PRINTER, lanciando un thread attraverso il metodo PRINTER::StartThread(&#8230;), dopo avere configurato la stessa.<\/p>\n<p>Configurare un oggetto PRINTER\u00a0significa assegnargli un&#8217;oggetto derivato da PRINTER_DRIVER ( ad esempio un&#8217;istanza di\u00a0PRINTER_DRIVER_XF640) ed una configurazione (un oggetto\u00a0PRINTER_CONFIGURATION).<\/p>\n<p><strong>PRINTER_CONFIGURATION:\u00a0<\/strong>contiene i parametri di configurazione dell&#8217;hardware, oltre all&#8217;id di un driver.<\/p>\n<p>Tutto il processo di creazione ed inizializzazione, pur complesso, \u00e8 svolto da\u00a0un una funzione statica, PRINTER::UseConfig(config_name), che riceve in ingresso un nome di configurazione, estrae dal database la stessa, ricava l&#8217;idi del driver, lo genera e assegna a PRINTER, \u00a0rimanda un oggetto PRINTER pronto per essere utilizzato.<\/p>\n<p>Per effettuare la stampa occorrer\u00e0 in seguito\u00a0chiamare la funzione PRINTER::StartThread(..) che attiva un thread di stampa.<\/p>\n<p><span style=\"color: #0000ff;\"><em><span style=\"color: #3366ff;\">In questo post descriveremo \u00a0come il thread di stampa lanciato comunica con il documento da stampare, richiedendo le linee di pixel (separazioni).<\/span><\/em><\/span><\/p>\n<p><!--nextpage-->I documenti stampabili in Colibri devono possedere l&#8217;interfaccia\u00a0OPERATION_CALL. In genere derivano da una classe DOCUMENT, la quale possiede questa interfaccia. Come vedremo, la definizione che stiamo dando \u00e8 coerente con l&#8217;esigenza di mantenere il massimo grado di astrazione: un documento pu\u00f2 essere qualunque cosa in grado di essere riprodotto su una stampante raster (un&#8217;immagine, una collezione di elementi vettoriali organizzati su un piano, un qualunque oggetto visualizzato sul monitor, non necessariamente raster); quindi, un documento stampabile \u00e8 un qualunque oggetto che, dato un numero di linea \u00e8 in grado di rimandare un vettore di byte contenente le separazioni in inks della linea). Le separazioni ovviamente faranno riferimento ai colori dell&#8217;oggetto da stampare, e saranno calcolate internamente all&#8217;oggetto in funzione di un profilo di stampa.<\/p>\n<h3>Lancio del thread di stampa<\/h3>\n<pre class=\"font-size:12line-height:15 lang:default mark:1 decode:true\">bool PRINTER::StartThread(OPERATION_CALL *obj,float dx_mm, float dy_mm, float resx, float resy,RES_UNMIS res_um) \r\n<\/pre>\n<p>La funzione StartThread della PRINTER ha come parametri un documento (obj) le\u00a0dimensioni di stampa in mm (dx_mm e dy_mm) le risoluzioni verticali e orizzontali del documento (non necessariamente uguali a quelle della stampante..) e l&#8217;unit\u00e0 di misura della risoluzione in dpi o ppm.<\/p>\n<p>Notare che, come gi\u00e0 scritto, il documento \u00e8 definito attraverso l&#8217;interfaccia<a href=\"https:\/\/www.colorwave.it\/blog\/?p=265\"> OPERATION_CALL<\/a>, senza alcun riferimento al suo contenuto, quale la presenza di immagini o altre caratteristiche.<\/p>\n<p>All&#8217;interno del thread, utilizzando queste informazioni verr\u00e0 calcolata la dimensione in pixel del documento da riprodurre, quindi saranno richiesti al documento i dati da stampare mandando\u00a0una sequenza di messaggi e parametri opportuni. E&#8217; evidente che la classe di definizione del documento dovr\u00e0 intercettare questi messaggi e costruire le informazioni in risposta;<\/p>\n<p>Di seguito mostreremo\u00a0quali comandi e dati sono richiesti dal thread di stampa ed il modo in cui dovranno essere ritornate le informazioni richieste. Per farlo useremo la classe documento\u00a0PRINTER_OUTPUT<\/p>\n<p><!--nextpage-->Per comprendere come \u00e8 definita la comunicazione fra il thread di stampa e un documento PRINTER_OUTPUT, ricordiamo che deriva dalla classe DOCUMENT dalla quale eredita l&#8217;interfaccia OPERATION_CALL. Quindi, <a href=\"https:\/\/www.colorwave.it\/blog\/?p=265\">come gi\u00e0 descritto in questo blog<\/a>\u00a0il costruttore di PRINTER_OUTPUT conterr\u00e0 la dichiarazione della funzione di interfaccia nel blocco\u00a0__declare_slots di inizializzazione, di seguito integralmente riportato<\/p>\n<pre class=\"lang:default mark:2,8 decode:true\">___declare_slots\r\n    { OP_FILTER, PRINTER_INTERFACE},\r\n__end__declare_slots\r\n\r\nPRINTER_OUTPUT::PRINTER_OUTPUT(void)\r\n{\r\n\tINIT_OBJ\r\n\tACTIVATE_OBJECT_SLOTS\r\n}\r\n\r\n<\/pre>\n<p>Abbiamo evidenziato due righe nel frammento di codice: la prima dichiara\u00a0uno slot PRINTER_INTERFACE che riceve i messaggi di codice OP_FILTER; la seconda linea, dichiarata nel costruttore di qualunque classe con interfaccia OPERATION_CALL, \u00e8 una macro che registra gli slots definiti nel blocco __declare_slots..__end_declare_slots (in questo caso solo PRINTER_INTERFACE)<\/p>\n<p>Riportiamo di seguito il codice relativo allo slot che intercetta i messaggi mandati dal thread di stampa:<\/p>\n<pre class=\"lang:default decode:true\" title=\"Lo slot di comunicazione con il thread di stampa\">__slot(PRINTER_INTERFACE)\r\n\t\r\n\tif (__function_is(L\"GET_SEPLINES\")) {\r\n\t\tint y=*A_INT(0);\r\n\t\tif (y&gt;=0 &amp;&amp; y&lt;STR-&gt;info.area.dy) {\r\n\t\t\tif (GET_SEPARATIONS_LINE(STR,y)) \r\n\t\t\t\t_A(3)=STR-&gt;sep;\r\n\t\t}\r\n\t}\r\n\telse\r\n\tif (__function_is(L\"PREPARE_PRINTING\")) {\r\n\r\n\t\tALLOC_MEM\t\t\/\/ alloca la memoria necessaria per le separazioni\r\n\t\tint dx=*A_INT(1);\r\n\t\tint dy=*A_INT(2);\r\n\t}\r\n\telse\r\n\t\/\/ la stampa \u00e8 stata chiusa, liberare la memoria..\r\n\tif (__function_is(L\"END_PRINTING\")) {\r\n\r\n\t\tFREE_MEM\t\r\n\r\n\t\tint dx=*A_INT(1);\r\n\t\tint dy=*A_INT(2);\r\n\t\tClock *t=(Clock *)_A(3);\r\n\t}\r\n__end_slot\r\n<\/pre>\n<p>La macro <em>__function_is effettua\u00a0<\/em>un test sul comando ricevuto ed eventualmente lo esegue; Il thread di stampa spedisce un insieme di comandi:<em><strong>PREPARE_PRINTING:<\/strong><\/em> comunica al documento che \u00e8 pronto per iniziare la stampa<\/p>\n<p><em><strong>PREPARE_PRINTING<\/strong><\/em>: comunica al documento che \u00e8 pronto per iniziare la stampa. In risposta il documento alloca la memoria necessari (ALLOC_MEM). il thread ha rimandato anche alcuni \u00a0parametri, quali le dimensioni in pixel della pagina in stampa che ospiter\u00e0 il documento. Li abbiamo estratti \u00a0ma non li abbiamo usati perch\u00e8 non necessari all&#8217;uso interno alla classe<\/p>\n<p><em><strong>GET_SEPLINES:\u00a0<\/strong><\/em>Richiede al documento la produzione delle linee delle separazioni, una per ciascun inchiostro definito nel profilo della stampante.<\/p>\n<pre class=\"lang:default decode:true\" title=\"Lo slot di comunicazione con il thread di stampa\">if (__function_is(L\"GET_SEPLINES\")) {\r\n\t\tint y=*A_INT(0);\r\n\t\tif (y&gt;=0 &amp;&amp; y&lt;STR-&gt;info.area.dy) {\r\n\t\t\tif (GET_SEPARATIONS_LINE(STR,y)) \r\n\t\t\t\t_A(3)=STR-&gt;sep;\r\n\t\t}\r\n\t}\r\n<\/pre>\n<p>Senza entrare in particolari inutili al contesto descritto, osserviamo che in risposta al comando GET_SEPLINES, viene estratto il numero di linea raster richiesto, quindi una volta testato che la linea appartiene all&#8217;intervallo del documento, richiama una funzione definita nel modulo (GET_SEPARATIONS_LINE) e, se l&#8217;operazione \u00e8 riuscita, trasmette nello stack dei parametri il puntatore alla variabile STR-&gt;sep, cio\u00e8 il vettore delle linee di pixel delle separazioni. La struttura STR-&gt;sep \u00e8 proprio quella che deve essere ritornata al thread per la stampa della linea dell&#8217;oggetto. fra poco la descriveremo in dettaglio, poich\u00e8 sar\u00e0 identica a quella che dovr\u00e0 essere rimandata da qualunque documento stampabile, indipendentemente dal modo di produzione interno alla classe.<\/p>\n<p><em><strong>END_PRINTING:<\/strong> <\/em>Con questo comando il thread comunica alla classe documento che \u00a0ha terminato la stampa; in risposta il documento in questo caso libera la memoria allocata per il processo. Come al solito il thread manda alcune altre informazioni, non strettamente necessarie all&#8217;esecuzione del comando. In questo caso la classe estrae le dimensioni dell&#8217;area stampata e un&#8217;istanza della classe orologio che pu\u00f2 essere usata per ricavare informazioni sui tempi di stampa (ma non ne faremo alcun uso in questo caso..)<\/p>\n<p><!--nextpage-->Abbiamo esposto il metodo attraverso il quale il thread di stampa generato dalla\u00a0PRINTER dialoga con un documento da stampare e abbiamo visto che sostanzialmente tutta l&#8217;operazione avviene intercettando tre comandi da parte del documento. Uno di questi comandi richiede il ritorno di un puntatore relativo alle linee di separazione da stampare. Non siamo entrati nel merito di come questo processo avvenga nel documento (in questo caso PRINTER_OUTPUT; vedremo questo in un prossimo blog; ci interessava descrivere lo <em>scheletro<\/em>\u00a0della comunicazione. Notare che nel caso la linea di stampa richiesta non sia\u00a0valida, il codice si limita a non trasferire il puntatore alle separazioni, che per default \u00e8 nullo.<\/p>\n<h3>Il formato delle linee di separazioni rimandate..<\/h3>\n<pre class=\"lang:default range:5-6 decode:true\" title=\"Il vettore delle linee di separazione in inks\">BEGIN_STRUCT\r\n\/\/\r\n.....\r\n....\r\n\t\/\/ parametri usati in stampa\r\n\tUBYTE *sep[MAXHEADS];\t\t\/\/ linee separate passate al driver di stampa\r\n.....\r\n.....\r\n\t\r\n\/\/\t\r\n\/\/\r\nEND_STRUCT\r\n<\/pre>\n<p>Le linee di separazione sono definite in un vettore di puntatori UBYTE (convenzionalmente allocato al numero massimo di teste su una stampante); se ad esempio la stampante possiede 8 teste, saranno validi gli indici 0..7 nel vettore. se il puntatore (ad esempio STR-&gt;sep[4]) \u00e8 passato a 0, significa che il relativo colore non \u00e8 presente nella separazione\u00a0\u00a0richiesta. Se invece il puntatore \u00e8 non nullo, esso \u00e8\u00a0\u00a0una linea di byte con valori (0..255) corrispondente alle concentrazioni sui diversi pixel. in questo caso il puntatore ad esempio STR-&gt;sep[4], punta ad un vettore di lunghezza pari al numero di pixel sulla linea (la dimensione in pixel della linea raster del documento).<\/p>\n<p>Ovviamente non finisce qui: il vettore delle separazioni ricevuto sar\u00e0 trasformato all&#8217;interno del thread in dati differenti, ad esempio in bit di dithering da trasferire alla stampante (compito svolto in funzione dei parametri di configurazione della stessa). tutte le operazioni successive saranno invisibili al codice del documento (cio\u00e8 non \u00e8 necessario che il documento <em>sappia<\/em> se la stampante usa il dhithering, un retino, o quale risoluzione di stampa si sta utilizzando..<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I processi di stampa in Colibri sono gestiti attraverso un insieme di classi: PRINTER_DRIVER: classe base per la strutturazione\u00a0dei driver delle stampanti. La classe mette a disposizione un insieme di metodi e funzioni per la configurazione dell&#8217;hardware. Da questa derivano tutti i&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"footnotes":"","_jetpack_memberships_contains_paid_content":false,"jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[1],"tags":[],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9rwsf-6B","jetpack_likes_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/posts\/409"}],"collection":[{"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/comments?post=409"}],"version-history":[{"count":35,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/posts\/409\/revisions"}],"predecessor-version":[{"id":444,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/posts\/409\/revisions\/444"}],"wp:attachment":[{"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/media?parent=409"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/categories?post=409"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/tags?post=409"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}