bitblt_g4.c

changeset 91
e63762afae80
parent 78
74b6b230f85d
child 94
7664a3f112ba
     1.1 --- a/bitblt_g4.c	Sat Mar 08 10:02:13 2003 +0000
     1.2 +++ b/bitblt_g4.c	Mon Mar 10 09:49:50 2003 +0000
     1.3 @@ -3,8 +3,8 @@
     1.4   *      bilevel image files.  The images in the resulting PDF file
     1.5   *      will be compressed using ITU-T T.6 (G4) fax encoding.
     1.6   *
     1.7 - * PDF routines
     1.8 - * $Id: bitblt_g4.c,v 1.8 2003/03/05 12:44:33 eric Exp $
     1.9 + * G4 compression
    1.10 + * $Id: bitblt_g4.c,v 1.9 2003/03/10 01:49:50 eric Exp $
    1.11   * Copyright 2003 Eric Smith <eric@brouhaha.com>
    1.12   *
    1.13   * This program is free software; you can redistribute it and/or modify
    1.14 @@ -32,108 +32,111 @@
    1.15  
    1.16  
    1.17  #include "bitblt.h"
    1.18 -#include "pdf.h"
    1.19 -#include "pdf_util.h"
    1.20 -#include "pdf_prim.h"
    1.21 -#include "pdf_private.h"
    1.22  
    1.23  
    1.24 -#include "pdf_g4_tables.h"
    1.25 -
    1.26 -
    1.27 -#define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0)
    1.28 +#include "g4_tables.h"
    1.29  
    1.30  
    1.31 -struct pdf_g4_image
    1.32 +#define BIT_BUF_SIZE 4096
    1.33 +
    1.34 +struct bit_buffer
    1.35  {
    1.36 -  double width, height;
    1.37 -  double x, y;
    1.38 -  double r, g, b;  /* fill color, only for ImageMask */
    1.39 -  unsigned long Columns;
    1.40 -  unsigned long Rows;
    1.41 -  bool ImageMask;
    1.42 -  bool BlackIs1;
    1.43 -  Bitmap *bitmap;
    1.44 -  char XObject_name [4];
    1.45 +  FILE *f;
    1.46 +  uint32_t byte_idx;  /* index to next byte position in data buffer */
    1.47 +  uint32_t bit_idx;   /* index to next bit position in data buffer,
    1.48 +			 0 = MSB, 7 = LSB */
    1.49 +  uint8_t data [BIT_BUF_SIZE];
    1.50  };
    1.51  
    1.52  
    1.53 -char pdf_new_XObject (pdf_page_handle pdf_page, struct pdf_obj *ind_ref)
    1.54 +static void flush_bits (struct bit_buffer *buf)
    1.55  {
    1.56 -  char XObject_name [4] = "Im ";
    1.57 -
    1.58 -  XObject_name [2] = ++pdf_page->last_XObject_name;
    1.59 -  
    1.60 -  if (! pdf_page->XObject_dict)
    1.61 +  size_t s;
    1.62 +  if (buf->bit_idx)
    1.63      {
    1.64 -      pdf_page->XObject_dict = pdf_new_obj (PT_DICTIONARY);
    1.65 -      pdf_set_dict_entry (pdf_page->resources, "XObject", pdf_page->XObject_dict);
    1.66 +      /* zero remaining bits in last byte */
    1.67 +      buf->data [buf->byte_idx] &= ~ ((1 << (8 - buf->bit_idx)) - 1);
    1.68 +      buf->byte_idx++;
    1.69 +      buf->bit_idx = 0;
    1.70      }
    1.71 +  s = fwrite (& buf->data [0], 1, buf->byte_idx, buf->f);
    1.72 +  /* $$$ should check result */
    1.73 +  buf->byte_idx = 0;
    1.74 +}
    1.75  
    1.76 -  pdf_set_dict_entry (pdf_page->XObject_dict, & XObject_name [0], ind_ref);
    1.77  
    1.78 -  return (pdf_page->last_XObject_name);
    1.79 +static void advance_byte (struct bit_buffer *buf)
    1.80 +{
    1.81 +  buf->byte_idx++;
    1.82 +  buf->bit_idx = 0;
    1.83 +  if (buf->byte_idx == BIT_BUF_SIZE)
    1.84 +    flush_bits (buf);
    1.85  }
    1.86  
    1.87  
    1.88 -void pdf_write_g4_content_callback (pdf_file_handle pdf_file,
    1.89 -				    struct pdf_obj *stream,
    1.90 -				    void *app_data)
    1.91 +static void write_bits (struct bit_buffer *buf,
    1.92 +			uint32_t count,
    1.93 +			uint32_t bits)
    1.94  {
    1.95 -  struct pdf_g4_image *image = app_data;
    1.96 +  uint32_t b2;  /* how many bits will fit in byte in data buffer */
    1.97 +  uint32_t c2;  /* how many bits to transfer on this iteration */
    1.98 +  uint32_t d2;  /* bits to transfer on this iteration */
    1.99  
   1.100 -  /* transformation matrix is: width 0 0 height x y cm */
   1.101 -  pdf_stream_printf (pdf_file, stream, "q %g 0 0 %g %g %g cm ",
   1.102 -		     image->width, image->height,
   1.103 -		     image->x, image->y);
   1.104 -  if (image->ImageMask)
   1.105 -    pdf_stream_printf (pdf_file, stream, "%g %g %g rg ",
   1.106 -		       image->r, image->g, image->b);
   1.107 -
   1.108 -  pdf_stream_printf (pdf_file, stream, "/%s Do Q\r\n",
   1.109 -		     image->XObject_name);
   1.110 +  while (count)
   1.111 +    {
   1.112 +      b2 = 8 - buf->bit_idx;
   1.113 +      if (b2 >= count)
   1.114 +	c2 = count;
   1.115 +      else
   1.116 +	c2 = b2;
   1.117 +      d2 = bits >> (count - c2);
   1.118 +      buf->data [buf->byte_idx] |= (d2 << (b2 + c2));
   1.119 +      buf->bit_idx += c2;
   1.120 +      if (buf->bit_idx > 7)
   1.121 +	advance_byte (buf);
   1.122 +      count -= c2;
   1.123 +    }
   1.124  }
   1.125  
   1.126  
   1.127 -static void pdf_g4_encode_horizontal_run (pdf_file_handle pdf_file,
   1.128 -					  struct pdf_obj *stream,
   1.129 -					  bool black,
   1.130 -					  uint32_t run_length)
   1.131 +static void g4_encode_horizontal_run (struct bit_buffer *buf,
   1.132 +				      bool black,
   1.133 +				      uint32_t run_length)
   1.134  {
   1.135    uint32_t i;
   1.136  
   1.137    while (run_length >= 2560)
   1.138      {
   1.139 -      pdf_stream_write_bits (pdf_file, stream, 12, 0x01f);
   1.140 +      write_bits (buf, 12, 0x01f);
   1.141        run_length -= 2560;
   1.142      }
   1.143  
   1.144    if (run_length >= 1792)
   1.145      {
   1.146        i = (run_length - 1792) >> 6;
   1.147 -      pdf_stream_write_bits (pdf_file, stream,
   1.148 -			     g4_long_makeup_code [i].count,
   1.149 -			     g4_long_makeup_code [i].bits);
   1.150 +      write_bits (buf,
   1.151 +		  g4_long_makeup_code [i].count,
   1.152 +		  g4_long_makeup_code [i].bits);
   1.153        run_length -= (1792 + (i << 6));
   1.154      }
   1.155    else if (run_length >= 64)
   1.156      {
   1.157        i = (run_length >> 6) - 1;
   1.158 -      pdf_stream_write_bits (pdf_file, stream,
   1.159 -			     g4_makeup_code [black] [i].count,
   1.160 -			     g4_makeup_code [black] [i].bits);
   1.161 +      write_bits (buf,
   1.162 +		  g4_makeup_code [black] [i].count,
   1.163 +		  g4_makeup_code [black] [i].bits);
   1.164        run_length -= (i + 1) << 6;
   1.165      }
   1.166  
   1.167 -  pdf_stream_write_bits (pdf_file, stream,
   1.168 -			 g4_h_code [black] [run_length].count,
   1.169 -			 g4_h_code [black] [run_length].bits);
   1.170 +  write_bits (buf,
   1.171 +	      g4_h_code [black] [run_length].count,
   1.172 +	      g4_h_code [black] [run_length].bits);
   1.173  }
   1.174  
   1.175  
   1.176 -uint32_t find_transition (uint8_t *data,
   1.177 -			  uint32_t pos,
   1.178 -			  uint32_t width)
   1.179 +static uint32_t find_transition (uint8_t *data,
   1.180 +				 uint32_t pos,
   1.181 +				 uint32_t width)
   1.182  {
   1.183    if (! data)
   1.184      return (width);
   1.185 @@ -141,11 +144,10 @@
   1.186  }
   1.187  
   1.188  
   1.189 -static void pdf_g4_encode_row (pdf_file_handle pdf_file,
   1.190 -			       struct pdf_obj *stream,
   1.191 -			       uint32_t width,
   1.192 -			       uint8_t *ref,
   1.193 -			       uint8_t *row)
   1.194 +static void g4_encode_row (struct bit_buffer *buf,
   1.195 +			   uint32_t width,
   1.196 +			   uint8_t *ref,
   1.197 +			   uint8_t *row)
   1.198  {
   1.199    int a0, a1, a2;
   1.200    int b1, b2;
   1.201 @@ -167,152 +169,58 @@
   1.202        if (b2 < a1)
   1.203  	{
   1.204  	  /* pass mode - 0001 */
   1.205 -	  pdf_stream_write_bits (pdf_file, stream, 4, 0x1);
   1.206 +	  write_bits (buf, 4, 0x1);
   1.207  	  a0 = b2;
   1.208  	}
   1.209        else if (abs (a1 - b1) <= 3)
   1.210  	{
   1.211  	  /* vertical mode */
   1.212 -	  pdf_stream_write_bits (pdf_file, stream,
   1.213 -				 g4_vert_code [3 + a1 - b1].count,
   1.214 -				 g4_vert_code [3 + a1 - b1].bits);
   1.215 +	  write_bits (buf,
   1.216 +		      g4_vert_code [3 + a1 - b1].count,
   1.217 +		      g4_vert_code [3 + a1 - b1].bits);
   1.218  	  a0 = a1;
   1.219  	}
   1.220        else
   1.221  	{
   1.222  	  /* horizontal mode - 001 */
   1.223 -	  pdf_stream_write_bits (pdf_file, stream, 3, 0x1);
   1.224 -	  pdf_g4_encode_horizontal_run (pdf_file, stream,
   1.225 -					0 /* $$$ color (a0) */, a1 - a0);
   1.226 -	  pdf_g4_encode_horizontal_run (pdf_file, stream,
   1.227 -					1 /* $$$ color (a1) */, a2 - a1);
   1.228 +	  write_bits (buf, 3, 0x1);
   1.229 +	  g4_encode_horizontal_run (buf, 0 /* $$$ color (a0) */, a1 - a0);
   1.230 +	  g4_encode_horizontal_run (buf, 1 /* $$$ color (a1) */, a2 - a1);
   1.231  	  a0 = a2;
   1.232  	}
   1.233      }
   1.234  }
   1.235  
   1.236  
   1.237 -void pdf_write_g4_fax_image_callback (pdf_file_handle pdf_file,
   1.238 -				      struct pdf_obj *stream,
   1.239 -				      void *app_data)
   1.240 +void bitblt_write_g4 (Bitmap *bitmap, FILE *f)
   1.241  {
   1.242 -  struct pdf_g4_image *image = app_data;
   1.243 -
   1.244    uint32_t row;
   1.245 +  struct bit_buffer bb;
   1.246  
   1.247    word_type *ref_line = NULL;  /* reference (previous) row */
   1.248 -  word_type *line = image->bitmap->bits;
   1.249 +  word_type *line = bitmap->bits;
   1.250 +
   1.251 +  memset (& bb, 0, sizeof (bb));
   1.252  
   1.253 -  for (row = image->bitmap->rect.min.y;
   1.254 -       row < image->bitmap->rect.max.y;
   1.255 +  bb.f = f;
   1.256 +
   1.257 +  for (row = bitmap->rect.min.y;
   1.258 +       row < bitmap->rect.max.y;
   1.259         row++)
   1.260      {
   1.261 -      pdf_g4_encode_row (pdf_file, stream, image->Columns,
   1.262 -			 (uint8_t *) ref_line,
   1.263 -			 (uint8_t *) line);
   1.264 +      g4_encode_row (& bb,
   1.265 +		     (bitmap->rect.max.x - bitmap->rect.min.x) + 1,
   1.266 +		     (uint8_t *) ref_line,
   1.267 +		     (uint8_t *) line);
   1.268        ref_line = line;
   1.269 -      line += image->bitmap->row_words;
   1.270 +      line += bitmap->row_words;
   1.271      }
   1.272  
   1.273    
   1.274    /* write EOFB code */
   1.275 -  pdf_stream_write_bits (pdf_file, stream, 24, 0x001001);
   1.276 +  write_bits (& bb, 24, 0x001001);
   1.277  
   1.278 -  pdf_stream_flush_bits (pdf_file, stream);
   1.279 +  flush_bits (& bb);
   1.280  }
   1.281  
   1.282  
   1.283 -void pdf_write_g4_fax_image (pdf_page_handle pdf_page,
   1.284 -			     double x,
   1.285 -			     double y,
   1.286 -			     double width,
   1.287 -			     double height,
   1.288 -			     Bitmap *bitmap,
   1.289 -			     bool ImageMask,
   1.290 -			     double r, /* RGB fill color, only for ImageMask */
   1.291 -			     double g,
   1.292 -			     double b,
   1.293 -			     bool BlackIs1)          /* boolean, typ. false */
   1.294 -{
   1.295 -  struct pdf_g4_image *image;
   1.296 -
   1.297 -  struct pdf_obj *stream;
   1.298 -  struct pdf_obj *stream_dict;
   1.299 -  struct pdf_obj *decode_parms;
   1.300 -
   1.301 -  struct pdf_obj *content_stream;
   1.302 -
   1.303 -  image = pdf_calloc (1, sizeof (struct pdf_g4_image));
   1.304 -
   1.305 -  image->width = width;
   1.306 -  image->height = height;
   1.307 -  image->x = x;
   1.308 -  image->y = y;
   1.309 -  image->r = r;
   1.310 -  image->g = g;
   1.311 -  image->b = b;
   1.312 -
   1.313 -  image->bitmap = bitmap;
   1.314 -  image->Columns = bitmap->rect.max.x - bitmap->rect.min.x;
   1.315 -  image->Rows = bitmap->rect.max.y - bitmap->rect.min.y;
   1.316 -  image->ImageMask = ImageMask;
   1.317 -  image->BlackIs1 = BlackIs1;
   1.318 -
   1.319 -  stream_dict = pdf_new_obj (PT_DICTIONARY);
   1.320 -
   1.321 -  stream = pdf_new_ind_ref (pdf_page->pdf_file,
   1.322 -			    pdf_new_stream (pdf_page->pdf_file,
   1.323 -					    stream_dict,
   1.324 -					    & pdf_write_g4_fax_image_callback,
   1.325 -					    image));
   1.326 -
   1.327 -  strcpy (& image->XObject_name [0], "Im ");
   1.328 -  image->XObject_name [2] = pdf_new_XObject (pdf_page, stream);
   1.329 -
   1.330 -  pdf_set_dict_entry (stream_dict, "Type",    pdf_new_name ("XObject"));
   1.331 -  pdf_set_dict_entry (stream_dict, "Subtype", pdf_new_name ("Image"));
   1.332 -  pdf_set_dict_entry (stream_dict, "Name",    pdf_new_name (& image->XObject_name [0]));
   1.333 -  pdf_set_dict_entry (stream_dict, "Width",   pdf_new_integer (image->Columns));
   1.334 -  pdf_set_dict_entry (stream_dict, "Height",  pdf_new_integer (image->Rows));
   1.335 -  pdf_set_dict_entry (stream_dict, "BitsPerComponent", pdf_new_integer (1));
   1.336 -  if (ImageMask)
   1.337 -    pdf_set_dict_entry (stream_dict, "ImageMask", pdf_new_bool (ImageMask));
   1.338 -  else
   1.339 -    pdf_set_dict_entry (stream_dict, "ColorSpace", pdf_new_name ("DeviceGray"));
   1.340 -
   1.341 -  decode_parms = pdf_new_obj (PT_DICTIONARY);
   1.342 -
   1.343 -  pdf_set_dict_entry (decode_parms,
   1.344 -		      "K",
   1.345 -		      pdf_new_integer (-1));
   1.346 -
   1.347 -  pdf_set_dict_entry (decode_parms,
   1.348 -		      "Columns",
   1.349 -		      pdf_new_integer (image->Columns));
   1.350 -
   1.351 -  pdf_set_dict_entry (decode_parms,
   1.352 -		      "Rows",
   1.353 -		      pdf_new_integer (image->Rows));
   1.354 -
   1.355 -  if (BlackIs1)
   1.356 -    pdf_set_dict_entry (decode_parms,
   1.357 -			"BlackIs1",
   1.358 -			pdf_new_bool (BlackIs1));
   1.359 -
   1.360 -  pdf_stream_add_filter (stream, "CCITTFaxDecode", decode_parms);
   1.361 -
   1.362 -  /* the following will write the stream, using our callback function to
   1.363 -     get the actual data */
   1.364 -  pdf_write_ind_obj (pdf_page->pdf_file, stream);
   1.365 -
   1.366 -  content_stream = pdf_new_ind_ref (pdf_page->pdf_file,
   1.367 -				    pdf_new_stream (pdf_page->pdf_file,
   1.368 -						    pdf_new_obj (PT_DICTIONARY),
   1.369 -						    & pdf_write_g4_content_callback,
   1.370 -						    image));
   1.371 -
   1.372 -  pdf_set_dict_entry (pdf_page->page_dict, "Contents", content_stream);
   1.373 -
   1.374 -  pdf_write_ind_obj (pdf_page->pdf_file, content_stream);
   1.375 -}
   1.376 -