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

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