"Fossies" - the Fresh Open Source Software Archive

Member "cups-filters-1.25.12/filter/urftopdf.cpp" (12 Nov 2019, 15350 Bytes) of package /linux/misc/cups-filters-1.25.12.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "urftopdf.cpp" see the Fossies "Dox" file reference documentation.

    1 /**
    2  * This program is free software: you can redistribute it and/or modify
    3  *  it under the terms of the GNU General Public License as published by
    4  *  the Free Software Foundation, either version 3 of the License, or
    5  *  (at your option) any later version.
    6  *
    7  *  This program is distributed in the hope that it will be useful,
    8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10  *  GNU General Public License for more details.
   11  *
   12  *  You should have received a copy of the GNU General Public License
   13  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
   14  *
   15  * @brief Decode URF to a PDF file
   16  * @file urftopdf.cpp
   17  * @author Neil 'Superna' Armstrong <superna9999@gmail.com> (C) 2010
   18  * @author Tobias Hoffmann <smilingthax@gmail.com> (c) 2012
   19  */
   20 
   21 #include <sys/types.h>
   22 #include <sys/stat.h>
   23 #include <fcntl.h>
   24 #include <stdio.h>
   25 #include <stdint.h>
   26 #include <unistd.h>
   27 #include <stdlib.h>
   28 #include <string.h>
   29 #include <limits>
   30 #include <errno.h>
   31 
   32 #include <arpa/inet.h>   // ntohl
   33 
   34 #include <vector>
   35 #include <qpdf/QPDF.hh>
   36 #include <qpdf/QPDFWriter.hh>
   37 #include <qpdf/QUtil.hh>
   38 
   39 #include <qpdf/Pl_Flate.hh>
   40 #include <qpdf/Pl_Buffer.hh>
   41 
   42 #include "unirast.h"
   43 
   44 #define DEFAULT_PDF_UNIT 72   // 1/72 inch
   45 
   46 #define PROGRAM "urftopdf"
   47 
   48 #ifdef URF_DEBUG
   49 #define dprintf(format, ...) fprintf(stderr, "DEBUG: (" PROGRAM ") " format, __VA_ARGS__)
   50 #else
   51 #define dprintf(format, ...)
   52 #endif
   53 
   54 #define iprintf(format, ...) fprintf(stderr, "INFO: (" PROGRAM ") " format, __VA_ARGS__)
   55 
   56 void die(const char * str)
   57 {
   58     fprintf(stderr, "CRIT: (" PROGRAM ") die(%s) [%s]\n", str, strerror(errno));
   59     exit(1);
   60 }
   61 
   62 //------------- PDF ---------------
   63 
   64 struct pdf_info
   65 {
   66     pdf_info() 
   67       : pagecount(0),
   68         width(0),height(0),
   69         pixel_bytes(0),line_bytes(0),
   70         bpp(0),
   71         page_width(0),page_height(0)
   72     {
   73     }
   74 
   75     QPDF pdf;
   76     QPDFObjectHandle page;
   77     unsigned pagecount;
   78     unsigned width;
   79     unsigned height;
   80     unsigned pixel_bytes;
   81     unsigned line_bytes;
   82     unsigned bpp;
   83     PointerHolder<Buffer> page_data;
   84     double page_width,page_height;
   85 };
   86 
   87 int create_pdf_file(struct pdf_info * info, unsigned pagecount)
   88 {
   89     try {
   90         info->pdf.emptyPDF();
   91     } catch (...) {
   92         return 1;
   93     }
   94 
   95     info->pagecount = pagecount;
   96 
   97     return 0;
   98 }
   99 
  100 QPDFObjectHandle makeBox(double x1, double y1, double x2, double y2)
  101 {
  102     QPDFObjectHandle ret=QPDFObjectHandle::newArray();
  103     ret.appendItem(QPDFObjectHandle::newReal(x1));
  104     ret.appendItem(QPDFObjectHandle::newReal(y1));
  105     ret.appendItem(QPDFObjectHandle::newReal(x2));
  106     ret.appendItem(QPDFObjectHandle::newReal(y2));
  107     return ret;
  108 }
  109 
  110 enum ColorSpace {
  111     DEVICE_GRAY,
  112     DEVICE_RGB,
  113     DEVICE_CMYK
  114 };
  115 
  116 #define PRE_COMPRESS
  117 /* or temporarily store images?
  118     if(cupsTempFile2(tempfile_name, 255) == NULL) die("Unable to create a temporary pdf file");
  119     iprintf("Created temporary file '%s'\n", tempfile_name);
  120 */
  121 
  122 QPDFObjectHandle makeImage(QPDF &pdf, PointerHolder<Buffer> page_data, unsigned width, unsigned height, ColorSpace cs, unsigned bpc)
  123 {
  124     QPDFObjectHandle ret = QPDFObjectHandle::newStream(&pdf);
  125 
  126     std::map<std::string,QPDFObjectHandle> dict;
  127 
  128     dict["/Type"]=QPDFObjectHandle::newName("/XObject");
  129     dict["/Subtype"]=QPDFObjectHandle::newName("/Image");
  130     dict["/Width"]=QPDFObjectHandle::newInteger(width);
  131     dict["/Height"]=QPDFObjectHandle::newInteger(height);
  132     dict["/BitsPerComponent"]=QPDFObjectHandle::newInteger(bpc);
  133 
  134     if (cs==DEVICE_GRAY) {
  135         dict["/ColorSpace"]=QPDFObjectHandle::newName("/DeviceGray");
  136     } else if (cs==DEVICE_RGB) {
  137         dict["/ColorSpace"]=QPDFObjectHandle::newName("/DeviceRGB");
  138     } else if (cs==DEVICE_CMYK) {
  139         dict["/ColorSpace"]=QPDFObjectHandle::newName("/DeviceCMYK");
  140     } else {
  141         return QPDFObjectHandle();
  142     }
  143 
  144     ret.replaceDict(QPDFObjectHandle::newDictionary(dict));
  145 
  146 #ifdef PRE_COMPRESS
  147     // we deliver already compressed content (instead of letting QPDFWriter do it), to avoid using excessive memory
  148     Pl_Buffer psink("psink");
  149     Pl_Flate pflate("pflate",&psink,Pl_Flate::a_deflate);
  150     
  151     pflate.write(page_data->getBuffer(),page_data->getSize());
  152     pflate.finish();
  153 
  154 //    /Filter /FlateDecode
  155 //    /DecodeParms  [<</Predictor 1 /Colors 1[3] /BitsPerComponent $bits /Columns $x>>]  ??
  156     ret.replaceStreamData(PointerHolder<Buffer>(psink.getBuffer()),
  157                           QPDFObjectHandle::newName("/FlateDecode"),QPDFObjectHandle::newNull());
  158 #else
  159     ret.replaceStreamData(page_data,QPDFObjectHandle::newNull(),QPDFObjectHandle::newNull());
  160 #endif
  161 
  162     return ret;
  163 }
  164 
  165 void finish_page(struct pdf_info * info)
  166 {
  167     //Finish previous Page
  168     if(!info->page_data.getPointer())
  169         return;
  170 
  171     QPDFObjectHandle image = makeImage(info->pdf, info->page_data, info->width, info->height, DEVICE_RGB, 8);
  172     if(!image.isInitialized()) die("Unable to load image data");
  173 
  174     // add it
  175     info->page.getKey("/Resources").getKey("/XObject").replaceKey("/I",image);
  176 
  177     // draw it
  178     std::string content;
  179     content.append(QUtil::double_to_string(info->page_width) + " 0 0 " + 
  180                    QUtil::double_to_string(info->page_height) + " 0 0 cm\n");
  181     content.append("/I Do\n");
  182     info->page.getKey("/Contents").replaceStreamData(content,QPDFObjectHandle::newNull(),QPDFObjectHandle::newNull());
  183 
  184     // bookkeeping
  185     info->page_data = PointerHolder<Buffer>();
  186 }
  187 
  188 int add_pdf_page(struct pdf_info * info, int pagen, unsigned width, unsigned height, int bpp, unsigned dpi)
  189 {
  190     try {
  191         finish_page(info); // any active
  192 
  193         info->width = width;
  194         info->height = height;
  195         info->pixel_bytes = bpp/8;
  196         info->line_bytes = (width*info->pixel_bytes);
  197         info->bpp = bpp;
  198     
  199         if (info->height > (std::numeric_limits<unsigned>::max() / info->line_bytes)) {
  200             die("Page too big");
  201         }
  202         info->page_data = PointerHolder<Buffer>(new Buffer(info->line_bytes*info->height));
  203 
  204         QPDFObjectHandle page = QPDFObjectHandle::parse(
  205             "<<"
  206             "  /Type /Page"
  207             "  /Resources <<"
  208             "    /XObject << >> "
  209             "  >>"
  210             "  /MediaBox null "
  211             "  /Contents null "
  212             ">>");
  213         page.replaceKey("/Contents",QPDFObjectHandle::newStream(&info->pdf)); // data will be provided later
  214     
  215         // Convert to pdf units
  216         info->page_width=((double)info->width/dpi)*DEFAULT_PDF_UNIT;
  217         info->page_height=((double)info->height/dpi)*DEFAULT_PDF_UNIT;
  218         page.replaceKey("/MediaBox",makeBox(0,0,info->page_width,info->page_height));
  219     
  220         info->page = info->pdf.makeIndirectObject(page); // we want to keep a reference
  221         info->pdf.addPage(info->page, false);
  222     } catch (std::bad_alloc &ex) {
  223         die("Unable to allocate page data");
  224     } catch (...) {
  225         return 1;
  226     }
  227 
  228     return 0;
  229 }
  230 
  231 int close_pdf_file(struct pdf_info * info)
  232 {
  233     try {
  234         finish_page(info); // any active
  235 
  236         QPDFWriter output(info->pdf,NULL);
  237         output.write();
  238     } catch (...) {
  239         return 1;
  240     }
  241 
  242     return 0;
  243 }
  244 
  245 void pdf_set_line(struct pdf_info * info, unsigned line_n, uint8_t line[])
  246 {
  247     dprintf("pdf_set_line(%d)\n", line_n);
  248 
  249     if(line_n > info->height)
  250     {
  251         dprintf("Bad line %d\n", line_n);
  252         return;
  253     }
  254   
  255     memcpy((info->page_data->getBuffer()+(line_n*info->line_bytes)), line, info->line_bytes);
  256 }
  257 
  258 // Data are in network endianness
  259 struct urf_file_header {
  260     char unirast[8];
  261     uint32_t page_count;
  262 } __attribute__((__packed__));
  263 
  264 struct urf_page_header {
  265     uint8_t bpp;
  266     uint8_t colorspace;
  267     uint8_t duplex;
  268     uint8_t quality;
  269     uint32_t unknown0;
  270     uint32_t unknown1;
  271     uint32_t width;
  272     uint32_t height;
  273     uint32_t dot_per_inch;
  274     uint32_t unknown2;
  275     uint32_t unknown3;
  276 } __attribute__((__packed__));
  277 
  278 int decode_raster(int fd, unsigned width, unsigned height, int bpp, struct pdf_info * info)
  279 {
  280     // We should be at raster start
  281     int i, j;
  282     unsigned cur_line = 0;
  283     unsigned pos = 0;
  284     uint8_t line_repeat_byte = 0;
  285     unsigned line_repeat = 0;
  286     int8_t packbit_code = 0;
  287     int pixel_size = (bpp/8);
  288     std::vector<uint8_t> pixel_container;
  289     std::vector<uint8_t> line_container;
  290 
  291     if (width > (std::numeric_limits<unsigned>::max() / pixel_size)) {
  292         die("Line too big");
  293     }
  294     try {
  295         pixel_container.resize(pixel_size);
  296         line_container.resize(pixel_size*width);
  297     } catch (...) {
  298         die("Unable to allocate temporary storage");
  299     }
  300 
  301     do
  302     {
  303         if(read(fd, &line_repeat_byte, 1) < 1)
  304         {
  305             dprintf("l%06d : line_repeat EOF at %lu\n", cur_line, lseek(fd, 0, SEEK_CUR));
  306             return 1;
  307         }
  308 
  309         line_repeat = (unsigned)line_repeat_byte + 1;
  310 
  311         dprintf("l%06d : next actions for %d lines\n", cur_line, line_repeat);
  312 
  313         // Start of line
  314         pos = 0;
  315 
  316         do
  317         {
  318             if(read(fd, &packbit_code, 1) < 1)
  319             {
  320                 dprintf("p%06dl%06d : packbit_code EOF at %lu\n", pos, cur_line, lseek(fd, 0, SEEK_CUR));
  321                 return 1;
  322             }
  323 
  324             dprintf("p%06dl%06d: Raster code %02X='%d'.\n", pos, cur_line, (uint8_t)packbit_code, packbit_code);
  325 
  326             if(packbit_code == -128)
  327             {
  328                 dprintf("\tp%06dl%06d : blank rest of line.\n", pos, cur_line);
  329                 memset((&line_container[pos*pixel_size]), 0xFF, (pixel_size*(width-pos)));
  330                 pos = width;
  331                 break;
  332             }
  333             else if(packbit_code >= 0 && packbit_code <= 127)
  334             {
  335                 int n = (packbit_code+1);
  336 
  337                 //Read pixel
  338                 if(read(fd, &pixel_container[0], pixel_size) < pixel_size)
  339                 {
  340                     dprintf("p%06dl%06d : pixel repeat EOF at %lu\n", pos, cur_line, lseek(fd, 0, SEEK_CUR));
  341                     return 1;
  342                 }
  343 
  344                 dprintf("\tp%06dl%06d : Repeat pixel '", pos, cur_line);
  345                 for(j = 0 ; j < pixel_size ; ++j)
  346                     dprintf("%02X ", pixel_container[j]);
  347                 dprintf("' for %d times.\n", n);
  348 
  349                 for(i = 0 ; i < n ; ++i)
  350                 {
  351                     //for(j = pixel_size-1 ; j >= 0 ; --j)
  352                     for(j = 0 ; j < pixel_size ; ++j)
  353                         line_container[pixel_size*pos + j] = pixel_container[j];
  354                     ++pos;
  355                     if(pos >= width)
  356                         break;
  357                 }
  358 
  359                 if(i < n && pos >= width)
  360                 {
  361                     dprintf("\tp%06dl%06d : Forced end of line for pixel repeat.\n", pos, cur_line);
  362                 }
  363                 
  364                 if(pos >= width)
  365                     break;
  366             }
  367             else if(packbit_code > -128 && packbit_code < 0)
  368             {
  369                 int n = (-(int)packbit_code)+1;
  370 
  371                 dprintf("\tp%06dl%06d : Copy %d verbatim pixels.\n", pos, cur_line, n);
  372 
  373                 for(i = 0 ; i < n ; ++i)
  374                 {
  375                     if(read(fd, &pixel_container[0], pixel_size) < pixel_size)
  376                     {
  377                         dprintf("p%06dl%06d : literal_pixel EOF at %lu\n", pos, cur_line, lseek(fd, 0, SEEK_CUR));
  378                         return 1;
  379                     }
  380                     //Invert pixels, should be programmable
  381                     for(j = 0 ; j < pixel_size ; ++j)
  382                         line_container[pixel_size*pos + j] = pixel_container[j];
  383                     ++pos;
  384                     if(pos >= width)
  385                         break;
  386                 }
  387 
  388                 if(i < n && pos >= width)
  389                 {
  390                     dprintf("\tp%06dl%06d : Forced end of line for pixel copy.\n", pos, cur_line);
  391                 }
  392                 
  393                 if(pos >= width)
  394                     break;
  395             }
  396         }
  397         while(pos < width);
  398 
  399         dprintf("\tl%06d : End Of line, drawing %d times.\n", cur_line, line_repeat);
  400 
  401         // write lines
  402         for(i = 0 ; i < (int)line_repeat ; ++i)
  403         {
  404             pdf_set_line(info, cur_line, &line_container[0]);
  405             ++cur_line;
  406         }
  407     }
  408     while(cur_line < height);
  409 
  410     return 0;
  411 }
  412 
  413 int main(int argc, char **argv)
  414 {
  415     int fd, page;
  416     struct urf_file_header head, head_orig;
  417     struct urf_page_header page_header, page_header_orig;
  418     struct pdf_info pdf;
  419 
  420     FILE * input = NULL;
  421 
  422     if(argc < 6)
  423     {
  424         fprintf(stderr, "Usage: %s <job> <user> <job name> <copies> <option> [file]\n", argv[0]);
  425         return 1;
  426     }
  427 
  428     if(argc > 6)
  429     {
  430         input = fopen(argv[6], "rb");
  431         if(input == NULL) die("Unable to open unirast file");
  432     }
  433     else
  434         input = stdin;
  435 
  436     // Get fd from file
  437     fd = fileno(input);
  438 
  439     if(read(fd, &head_orig, sizeof(head)) == -1) die("Unable to read file header");
  440 
  441     //Transform
  442     memcpy(head.unirast, head_orig.unirast, sizeof(head.unirast));
  443     head.page_count = ntohl(head_orig.page_count);
  444 
  445     if(head.unirast[7])
  446         head.unirast[7] = 0;
  447 
  448     if(strncmp(head.unirast, "UNIRAST", 7) != 0) die("Bad File Header");
  449 
  450     iprintf("%s file, with %d page(s).\n", head.unirast, head.page_count);
  451 
  452     if(create_pdf_file(&pdf, head.page_count) != 0) die("Unable to create PDF file");
  453 
  454     for(page = 0 ; page < (int)head.page_count ; ++page)
  455     {
  456         if(read(fd, &page_header_orig, sizeof(page_header_orig)) == -1) die("Unable to read page header");
  457 
  458         //Transform
  459         page_header.bpp = page_header_orig.bpp;
  460         page_header.colorspace = page_header_orig.colorspace;
  461         page_header.duplex = page_header_orig.duplex;
  462         page_header.quality = page_header_orig.quality;
  463         page_header.unknown0 = 0;
  464         page_header.unknown1 = 0;
  465         page_header.width = ntohl(page_header_orig.width);
  466         page_header.height = ntohl(page_header_orig.height);
  467         page_header.dot_per_inch = ntohl(page_header_orig.dot_per_inch);
  468         page_header.unknown2 = 0;
  469         page_header.unknown3 = 0;
  470 
  471         iprintf("Page %d :\n", page);
  472         iprintf("Bits Per Pixel : %d\n", page_header.bpp);
  473         iprintf("Colorspace : %d\n", page_header.colorspace);
  474         iprintf("Duplex Mode : %d\n", page_header.duplex);
  475         iprintf("Quality : %d\n", page_header.quality);
  476         iprintf("Size : %dx%d pixels\n", page_header.width, page_header.height);
  477         iprintf("Dots per Inches : %d\n", page_header.dot_per_inch);
  478 
  479         if(page_header.colorspace != UNIRAST_COLOR_SPACE_SRGB_24BIT_1)
  480         {
  481             die("Invalid ColorSpace, only RGB 24BIT type 1 is supported");
  482         }
  483         
  484         if(page_header.bpp != UNIRAST_BPP_24BIT)
  485         {
  486             die("Invalid Bit Per Pixel value, only 24bit is supported");
  487         }
  488 
  489         if(add_pdf_page(&pdf, page, page_header.width, page_header.height, page_header.bpp, page_header.dot_per_inch) != 0) die("Unable to create PDF file");
  490 
  491         if(decode_raster(fd, page_header.width, page_header.height, page_header.bpp, &pdf) != 0)
  492             die("Failed to decode Page");
  493     }
  494 
  495     close_pdf_file(&pdf); // will output to stdout
  496 
  497     return 0;
  498 }