tumble_jp2.c

Mon, 14 Dec 2009 16:16:03 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 14 Dec 2009 16:16:03 +0000
changeset 169
da28fb586984
parent 166
301f6f17c364
permissions
-rw-r--r--

Added tag V0_33_philpem1 for changeset ad0b9a8990ac

     1 /*
     2  * tumble: build a PDF file from image files
     3  *
     4  * Copyright 2004 Daniel Gloeckner
     5  *
     6  * Derived from tumble_jpeg.c written 2003 by Eric Smith <eric at brouhaha.com>
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License version 2 as
    10  * published by the Free Software Foundation.  Note that permission is
    11  * not granted to redistribute this program under the terms of any
    12  * other version of the General Public License.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU General Public License for more details.
    18  *
    19  * You should have received a copy of the GNU General Public License
    20  * along with this program; if not, write to the Free Software
    21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
    22  */
    25 #include <stdbool.h>
    26 #include <stdint.h>
    27 #include <stdio.h>
    28 #include <math.h>
    29 #include <strings.h>  /* strcasecmp() is a BSDism */
    32 #include "semantics.h"
    33 #include "tumble.h"
    34 #include "bitblt.h"
    35 #include "pdf.h"
    36 #include "tumble_input.h"
    39 static bool match_jp2_suffix (char *suffix)
    40 {
    41   return (strcasecmp (suffix, ".jp2") == 0);
    42 }
    44 static bool close_jp2_input_file (void)
    45 {
    46   return (1);
    47 }
    49 static struct {
    50   FILE *f;
    51   uint32_t width,height;
    52   struct {
    53     double VR,HR;
    54   } res[2];
    55 } jp2info;
    57 struct box {
    58   char TBox[4];
    59   bool (*func)(uint64_t size, void *cparam);
    60   void *cparam;
    61 };
    63 #define BE32(p) (((p)[0]<<24)+((p)[1]<<16)+((p)[2]<<8)+(p)[3])
    64 #define BE16(p) (((p)[2]<<8)+(p)[3])
    66 static bool skipbox(uint64_t size, void *cparam)
    67 {
    68   if(size==~0)
    69     fseek(jp2info.f,0,SEEK_END);
    70   else {
    71     if(cparam)
    72       size-=*(int *)cparam;
    73     fseek(jp2info.f,size,SEEK_CUR); /*FIXME: size is 64bit*/
    74   }
    75   return 1;
    76 }
    78 static bool read_res(uint64_t size, void *cparam)
    79 {
    80   int read=0;
    81   bool ret=1;
    82   if(size>=10) {
    83     int i;
    84     unsigned char buf[10];
    86     ret=0;
    87     i=(int)cparam;
    88     read=fread(buf,1,10,jp2info.f);
    89     if(read==10) {
    90       uint16_t vrn,vrd,hrn,hrd;
    91       int8_t vre,hre;
    92       vrn=BE16(buf);
    93       vrd=BE16(buf+2);
    94       hrn=BE16(buf+4);
    95       hrd=BE16(buf+6);
    96       vre=((signed char *)buf)[8];
    97       hre=((signed char *)buf)[9];
    98       if(vrn && vrd && hrn && hrd) {
    99 	jp2info.res[i].VR=vrn*pow(10.0,vre)/vrd;
   100 	jp2info.res[i].HR=hrn*pow(10.0,hre)/hrd;
   101 	ret=1;
   102       }
   103     }
   104   }
   105   skipbox(size,&read);
   106   return ret;
   107 }
   109 static bool read_ihdr(uint64_t size, void *cparam)
   110 {
   111   int read=0;
   112   bool ret=1;
   113   if(size>=8) {
   114     unsigned char buf[8];
   115     read=fread(buf,1,8,jp2info.f);
   116     if(read==8) {
   117       jp2info.height=BE32(buf);
   118       jp2info.width=BE32(buf+4);
   119     } else
   120       ret=0;
   121   }
   122   skipbox(size,&read);
   123   return ret;
   124 }
   126 static bool superbox(uint64_t size, void *cparam)
   127 { 
   128   while(size>=8) {
   129     static unsigned char buf[12];
   130     int r;
   131     uint64_t s;
   132     struct box *l;
   134     r=fread(buf+4,1,8,jp2info.f);
   135     if(r<8)
   136       return (size==~0 && r==0);
   138     s=BE32(buf+4);
   139     if(s==1 && size>=16) {
   140       r=fread(buf,1,8,jp2info.f);
   141       if(r<8)
   142         return 0;
   143       s=((uint64_t)BE32(buf)<<32)+BE32(buf+4);
   144     }
   145     if(s && s<8)
   146       return 0;
   147     if(size!=~0) {
   148       if(!s)
   149         return 0;
   150       size-=s;
   151     } else if(!s)
   152       size=0;
   153     s=s?s-8:~0;
   155     for(l=(struct box *)cparam;l->func;l++)
   156       if(!memcmp(l->TBox,buf+8,4))
   157         break;
   158     if(l->func) {
   159       if(!l->func(s,l->cparam))
   160 	return 0;
   161     }else
   162       if(!skipbox(s,NULL))
   163 	return 0;
   164   }
   166   return size==0;
   167 }
   169 static const struct box res_boxes[]={
   170   {"resc",read_res,(void *)0},
   171   {"resd",read_res,(void *)1},
   172   {"",NULL,NULL}
   173 };
   175 static const struct box jp2h_boxes[]={
   176   {"ihdr",read_ihdr,NULL},
   177   {"res ",superbox,(void *)res_boxes},
   178   {"",NULL,NULL}
   179 };
   181 static const struct box root[]={
   182   {"jp2h",superbox,(void *)jp2h_boxes},
   183   {"",NULL,NULL}
   184 };
   186 static bool open_jp2_input_file (FILE *f, char *name)
   187 {
   188   int s;
   189   const char sig[12]="\0\0\0\xCjP  \r\n\x87\n";
   190   char buf[12];
   192   memset(&jp2info,0,sizeof(jp2info));
   193   jp2info.f=f;
   195   s=fread(buf,1,12,f);
   196   rewind(f);
   197   return (s==12 && !memcmp(buf,sig,12));
   198 }
   201 static bool last_jp2_input_page (void)
   202 {
   203   return 1;
   204 }
   207 static bool get_jp2_image_info (int image,
   208 				 input_attributes_t input_attributes,
   209 				 image_info_t *image_info)
   210 {
   211   int i;
   213   if(!superbox(~0,(void *)root))
   214     return 0;
   215   rewind(jp2info.f);
   217 #ifdef DEBUG_JPEG
   218   printf ("capture x density: %d pixel/m\n", jp2info.res[0].HR);
   219   printf ("capture y density: %d pixel/m\n", jp2info.res[0].VR);
   220   printf ("display x density: %d pixel/m\n", jp2info.res[1].HR);
   221   printf ("display y density: %d pixel/m\n", jp2info.res[1].VR);
   222   printf ("width: %d\n", jp2info.width);
   223   printf ("height: %d\n", jp2info.height);
   224 #endif
   226   image_info->color = 1;
   227   image_info->width_samples = jp2info.width;
   228   image_info->height_samples = jp2info.height;
   230   image_info->width_points = (image_info->width_samples * POINTS_PER_INCH) / 300.0;
   231   image_info->height_points = (image_info->height_samples * POINTS_PER_INCH) / 300.0;
   233   for(i=2;i--;)
   234     if(jp2info.res[i].VR > 0.0 && jp2info.res[i].HR > 0.0) {
   235       image_info->width_points = (image_info->width_samples * POINTS_PER_INCH * 10000)/(jp2info.res[i].HR * 254);
   236       image_info->height_points = (image_info->height_samples * POINTS_PER_INCH * 10000)/(jp2info.res[i].VR * 254);
   237       break;
   238     }
   240   return 1;
   241 }
   244 static bool process_jp2_image (int image,  /* range 1 .. n */
   245 				input_attributes_t input_attributes,
   246 				image_info_t *image_info,
   247 				pdf_page_handle page)
   248 {
   249   pdf_write_jp2_image (page,
   250 			0, 0,  /* x, y */
   251 			image_info->width_points,
   252 			image_info->height_points,
   253 			image_info->width_samples,
   254 			image_info->height_samples,
   255 			jp2info.f);
   257   return (1);
   258 }
   261 input_handler_t jp2_handler =
   262   {
   263     match_jp2_suffix,
   264     open_jp2_input_file,
   265     close_jp2_input_file,
   266     last_jp2_input_page,
   267     get_jp2_image_info,
   268     process_jp2_image
   269   };
   272 void init_jp2_handler (void)
   273 {
   274   install_input_handler (& jp2_handler);
   275 }