Esempio n. 1
0
// -- Compresses low color pixmap.
void 
cpaldjvu(ByteStream *ibs, GURL &urlout, const cpaldjvuopts &opts)
{
  GP<GPixmap> ginput=GPixmap::create(*ibs);
  int w = ginput->columns();
  int h = ginput->rows();
  int dpi = MAX(200, MIN(900, opts.dpi));
  int largesize = MIN(500, MAX(64, dpi));
  int smallsize = MAX(2, dpi/150);

  // Compute optimal palette and quantize input pixmap
  GP<DjVuPalette> gpal=DjVuPalette::create();
  DjVuPalette &pal=*gpal;
  GPixel bgcolor;
  int bgindex = -1;
  if (! opts.bgwhite)
    {
      bgindex = pal.compute_pixmap_palette(*ginput, opts.ncolors);
      pal.index_to_color(bgindex, bgcolor);
    }
  else
    {
      bgcolor = GPixel::WHITE;
      pal.histogram_clear();
      for (int j=0; j<h; j++)
        {
          const GPixel *p = (*ginput)[j];
          for (int i=0; i<w; i++)
            if (p[i] != GPixel::WHITE)
              pal.histogram_add(p[i], 1);
        }
      pal.compute_palette(opts.ncolors);
    }
  if (opts.verbose)
    DjVuFormatErrorUTF8( "%s\t%d\t%d\t%d",
                         ERR_MSG("cpaldjvu.quantizied"), 
                         w, h, pal.size());
  if (opts.verbose && !opts.bgwhite)
    DjVuPrintErrorUTF8("cpaldjvu: background color is #%02x%02x%02x.\n", 
                       bgcolor.r, bgcolor.g, bgcolor.b);
  
  // Fill CCImage with color runs
  int xruncount=0,yruncount=0;
  CCImage rimg(w, h);
  int *line;
  GPBuffer<int> gline(line,w);
  int *prevline;
  GPBuffer<int> gprevline(prevline,w);
  for (int x=0;x<w;x++)
  {
    prevline[x]=bgindex;
  }
  for (int y=0; y<h; y++)
    {
      int x;
      const GPixel *row = (*ginput)[y];
      for(x=0;x<w;x++)
        {
          line[x] = pal.color_to_index(row[x]);
          if (opts.bgwhite && row[x]==GPixel::WHITE)
            line[x] = bgindex;
        }
      for(x=0;x<w;)
        {
          int x1 = x;
          int index = line[x++];
          while (x<w && line[x]==index) { x++; }
          if (index != bgindex)
            {
              xruncount++;
              rimg.add_single_run(y, x1, x-1, index);
            }
        }
      for(x=0;x<w;x++)
        if(prevline[x] != line[x]) yruncount++;
      gprevline.swap(gline);
    }
  ginput = 0; //save memory
  if (opts.verbose)
    DjVuFormatErrorUTF8( "%s\t%d", ERR_MSG("cpaldjvu.color_runs"), 
                         rimg.runs.size());

  // Perform Color Connected Component Analysis
  rimg.make_ccids_by_analysis();                  // Obtain ccids
  rimg.make_ccs_from_ccids();                     // Compute cc descriptors
  if (opts.verbose)
    DjVuFormatErrorUTF8( "%s\t%d", ERR_MSG("cpaldjvu.ccs_before"), 
                         rimg.ccs.size());
  rimg.merge_and_split_ccs(smallsize,largesize);  // Eliminates gross ccs
  if (opts.verbose)
    DjVuFormatErrorUTF8( "%s\t%d", ERR_MSG("cpaldjvu.ccs_after"), 
                         rimg.ccs.size());
  rimg.sort_in_reading_order();                   // Sort cc descriptors
  
  // Create JB2Image and fill colordata
  GP<JB2Image> gjimg=JB2Image::create();
  JB2Image &jimg=*gjimg;
  jimg.set_dimension(w, h);
  int nccs = rimg.ccs.size();
  for (int ccid=0; ccid<nccs; ccid++)
    {
      JB2Shape shape;
      JB2Blit  blit;
      shape.parent = -1;
      shape.userdata = 0;
      if (ccid >= rimg.nregularccs)
        shape.userdata |= JB2SHAPE_SPECIAL;
      shape.bits = rimg.get_bitmap_for_cc(ccid);
      shape.bits->compress();
      CC& cc = rimg.ccs[ccid];
      blit.shapeno = jimg.add_shape(shape);
      blit.left = cc.bb.xmin;
      blit.bottom = cc.bb.ymin;
      int blitno = jimg.add_blit(blit);
      pal.colordata.touch(blitno);
      pal.colordata[blitno] = cc.color;
    }
  
  // Organize JB2Image
  tune_jb2image_lossless(&jimg);
  if (opts.verbose)
    {
      int nshape=0, nrefine=0;
      for (int i=0; i<jimg.get_shape_count(); i++) {
        if (!jimg.get_shape(i).bits) continue;
        if (jimg.get_shape(i).parent >= 0) nrefine++; 
        nshape++; 
      }
      DjVuFormatErrorUTF8( "%s\t%d\t%d",
                       ERR_MSG("cpaldjvu.cross_code"), 
                       nshape, nrefine);
    }
  
  // Create background image
#ifdef BACKGROUND_SUBSAMPLING_FACTOR
  // -- we may create the background by masking and subsampling
  GP<GPixmap> ginputsub=GPixmap::create();
  GPixmap &inputsub=*ginputsub;
  GP<GBitmap> mask = jimg.get_bitmap(BACKGROUND_SUBSAMPLING_FACTOR);
  inputsub.downsample(&input, BACKGROUND_SUBSAMPLING_FACTOR);
  GP<IW44Image> iwimage=IW44Image::create(inputsub, mask);
#else
  // -- but who cares since the background is uniform.
  GP<GPixmap> ginputsub=GPixmap::create((h+11)/12, (w+11)/12, &bgcolor);
  GPixmap &inputsub=*ginputsub;
  GP<IW44Image> iwimage=IW44Image::create_encode(inputsub);
#endif

  // Assemble DJVU file
  GP<ByteStream> obs=ByteStream::create(urlout, "wb");
  GP<IFFByteStream> giff=IFFByteStream::create(obs);
  IFFByteStream &iff=*giff;
  // -- main composite chunk
  iff.put_chunk("FORM:DJVU", 1);
  // -- ``INFO'' chunk
  iff.put_chunk("INFO");
  GP<DjVuInfo> ginfo=DjVuInfo::create();
  DjVuInfo info=*ginfo;
  info.height = h;
  info.width = w;
  info.dpi = opts.dpi;
  info.encode(*iff.get_bytestream());
  iff.close_chunk();
  // -- ``Sjbz'' chunk
  iff.put_chunk("Sjbz");
  jimg.encode(iff.get_bytestream());
  iff.close_chunk();
  // -- ``FGbz'' chunk
  iff.put_chunk("FGbz");
  pal.encode(iff.get_bytestream());
  iff.close_chunk();
  // -- ``BG44'' chunk
  IWEncoderParms iwparms;
#ifdef PROGRESSIVE_BACKGROUND
  // ----- we may use several chunks to enable progressive rendering ...
  iff.put_chunk("BG44");
  iwparms.slices = 74;
  iwimage->encode_chunk(iff, iwparms);
  iff.close_chunk();
  iff.put_chunk("BG44");
  iwparms.slices = 87;
  iwimage->encode_chunk(iff, iwparms);
  iff.close_chunk();
#endif
  // ----- but who cares when the background is so small.
  iff.put_chunk("BG44");
  iwparms.slices = 97;
  iwimage->encode_chunk(iff.get_bytestream(), iwparms);
  iff.close_chunk();
  // -- terminate main composite chunk
  iff.close_chunk();
  // Finished!
}  
Esempio n. 2
0
void 
cjb2(const GURL &urlin, const GURL &urlout, cjb2opts &opts)
{
  GP<ByteStream> ibs=ByteStream::create(urlin, "rb");
  CCImage rimg;

#if HAVE_TIFF
  if (is_tiff(ibs))
    read_tiff(rimg, ibs, opts);
  else
#endif
    {
      GP<GBitmap> input=GBitmap::create(*ibs);
      rimg.init(input->columns(), input->rows(), opts.dpi);
      rimg.add_bitmap_runs(*input); 
    }
  if (opts.verbose)
    DjVuFormatErrorUTF8( "%s\t%d", ERR_MSG("cjb2.runs"), 
                         rimg.runs.size() );
  
  // Component analysis
  rimg.make_ccids_by_analysis(); // obtain ccids
  rimg.make_ccs_from_ccids();    // compute cc descriptors
  if (opts.verbose)
    DjVuFormatErrorUTF8( "%s\t%d", ERR_MSG("cjb2.ccs_before"), 
                         rimg.ccs.size());
  if (opts.losslevel > 0) 
    rimg.erase_tiny_ccs();       // clean
  rimg.merge_and_split_ccs();    // reorganize weird ccs
  rimg.sort_in_reading_order();  // sort cc descriptors
  if (opts.verbose)
    DjVuFormatErrorUTF8( "%s\t%d", ERR_MSG("cjb2.ccs_after"), 
                         rimg.ccs.size());
  
  // Pattern matching
  GP<JB2Image> jimg = rimg.get_jb2image();          // get ``raw'' jb2image
  rimg.runs.empty();                                // save memory
  rimg.ccs.empty();                                 // save memory
  if (opts.losslevel>1)
    tune_jb2image_lossy(jimg, opts.dpi, opts.losslevel);
  else
    tune_jb2image_lossless(jimg);
  if (opts.verbose)
    {
      int nshape=0, nrefine=0;
      for (int i=0; i<jimg->get_shape_count(); i++) {
        if (!jimg->get_shape(i).bits) continue;
        if (jimg->get_shape(i).parent >= 0) nrefine++; 
        nshape++; 
      }
      DjVuFormatErrorUTF8( "%s\t%d\t%d", ERR_MSG("cjb2.shapes"), 
                           nshape, nrefine);
    }
  
  // Code
  GP<ByteStream> obs=ByteStream::create(urlout, "wb");
  GP<IFFByteStream> giff=IFFByteStream::create(obs);
  IFFByteStream &iff=*giff;
  // -- main composite chunk
  iff.put_chunk("FORM:DJVU", 1);
  // -- ``INFO'' chunk
  GP<DjVuInfo> ginfo=DjVuInfo::create();
  DjVuInfo &info=*ginfo;
  info.height = rimg.height;
  info.width = rimg.width;
  info.dpi = opts.dpi;
  iff.put_chunk("INFO");
  info.encode(*iff.get_bytestream());
  iff.close_chunk();
  // -- ``Sjbz'' chunk
  iff.put_chunk("Sjbz");
  jimg->encode(iff.get_bytestream());
  iff.close_chunk();
  // -- terminate main composite chunk
  iff.close_chunk();
  // Finished!
}