head 1.403; access; symbols; locks; strict; comment @ * @; 1.403 date 2008.04.29.18.18.53; author dcoffin; state Exp; branches; next 1.402; 1.402 date 2008.04.20.08.09.37; author dcoffin; state Exp; branches; next 1.401; 1.401 date 2008.04.07.19.25.08; author dcoffin; state Exp; branches; next 1.400; 1.400 date 2008.04.06.01.18.43; author dcoffin; state Exp; branches; next 1.399; 1.399 date 2008.03.05.01.29.34; author dcoffin; state Exp; branches; next 1.398; 1.398 date 2008.02.06.21.29.13; author dcoffin; state Exp; branches; next 1.397; 1.397 date 2007.12.10.07.43.31; author dcoffin; state Exp; branches; next 1.396; 1.396 date 2007.11.16.15.24.52; author dcoffin; state Exp; branches; next 1.395; 1.395 date 2007.11.12.20.28.32; author dcoffin; state Exp; branches; next 1.394; 1.394 date 2007.11.04.02.18.54; author dcoffin; state Exp; branches; next 1.393; 1.393 date 2007.10.30.06.23.29; author dcoffin; state Exp; branches; next 1.392; 1.392 date 2007.08.10.21.09.34; author dcoffin; state Exp; branches; next 1.391; 1.391 date 2007.08.08.21.28.17; author dcoffin; state Exp; branches; next 1.390; 1.390 date 2007.08.01.17.39.28; author dcoffin; state Exp; branches; next 1.389; 1.389 date 2007.07.28.23.39.53; author dcoffin; state Exp; branches; next 1.388; 1.388 date 2007.07.23.06.52.52; author dcoffin; state Exp; branches; next 1.387; 1.387 date 2007.06.24.00.18.52; author dcoffin; state Exp; branches; next 1.386; 1.386 date 2007.06.13.22.42.15; author dcoffin; state Exp; branches; next 1.385; 1.385 date 2007.06.13.06.40.04; author dcoffin; state Exp; branches; next 1.384; 1.384 date 2007.06.08.21.29.34; author dcoffin; state Exp; branches; next 1.383; 1.383 date 2007.06.04.01.19.23; author dcoffin; state Exp; branches; next 1.382; 1.382 date 2007.06.02.04.18.22; author dcoffin; state Exp; branches; next 1.381; 1.381 date 2007.05.09.17.19.29; author dcoffin; state Exp; branches; next 1.380; 1.380 date 2007.05.06.23.05.56; author dcoffin; state Exp; branches; next 1.379; 1.379 date 2007.05.03.06.15.16; author dcoffin; state Exp; branches; next 1.378; 1.378 date 2007.04.29.19.01.29; author dcoffin; state Exp; branches; next 1.377; 1.377 date 2007.03.25.22.56.19; author dcoffin; state Exp; branches; next 1.376; 1.376 date 2007.03.19.21.09.00; author dcoffin; state Exp; branches; next 1.375; 1.375 date 2007.03.17.05.18.22; author dcoffin; state Exp; branches; next 1.374; 1.374 date 2007.03.15.05.19.10; author dcoffin; state Exp; branches; next 1.373; 1.373 date 2007.03.14.20.30.19; author dcoffin; state Exp; branches; next 1.372; 1.372 date 2007.03.13.05.04.22; author dcoffin; state Exp; branches; next 1.371; 1.371 date 2007.03.07.23.37.58; author dcoffin; state Exp; branches; next 1.370; 1.370 date 2007.03.02.17.40.15; author dcoffin; state Exp; branches; next 1.369; 1.369 date 2007.02.27.02.11.06; author dcoffin; state Exp; branches; next 1.368; 1.368 date 2007.02.25.03.09.54; author dcoffin; state Exp; branches; next 1.367; 1.367 date 2007.02.24.22.10.59; author dcoffin; state Exp; branches; next 1.366; 1.366 date 2007.02.22.16.50.08; author dcoffin; state Exp; branches; next 1.365; 1.365 date 2007.02.12.22.55.47; author dcoffin; state Exp; branches; next 1.364; 1.364 date 2007.01.21.00.41.17; author dcoffin; state Exp; branches; next 1.363; 1.363 date 2007.01.18.23.57.32; author dcoffin; state Exp; branches; next 1.362; 1.362 date 2007.01.09.02.06.51; author dcoffin; state Exp; branches; next 1.361; 1.361 date 2007.01.02.03.51.27; author dcoffin; state Exp; branches; next 1.360; 1.360 date 2006.12.22.03.56.43; author dcoffin; state Exp; branches; next 1.359; 1.359 date 2006.12.14.15.40.47; author dcoffin; state Exp; branches; next 1.358; 1.358 date 2006.12.04.03.10.46; author dcoffin; state Exp; branches; next 1.357; 1.357 date 2006.11.28.04.18.50; author dcoffin; state Exp; branches; next 1.356; 1.356 date 2006.11.21.16.32.10; author dcoffin; state Exp; branches; next 1.355; 1.355 date 2006.11.04.15.55.41; author dcoffin; state Exp; branches; next 1.354; 1.354 date 2006.10.25.22.35.03; author dcoffin; state Exp; branches; next 1.353; 1.353 date 2006.10.10.04.46.02; author dcoffin; state Exp; branches; next 1.352; 1.352 date 2006.10.06.16.35.50; author dcoffin; state Exp; branches; next 1.351; 1.351 date 2006.09.22.04.59.09; author dcoffin; state Exp; branches; next 1.350; 1.350 date 2006.09.19.20.50.11; author dcoffin; state Exp; branches; next 1.349; 1.349 date 2006.09.12.08.38.59; author dcoffin; state Exp; branches; next 1.348; 1.348 date 2006.09.08.14.52.39; author dcoffin; state Exp; branches; next 1.347; 1.347 date 2006.09.06.18.44.58; author dcoffin; state Exp; branches; next 1.346; 1.346 date 2006.09.03.16.37.49; author dcoffin; state Exp; branches; next 1.345; 1.345 date 2006.09.02.14.56.28; author dcoffin; state Exp; branches; next 1.344; 1.344 date 2006.08.31.18.43.44; author dcoffin; state Exp; branches; next 1.343; 1.343 date 2006.08.24.20.24.51; author dcoffin; state Exp; branches; next 1.342; 1.342 date 2006.08.20.05.14.23; author dcoffin; state Exp; branches; next 1.341; 1.341 date 2006.08.18.02.52.47; author dcoffin; state Exp; branches; next 1.340; 1.340 date 2006.08.08.15.06.13; author dcoffin; state Exp; branches; next 1.339; 1.339 date 2006.08.06.20.28.43; author dcoffin; state Exp; branches; next 1.338; 1.338 date 2006.07.31.21.34.50; author dcoffin; state Exp; branches; next 1.337; 1.337 date 2006.07.30.19.52.37; author dcoffin; state Exp; branches; next 1.336; 1.336 date 2006.07.27.20.04.06; author dcoffin; state Exp; branches; next 1.335; 1.335 date 2006.07.26.18.02.50; author dcoffin; state Exp; branches; next 1.334; 1.334 date 2006.07.21.14.48.23; author dcoffin; state Exp; branches; next 1.333; 1.333 date 2006.07.18.06.30.03; author dcoffin; state Exp; branches; next 1.332; 1.332 date 2006.06.23.07.36.10; author dcoffin; state Exp; branches; next 1.331; 1.331 date 2006.06.21.20.00.07; author dcoffin; state Exp; branches; next 1.330; 1.330 date 2006.05.29.18.54.35; author dcoffin; state Exp; branches; next 1.329; 1.329 date 2006.05.28.05.07.49; author dcoffin; state Exp; branches; next 1.328; 1.328 date 2006.05.21.20.04.39; author dcoffin; state Exp; branches; next 1.327; 1.327 date 2006.05.21.19.44.03; author dcoffin; state Exp; branches; next 1.326; 1.326 date 2006.05.18.06.34.26; author dcoffin; state Exp; branches; next 1.325; 1.325 date 2006.05.14.05.08.10; author dcoffin; state Exp; branches; next 1.324; 1.324 date 2006.05.04.22.45.45; author dcoffin; state Exp; branches; next 1.323; 1.323 date 2006.04.09.02.40.56; author dcoffin; state Exp; branches; next 1.322; 1.322 date 2006.04.06.18.51.37; author dcoffin; state Exp; branches; next 1.321; 1.321 date 2006.03.31.21.54.29; author dcoffin; state Exp; branches; next 1.320; 1.320 date 2006.03.29.02.44.05; author dcoffin; state Exp; branches; next 1.319; 1.319 date 2006.03.24.07.03.04; author dcoffin; state Exp; branches; next 1.318; 1.318 date 2006.03.21.20.47.06; author dcoffin; state Exp; branches; next 1.317; 1.317 date 2006.03.21.02.28.23; author dcoffin; state Exp; branches; next 1.316; 1.316 date 2006.03.20.21.50.28; author dcoffin; state Exp; branches; next 1.315; 1.315 date 2006.02.09.05.23.08; author dcoffin; state Exp; branches; next 1.314; 1.314 date 2006.02.07.06.56.51; author dcoffin; state Exp; branches; next 1.313; 1.313 date 2006.01.24.16.51.53; author dcoffin; state Exp; branches; next 1.312; 1.312 date 2006.01.24.08.47.38; author dcoffin; state Exp; branches; next 1.311; 1.311 date 2006.01.23.09.31.52; author dcoffin; state Exp; branches; next 1.310; 1.310 date 2006.01.21.10.41.56; author dcoffin; state Exp; branches; next 1.309; 1.309 date 2005.12.18.21.02.19; author dcoffin; state Exp; branches; next 1.308; 1.308 date 2005.12.11.01.07.33; author dcoffin; state Exp; branches; next 1.307; 1.307 date 2005.12.09.03.05.18; author dcoffin; state Exp; branches; next 1.306; 1.306 date 2005.12.08.01.42.17; author dcoffin; state Exp; branches; next 1.305; 1.305 date 2005.12.06.08.18.35; author dcoffin; state Exp; branches; next 1.304; 1.304 date 2005.11.29.18.59.01; author dcoffin; state Exp; branches; next 1.303; 1.303 date 2005.11.29.08.36.52; author dcoffin; state Exp; branches; next 1.302; 1.302 date 2005.11.24.01.42.35; author dcoffin; state Exp; branches; next 1.301; 1.301 date 2005.11.23.08.07.55; author dcoffin; state Exp; branches; next 1.300; 1.300 date 2005.11.13.01.46.57; author dcoffin; state Exp; branches; next 1.299; 1.299 date 2005.11.12.01.20.27; author dcoffin; state Exp; branches; next 1.298; 1.298 date 2005.11.11.01.39.54; author dcoffin; state Exp; branches; next 1.297; 1.297 date 2005.11.06.04.17.59; author dcoffin; state Exp; branches; next 1.296; 1.296 date 2005.11.04.07.11.14; author dcoffin; state Exp; branches; next 1.295; 1.295 date 2005.10.26.22.36.53; author dcoffin; state Exp; branches; next 1.294; 1.294 date 2005.10.26.07.22.16; author dcoffin; state Exp; branches; next 1.293; 1.293 date 2005.10.21.02.01.00; author dcoffin; state Exp; branches; next 1.292; 1.292 date 2005.10.19.21.55.29; author dcoffin; state Exp; branches; next 1.291; 1.291 date 2005.10.18.07.43.44; author dcoffin; state Exp; branches; next 1.290; 1.290 date 2005.10.12.03.50.10; author dcoffin; state Exp; branches; next 1.289; 1.289 date 2005.10.08.04.03.17; author dcoffin; state Exp; branches; next 1.288; 1.288 date 2005.10.03.05.31.46; author dcoffin; state Exp; branches; next 1.287; 1.287 date 2005.10.01.04.55.11; author dcoffin; state Exp; branches; next 1.286; 1.286 date 2005.09.25.22.26.03; author dcoffin; state Exp; branches; next 1.285; 1.285 date 2005.09.13.01.03.22; author dcoffin; state Exp; branches; next 1.284; 1.284 date 2005.09.08.04.31.20; author dcoffin; state Exp; branches; next 1.283; 1.283 date 2005.09.07.06.01.08; author dcoffin; state Exp; branches; next 1.282; 1.282 date 2005.09.06.19.17.07; author dcoffin; state Exp; branches; next 1.281; 1.281 date 2005.09.01.00.29.22; author dcoffin; state Exp; branches; next 1.280; 1.280 date 2005.08.30.22.53.17; author dcoffin; state Exp; branches; next 1.279; 1.279 date 2005.08.25.05.59.23; author dcoffin; state Exp; branches; next 1.278; 1.278 date 2005.08.24.20.02.34; author dcoffin; state Exp; branches; next 1.277; 1.277 date 2005.08.22.06.13.13; author dcoffin; state Exp; branches; next 1.276; 1.276 date 2005.08.16.08.48.10; author dcoffin; state Exp; branches; next 1.275; 1.275 date 2005.08.12.21.03.34; author dcoffin; state Exp; branches; next 1.274; 1.274 date 2005.08.06.01.04.30; author dcoffin; state Exp; branches; next 1.273; 1.273 date 2005.08.01.06.28.03; author dcoffin; state Exp; branches; next 1.272; 1.272 date 2005.07.31.02.51.11; author dcoffin; state Exp; branches; next 1.271; 1.271 date 2005.07.29.04.06.08; author dcoffin; state Exp; branches; next 1.270; 1.270 date 2005.07.20.22.41.33; author dcoffin; state Exp; branches; next 1.269; 1.269 date 2005.07.14.02.13.45; author dcoffin; state Exp; branches; next 1.268; 1.268 date 2005.07.13.07.25.45; author dcoffin; state Exp; branches; next 1.267; 1.267 date 2005.07.07.03.40.57; author dcoffin; state Exp; branches; next 1.266; 1.266 date 2005.07.06.05.44.34; author dcoffin; state Exp; branches; next 1.265; 1.265 date 2005.06.27.20.22.12; author dcoffin; state Exp; branches; next 1.264; 1.264 date 2005.06.27.05.12.08; author dcoffin; state Exp; branches; next 1.263; 1.263 date 2005.06.06.05.32.07; author dcoffin; state Exp; branches; next 1.262; 1.262 date 2005.05.27.01.39.38; author dcoffin; state Exp; branches; next 1.261; 1.261 date 2005.05.21.01.54.47; author dcoffin; state Exp; branches; next 1.260; 1.260 date 2005.05.20.06.18.43; author dcoffin; state Exp; branches; next 1.259; 1.259 date 2005.05.10.20.57.07; author dcoffin; state Exp; branches; next 1.258; 1.258 date 2005.05.05.06.35.59; author dcoffin; state Exp; branches; next 1.257; 1.257 date 2005.05.03.18.50.30; author dcoffin; state Exp; branches; next 1.256; 1.256 date 2005.05.03.04.16.09; author dcoffin; state Exp; branches; next 1.255; 1.255 date 2005.04.29.16.38.16; author dcoffin; state Exp; branches; next 1.254; 1.254 date 2005.04.27.20.10.40; author dcoffin; state Exp; branches; next 1.253; 1.253 date 2005.04.26.00.46.33; author dcoffin; state Exp; branches; next 1.252; 1.252 date 2005.04.22.16.03.53; author dcoffin; state Exp; branches; next 1.251; 1.251 date 2005.04.19.16.00.41; author dcoffin; state Exp; branches; next 1.250; 1.250 date 2005.04.18.03.18.57; author dcoffin; state Exp; branches; next 1.249; 1.249 date 2005.04.05.07.21.29; author dcoffin; state Exp; branches; next 1.248; 1.248 date 2005.03.31.19.42.59; author dcoffin; state Exp; branches; next 1.247; 1.247 date 2005.03.29.06.33.18; author dcoffin; state Exp; branches; next 1.246; 1.246 date 2005.03.28.19.32.13; author dcoffin; state Exp; branches; next 1.245; 1.245 date 2005.03.28.04.56.02; author dcoffin; state Exp; branches; next 1.244; 1.244 date 2005.03.25.19.39.58; author dcoffin; state Exp; branches; next 1.243; 1.243 date 2005.03.23.23.00.33; author dcoffin; state Exp; branches; next 1.242; 1.242 date 2005.03.23.17.52.43; author dcoffin; state Exp; branches; next 1.241; 1.241 date 2005.03.19.01.40.04; author dcoffin; state Exp; branches; next 1.240; 1.240 date 2005.03.18.22.15.37; author dcoffin; state Exp; branches; next 1.239; 1.239 date 2005.03.11.18.47.13; author dcoffin; state Exp; branches; next 1.238; 1.238 date 2005.03.11.00.50.22; author dcoffin; state Exp; branches; next 1.237; 1.237 date 2005.03.10.03.48.40; author dcoffin; state Exp; branches; next 1.236; 1.236 date 2005.02.27.03.26.37; author dcoffin; state Exp; branches; next 1.235; 1.235 date 2005.02.16.06.11.39; author dcoffin; state Exp; branches; next 1.234; 1.234 date 2005.02.02.22.29.22; author dcoffin; state Exp; branches; next 1.233; 1.233 date 2005.01.25.20.31.18; author dcoffin; state Exp; branches; next 1.232; 1.232 date 2005.01.25.17.31.10; author dcoffin; state Exp; branches; next 1.231; 1.231 date 2005.01.25.02.29.44; author dcoffin; state Exp; branches; next 1.230; 1.230 date 2005.01.24.05.43.59; author dcoffin; state Exp; branches; next 1.229; 1.229 date 2005.01.21.06.48.13; author dcoffin; state Exp; branches; next 1.228; 1.228 date 2005.01.19.08.50.44; author dcoffin; state Exp; branches; next 1.227; 1.227 date 2005.01.14.00.01.30; author dcoffin; state Exp; branches; next 1.226; 1.226 date 2005.01.10.07.04.46; author dcoffin; state Exp; branches; next 1.225; 1.225 date 2005.01.08.05.26.49; author dcoffin; state Exp; branches; next 1.224; 1.224 date 2005.01.04.23.08.52; author dcoffin; state Exp; branches; next 1.223; 1.223 date 2004.12.31.09.07.44; author dcoffin; state Exp; branches; next 1.222; 1.222 date 2004.12.22.20.48.54; author dcoffin; state Exp; branches; next 1.221; 1.221 date 2004.12.17.07.31.32; author dcoffin; state Exp; branches; next 1.220; 1.220 date 2004.12.08.23.50.03; author dcoffin; state Exp; branches; next 1.219; 1.219 date 2004.12.04.05.42.44; author dcoffin; state Exp; branches; next 1.218; 1.218 date 2004.12.01.21.54.52; author dcoffin; state Exp; branches; next 1.217; 1.217 date 2004.11.28.02.27.04; author dcoffin; state Exp; branches; next 1.216; 1.216 date 2004.11.22.02.34.41; author dcoffin; state Exp; branches; next 1.215; 1.215 date 2004.11.05.06.48.50; author dcoffin; state Exp; branches; next 1.214; 1.214 date 2004.10.26.02.28.46; author dcoffin; state Exp; branches; next 1.213; 1.213 date 2004.10.24.23.27.22; author dcoffin; state Exp; branches; next 1.212; 1.212 date 2004.10.23.04.40.54; author dcoffin; state Exp; branches; next 1.211; 1.211 date 2004.10.13.01.13.53; author dcoffin; state Exp; branches; next 1.210; 1.210 date 2004.10.08.02.34.46; author dcoffin; state Exp; branches; next 1.209; 1.209 date 2004.10.07.01.11.51; author dcoffin; state Exp; branches; next 1.208; 1.208 date 2004.10.04.20.33.44; author dcoffin; state Exp; branches; next 1.207; 1.207 date 2004.10.02.21.59.44; author dcoffin; state Exp; branches; next 1.206; 1.206 date 2004.09.19.05.00.32; author dcoffin; state Exp; branches; next 1.205; 1.205 date 2004.09.16.20.29.15; author dcoffin; state Exp; branches; next 1.204; 1.204 date 2004.09.14.00.35.12; author dcoffin; state Exp; branches; next 1.203; 1.203 date 2004.09.07.17.25.15; author dcoffin; state Exp; branches; next 1.202; 1.202 date 2004.09.06.05.50.09; author dcoffin; state Exp; branches; next 1.201; 1.201 date 2004.09.01.21.28.04; author dcoffin; state Exp; branches; next 1.200; 1.200 date 2004.08.04.18.40.25; author dcoffin; state Exp; branches; next 1.199; 1.199 date 2004.07.28.04.25.31; author dcoffin; state Exp; branches; next 1.198; 1.198 date 2004.07.06.18.36.13; author dcoffin; state Exp; branches; next 1.197; 1.197 date 2004.06.29.22.56.42; author dcoffin; state Exp; branches; next 1.196; 1.196 date 2004.06.29.02.23.39; author dcoffin; state Exp; branches; next 1.195; 1.195 date 2004.06.16.17.19.36; author dcoffin; state Exp; branches; next 1.194; 1.194 date 2004.05.22.15.41.31; author dcoffin; state Exp; branches; next 1.193; 1.193 date 2004.05.14.21.26.40; author dcoffin; state Exp; branches; next 1.192; 1.192 date 2004.05.11.19.09.02; author dcoffin; state Exp; branches; next 1.191; 1.191 date 2004.05.11.04.38.40; author dcoffin; state Exp; branches; next 1.190; 1.190 date 2004.05.05.17.20.10; author dcoffin; state Exp; branches; next 1.189; 1.189 date 2004.05.02.19.14.54; author dcoffin; state Exp; branches; next 1.188; 1.188 date 2004.04.29.19.11.08; author dcoffin; state Exp; branches; next 1.187; 1.187 date 2004.04.28.14.35.07; author dcoffin; state Exp; branches; next 1.186; 1.186 date 2004.04.25.20.19.33; author dcoffin; state Exp; branches; next 1.185; 1.185 date 2004.04.25.04.54.14; author dcoffin; state Exp; branches; next 1.184; 1.184 date 2004.04.22.16.53.47; author dcoffin; state Exp; branches; next 1.183; 1.183 date 2004.04.22.01.01.56; author dcoffin; state Exp; branches; next 1.182; 1.182 date 2004.04.19.22.58.46; author dcoffin; state Exp; branches; next 1.181; 1.181 date 2004.04.14.19.19.12; author dcoffin; state Exp; branches; next 1.180; 1.180 date 2004.04.01.18.17.04; author dcoffin; state Exp; branches; next 1.179; 1.179 date 2004.03.29.19.53.10; author dcoffin; state Exp; branches 1.179.1.1; next 1.178; 1.178 date 2004.03.07.02.06.59; author dcoffin; state Exp; branches; next 1.177; 1.177 date 2004.03.05.17.25.30; author dcoffin; state Exp; branches; next 1.176; 1.176 date 2004.03.01.15.17.47; author dcoffin; state Exp; branches; next 1.175; 1.175 date 2004.02.24.04.56.12; author dcoffin; state Exp; branches; next 1.174; 1.174 date 2004.02.23.00.18.33; author dcoffin; state Exp; branches; next 1.173; 1.173 date 2004.02.22.19.28.03; author dcoffin; state Exp; branches; next 1.172; 1.172 date 2004.02.22.04.02.44; author dcoffin; state Exp; branches; next 1.171; 1.171 date 2004.02.21.23.35.56; author dcoffin; state Exp; branches; next 1.170; 1.170 date 2004.02.20.18.37.17; author dcoffin; state Exp; branches; next 1.169; 1.169 date 2004.02.20.04.22.08; author dcoffin; state Exp; branches; next 1.168; 1.168 date 2004.02.18.20.29.52; author dcoffin; state Exp; branches; next 1.167; 1.167 date 2004.02.16.01.01.44; author dcoffin; state Exp; branches; next 1.166; 1.166 date 2004.02.13.16.29.33; author dcoffin; state Exp; branches; next 1.165; 1.165 date 2004.02.13.14.20.06; author dcoffin; state Exp; branches; next 1.164; 1.164 date 2004.02.12.03.44.30; author dcoffin; state Exp; branches; next 1.163; 1.163 date 2004.02.10.18.29.09; author dcoffin; state Exp; branches; next 1.162; 1.162 date 2004.02.07.13.36.34; author dcoffin; state Exp; branches; next 1.161; 1.161 date 2004.01.04.09.21.49; author dcoffin; state Exp; branches; next 1.160; 1.160 date 2004.01.04.08.09.05; author dcoffin; state Exp; branches; next 1.159; 1.159 date 2003.12.24.18.29.49; author dcoffin; state Exp; branches; next 1.158; 1.158 date 2003.12.23.04.30.39; author dcoffin; state Exp; branches; next 1.157; 1.157 date 2003.12.19.05.07.31; author dcoffin; state Exp; branches; next 1.156; 1.156 date 2003.12.17.05.08.01; author dcoffin; state Exp; branches; next 1.155; 1.155 date 2003.12.09.20.35.40; author dcoffin; state Exp; branches; next 1.154; 1.154 date 2003.12.08.07.09.16; author dcoffin; state Exp; branches; next 1.153; 1.153 date 2003.12.04.01.23.06; author dcoffin; state Exp; branches; next 1.152; 1.152 date 2003.11.25.02.25.27; author dcoffin; state Exp; branches; next 1.151; 1.151 date 2003.11.16.08.39.38; author dcoffin; state Exp; branches; next 1.150; 1.150 date 2003.11.14.23.42.33; author dcoffin; state Exp; branches; next 1.149; 1.149 date 2003.11.14.15.53.47; author dcoffin; state Exp; branches; next 1.148; 1.148 date 2003.11.09.00.44.50; author dcoffin; state Exp; branches; next 1.147; 1.147 date 2003.11.06.00.58.27; author dcoffin; state Exp; branches; next 1.146; 1.146 date 2003.11.05.18.10.17; author dcoffin; state Exp; branches; next 1.145; 1.145 date 2003.10.28.00.20.01; author dcoffin; state Exp; branches; next 1.144; 1.144 date 2003.10.20.18.35.01; author dcoffin; state Exp; branches; next 1.143; 1.143 date 2003.10.16.19.38.02; author dcoffin; state Exp; branches; next 1.142; 1.142 date 2003.10.14.20.36.32; author dcoffin; state Exp; branches; next 1.141; 1.141 date 2003.10.14.01.16.41; author dcoffin; state Exp; branches; next 1.140; 1.140 date 2003.10.13.21.21.00; author dcoffin; state Exp; branches; next 1.139; 1.139 date 2003.10.07.07.27.24; author dcoffin; state Exp; branches; next 1.138; 1.138 date 2003.10.04.19.17.37; author dcoffin; state Exp; branches; next 1.137; 1.137 date 2003.10.01.21.59.51; author dcoffin; state Exp; branches; next 1.136; 1.136 date 2003.09.23.00.38.14; author dcoffin; state Exp; branches; next 1.135; 1.135 date 2003.09.21.19.31.42; author dcoffin; state Exp; branches; next 1.134; 1.134 date 2003.09.20.01.51.39; author dcoffin; state Exp; branches; next 1.133; 1.133 date 2003.09.19.04.02.26; author dcoffin; state Exp; branches; next 1.132; 1.132 date 2003.09.18.02.21.21; author dcoffin; state Exp; branches; next 1.131; 1.131 date 2003.09.17.18.33.30; author dcoffin; state Exp; branches; next 1.130; 1.130 date 2003.09.15.03.12.54; author dcoffin; state Exp; branches; next 1.129; 1.129 date 2003.09.11.20.35.53; author dcoffin; state Exp; branches; next 1.128; 1.128 date 2003.07.17.19.06.11; author dcoffin; state Exp; branches; next 1.127; 1.127 date 2003.07.03.02.53.00; author dcoffin; state Exp; branches; next 1.126; 1.126 date 2003.07.02.04.36.23; author dcoffin; state Exp; branches; next 1.125; 1.125 date 2003.06.27.17.12.37; author dcoffin; state Exp; branches; next 1.124; 1.124 date 2003.06.24.15.07.14; author dcoffin; state Exp; branches; next 1.123; 1.123 date 2003.06.22.17.01.02; author dcoffin; state Exp; branches; next 1.122; 1.122 date 2003.06.21.02.06.35; author dcoffin; state Exp; branches; next 1.121; 1.121 date 2003.06.21.00.16.57; author dcoffin; state Exp; branches; next 1.120; 1.120 date 2003.06.12.23.13.36; author dcoffin; state Exp; branches; next 1.119; 1.119 date 2003.06.06.16.25.41; author dcoffin; state Exp; branches; next 1.118; 1.118 date 2003.06.06.15.45.57; author dcoffin; state Exp; branches; next 1.117; 1.117 date 2003.06.03.19.06.14; author dcoffin; state Exp; branches; next 1.116; 1.116 date 2003.06.02.14.49.38; author dcoffin; state Exp; branches; next 1.115; 1.115 date 2003.05.30.03.42.18; author dcoffin; state Exp; branches; next 1.114; 1.114 date 2003.05.30.02.19.44; author dcoffin; state Exp; branches; next 1.113; 1.113 date 2003.05.29.22.34.18; author dcoffin; state Exp; branches; next 1.112; 1.112 date 2003.05.28.14.10.08; author dcoffin; state Exp; branches; next 1.111; 1.111 date 2003.05.27.18.17.16; author dcoffin; state Exp; branches; next 1.110; 1.110 date 2003.04.25.17.48.05; author dcoffin; state Exp; branches; next 1.109; 1.109 date 2003.04.25.00.46.29; author dcoffin; state Exp; branches; next 1.108; 1.108 date 2003.04.12.15.31.58; author dcoffin; state Exp; branches; next 1.107; 1.107 date 2003.03.29.23.22.37; author dcoffin; state Exp; branches; next 1.106; 1.106 date 2003.03.23.02.49.33; author dcoffin; state Exp; branches; next 1.105; 1.105 date 2003.03.17.19.34.10; author dcoffin; state Exp; branches; next 1.104; 1.104 date 2003.03.14.16.43.26; author dcoffin; state Exp; branches; next 1.103; 1.103 date 2003.03.12.05.22.20; author dcoffin; state Exp; branches; next 1.102; 1.102 date 2003.03.08.02.28.12; author dcoffin; state Exp; branches; next 1.101; 1.101 date 2003.03.07.00.58.29; author dcoffin; state Exp; branches; next 1.100; 1.100 date 2003.02.25.00.41.11; author dcoffin; state Exp; branches; next 1.99; 1.99 date 2003.02.23.16.34.58; author dcoffin; state Exp; branches; next 1.98; 1.98 date 2003.02.22.20.44.54; author dcoffin; state Exp; branches; next 1.97; 1.97 date 2003.02.17.04.23.32; author dcoffin; state Exp; branches; next 1.96; 1.96 date 2003.02.16.05.01.06; author dcoffin; state Exp; branches; next 1.95; 1.95 date 2003.01.30.19.45.42; author dcoffin; state Exp; branches; next 1.94; 1.94 date 2003.01.28.06.19.40; author dcoffin; state Exp; branches; next 1.93; 1.93 date 2003.01.27.02.55.01; author dcoffin; state Exp; branches; next 1.92; 1.92 date 2003.01.13.21.54.22; author dcoffin; state Exp; branches; next 1.91; 1.91 date 2003.01.09.05.07.39; author dcoffin; state Exp; branches; next 1.90; 1.90 date 2003.01.02.23.24.00; author dcoffin; state Exp; branches; next 1.89; 1.89 date 2002.12.31.23.23.33; author dcoffin; state Exp; branches; next 1.88; 1.88 date 2002.12.19.16.33.15; author dcoffin; state Exp; branches; next 1.87; 1.87 date 2002.12.19.03.13.42; author dcoffin; state Exp; branches; next 1.86; 1.86 date 2002.12.18.03.43.08; author dcoffin; state Exp; branches; next 1.85; 1.85 date 2002.12.17.19.52.52; author dcoffin; state Exp; branches; next 1.84; 1.84 date 2002.12.17.01.45.16; author dcoffin; state Exp; branches; next 1.83; 1.83 date 2002.12.16.06.23.49; author dcoffin; state Exp; branches; next 1.82; 1.82 date 2002.12.13.02.48.35; author dcoffin; state Exp; branches; next 1.81; 1.81 date 2002.12.12.18.14.52; author dcoffin; state Exp; branches; next 1.80; 1.80 date 2002.12.12.06.31.37; author dcoffin; state Exp; branches; next 1.79; 1.79 date 2002.12.04.03.28.49; author dcoffin; state Exp; branches; next 1.78; 1.78 date 2002.12.01.04.34.57; author dcoffin; state Exp; branches; next 1.77; 1.77 date 2002.11.25.04.36.23; author dcoffin; state Exp; branches; next 1.76; 1.76 date 2002.11.24.15.00.57; author dcoffin; state Exp; branches; next 1.75; 1.75 date 2002.11.13.17.37.41; author dcoffin; state Exp; branches; next 1.74; 1.74 date 2002.11.11.02.26.53; author dcoffin; state Exp; branches; next 1.73; 1.73 date 2002.11.09.05.31.58; author dcoffin; state Exp; branches; next 1.72; 1.72 date 2002.10.27.23.55.19; author dcoffin; state Exp; branches; next 1.71; 1.71 date 2002.10.27.18.50.40; author dcoffin; state Exp; branches; next 1.70; 1.70 date 2002.10.20.19.47.30; author dcoffin; state Exp; branches; next 1.69; 1.69 date 2002.10.16.01.09.16; author dcoffin; state Exp; branches; next 1.68; 1.68 date 2002.10.15.01.28.32; author dcoffin; state Exp; branches; next 1.67; 1.67 date 2002.08.15.17.22.53; author dcoffin; state Exp; branches; next 1.66; 1.66 date 2002.08.08.13.12.37; author dcoffin; state Exp; branches; next 1.65; 1.65 date 2002.08.07.23.28.31; author dcoffin; state Exp; branches; next 1.64; 1.64 date 2002.08.07.22.50.13; author dcoffin; state Exp; branches; next 1.63; 1.63 date 2002.06.28.03.55.09; author dcoffin; state Exp; branches; next 1.62; 1.62 date 2002.06.24.14.58.04; author dcoffin; state Exp; branches; next 1.61; 1.61 date 2002.06.23.20.39.42; author dcoffin; state Exp; branches; next 1.60; 1.60 date 2002.06.20.20.32.08; author dcoffin; state Exp; branches; next 1.59; 1.59 date 2002.05.28.17.18.51; author dcoffin; state Exp; branches; next 1.58; 1.58 date 2002.05.23.16.26.47; author dcoffin; state Exp; branches; next 1.57; 1.57 date 2002.05.06.04.11.13; author dcoffin; state Exp; branches; next 1.56; 1.56 date 2002.05.05.20.35.28; author dcoffin; state Exp; branches; next 1.55; 1.55 date 2002.05.05.04.52.02; author dcoffin; state Exp; branches; next 1.54; 1.54 date 2002.05.02.19.44.17; author dcoffin; state Exp; branches; next 1.53; 1.53 date 2002.04.26.03.29.48; author dcoffin; state Exp; branches; next 1.52; 1.52 date 2002.04.17.21.29.10; author dcoffin; state Exp; branches; next 1.51; 1.51 date 2002.04.16.23.32.41; author dcoffin; state Exp; branches; next 1.50; 1.50 date 2002.04.07.19.09.14; author dcoffin; state Exp; branches; next 1.49; 1.49 date 2002.04.04.01.44.38; author dcoffin; state Exp; branches; next 1.48; 1.48 date 2002.04.02.13.44.26; author dcoffin; state Exp; branches; next 1.47; 1.47 date 2002.03.29.02.23.51; author dcoffin; state Exp; branches; next 1.46; 1.46 date 2002.03.28.01.05.30; author dcoffin; state Exp; branches; next 1.45; 1.45 date 2002.03.25.03.52.38; author dcoffin; state Exp; branches; next 1.44; 1.44 date 2002.03.24.19.29.10; author dcoffin; state Exp; branches; next 1.43; 1.43 date 2002.03.24.17.34.52; author dcoffin; state Exp; branches; next 1.42; 1.42 date 2002.02.05.22.40.25; author dcoffin; state Exp; branches; next 1.41; 1.41 date 2002.01.29.20.53.56; author dcoffin; state Exp; branches; next 1.40; 1.40 date 2002.01.13.18.05.57; author dcoffin; state Exp; branches; next 1.39; 1.39 date 2001.12.08.22.59.44; author dcoffin; state Exp; branches; next 1.38; 1.38 date 2001.12.06.04.18.11; author dcoffin; state Exp; branches; next 1.37; 1.37 date 2001.11.25.21.39.22; author dcoffin; state Exp; branches; next 1.36; 1.36 date 2001.11.22.17.13.19; author dcoffin; state Exp; branches; next 1.35; 1.35 date 2001.11.06.00.16.04; author dcoffin; state Exp; branches; next 1.34; 1.34 date 2001.10.28.01.00.19; author dcoffin; state Exp; branches; next 1.33; 1.33 date 2001.10.24.17.56.06; author dcoffin; state Exp; branches; next 1.32; 1.32 date 2001.10.23.13.45.51; author dcoffin; state Exp; branches; next 1.31; 1.31 date 2001.10.19.23.01.31; author dcoffin; state Exp; branches; next 1.30; 1.30 date 2001.10.19.20.14.37; author dcoffin; state Exp; branches; next 1.29; 1.29 date 2001.10.15.04.28.53; author dcoffin; state Exp; branches; next 1.28; 1.28 date 2001.10.14.20.46.29; author dcoffin; state Exp; branches; next 1.27; 1.27 date 2001.09.30.15.30.42; author dcoffin; state Exp; branches; next 1.26; 1.26 date 2001.09.30.00.04.43; author dcoffin; state Exp; branches; next 1.25; 1.25 date 2001.09.24.22.41.06; author dcoffin; state Exp; branches; next 1.24; 1.24 date 2000.06.23.20.19.09; author dcoffin; state Exp; branches; next 1.23; 1.23 date 2000.06.19.06.56.27; author dcoffin; state Exp; branches; next 1.22; 1.22 date 2000.05.20.20.31.28; author dcoffin; state Exp; branches; next 1.21; 1.21 date 2000.05.07.04.26.08; author dcoffin; state Exp; branches; next 1.20; 1.20 date 2000.05.06.20.28.57; author dcoffin; state Exp; branches; next 1.19; 1.19 date 2000.05.05.13.48.25; author dcoffin; state Exp; branches; next 1.18; 1.18 date 2000.05.05.04.21.40; author dcoffin; state Exp; branches; next 1.17; 1.17 date 2000.05.02.13.45.14; author dcoffin; state Exp; branches; next 1.16; 1.16 date 2000.05.02.12.18.24; author dcoffin; state Exp; branches; next 1.15; 1.15 date 2000.05.01.07.06.04; author dcoffin; state Exp; branches; next 1.14; 1.14 date 99.05.07.00.10.38; author dcoffin; state Exp; branches; next 1.13; 1.13 date 99.04.15.21.20.26; author dcoffin; state Exp; branches; next 1.12; 1.12 date 99.04.15.19.57.55; author dcoffin; state Exp; branches; next 1.11; 1.11 date 99.04.12.22.57.06; author dcoffin; state Exp; branches 1.11.1.1; next 1.10; 1.10 date 99.04.12.19.36.36; author dcoffin; state Exp; branches; next 1.9; 1.9 date 99.01.01.20.56.22; author dcoffin; state Exp; branches; next 1.8; 1.8 date 97.08.31.02.09.41; author dcoffin; state Exp; branches; next 1.7; 1.7 date 97.08.24.04.06.03; author dcoffin; state Exp; branches; next 1.6; 1.6 date 97.08.23.19.36.52; author dcoffin; state Exp; branches; next 1.5; 1.5 date 97.03.25.02.49.34; author dcoffin; state Exp; branches; next 1.4; 1.4 date 97.02.25.04.12.42; author dcoffin; state Exp; branches; next 1.3; 1.3 date 97.02.24.02.04.30; author dcoffin; state Exp; branches; next 1.2; 1.2 date 97.02.23.02.17.04; author dcoffin; state Exp; branches; next 1.1; 1.1 date 97.02.23.01.20.29; author dcoffin; state Exp; branches; next ; 1.11.1.1 date 99.04.12.23.00.06; author dcoffin; state Exp; branches; next 1.11.1.2; 1.11.1.2 date 99.04.15.19.17.17; author dcoffin; state Exp; branches; next 1.11.1.3; 1.11.1.3 date 99.04.15.19.57.17; author dcoffin; state Exp; branches; next ; 1.179.1.1 date 2004.04.07.07.22.56; author dcoffin; state Exp; branches; next ; desc @Command-line tool to decode raw photos from all digital cameras @ 1.403 log @Don't crash on corrupt CR2 files. Extract the largest JPEG from any X3F file. @ text @/* dcraw.c -- Dave Coffin's raw photo decoder Copyright 1997-2008 by Dave Coffin, dcoffin a cybercom o net This is a command-line ANSI C program to convert raw photos from any digital camera on any computer running any operating system. No license is required to download and use dcraw.c. However, to lawfully redistribute dcraw, you must either (a) offer, at no extra charge, full source code* for all executable files containing RESTRICTED functions, (b) distribute this code under the GPL Version 2 or later, (c) remove all RESTRICTED functions, re-implement them, or copy them from an earlier, unrestricted Revision of dcraw.c, or (d) purchase a license from the author. The functions that process Foveon images have been RESTRICTED since Revision 1.237. All other code remains free for all uses. *If you have not modified dcraw.c in any way, a link to my homepage qualifies as "full source code". $Revision$ $Date$ */ #define VERSION "8.86" #define _GNU_SOURCE #define _USE_MATH_DEFINES #include #include #include #include #include #include #include #include #include #include #include #include /* NO_JPEG disables decoding of compressed Kodak DC120 files. NO_LCMS disables the "-p" option. */ #ifndef NO_JPEG #include #endif #ifndef NO_LCMS #include #endif #ifdef LOCALEDIR #include #define _(String) gettext(String) #else #define _(String) (String) #endif #ifdef DJGPP #define fseeko fseek #define ftello ftell #else #define fgetc getc_unlocked #endif #ifdef __CYGWIN__ #include #endif #ifdef WIN32 #include #include #pragma comment(lib, "ws2_32.lib") #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp typedef __int64 INT64; typedef unsigned __int64 UINT64; #else #include #include #include typedef long long INT64; typedef unsigned long long UINT64; #endif #ifdef LJPEG_DECODE #error Please compile dcraw.c by itself. #error Do not link it with ljpeg_decode. #endif #ifndef LONG_BIT #define LONG_BIT (8 * sizeof (long)) #endif #define ushort UshORt typedef unsigned char uchar; typedef unsigned short ushort; /* All global variables are defined here, and all functions that access them are prefixed with "CLASS". Note that a thread-safe C++ class cannot have non-const static local variables. */ FILE *ifp; short order; char *ifname, *meta_data; char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64]; float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len; time_t timestamp; unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id; off_t strip_offset, data_offset; off_t thumb_offset, meta_offset, profile_offset; unsigned thumb_length, meta_length, profile_length; unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0; unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress; unsigned black, maximum, mix_green, raw_color, use_gamma, zero_is_bad; unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error; unsigned tile_width, tile_length, gpsdata[32]; ushort raw_height, raw_width, height, width, top_margin, left_margin; ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height; int flip, tiff_flip, colors; double pixel_aspect, aber[4]={1,1,1,1}; ushort (*image)[4], white[8][8], curve[0x4001], cr2_slice[3], sraw_mul[4]; float bright=1, user_mul[4]={0,0,0,0}, threshold=0; int half_size=0, four_color_rgb=0, document_mode=0, highlight=0; int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=-1; int output_color=1, output_bps=8, output_tiff=0, med_passes=0; int no_auto_bright=0; unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX }; float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4]; const double xyz_rgb[3][3] = { /* XYZ from RGB */ { 0.412453, 0.357580, 0.180423 }, { 0.212671, 0.715160, 0.072169 }, { 0.019334, 0.119193, 0.950227 } }; const float d65_white[3] = { 0.950456, 1, 1.088754 }; int histogram[4][0x2000]; void (*write_thumb)(FILE *), (*write_fun)(FILE *); void (*load_raw)(), (*thumb_load_raw)(); jmp_buf failure; struct decode { struct decode *branch[2]; int leaf; } first_decode[2048], *second_decode, *free_decode; struct { int width, height, bps, comp, phint, offset, flip, samples, bytes; } tiff_ifd[10]; struct { int format, key_off, black, black_off, split_col, tag_21a; float tag_210; } ph1; #define CLASS #define FORC(cnt) for (c=0; c < cnt; c++) #define FORC3 FORC(3) #define FORC4 FORC(4) #define FORCC FORC(colors) #define SQR(x) ((x)*(x)) #define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LIM(x,min,max) MAX(min,MIN(x,max)) #define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) #define CLIP(x) LIM(x,0,65535) #define SWAP(a,b) { a ^= b; a ^= (b ^= a); } /* In order to inline this calculation, I make the risky assumption that all filter patterns can be described by a repeating pattern of eight rows and two columns Do not use the FC or BAYER macros with the Leaf CatchLight, because its pattern is 16x16, not 2x8. Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4: 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M 4 C Y C Y C Y 4 Y C Y C Y C PowerShot A5 5 G M G M G M 5 G M G M G M 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y 7 M G M G M G 7 M G M G M G 0 1 2 3 4 5 0 C Y C Y C Y 1 G M G M G M 2 C Y C Y C Y 3 M G M G M G All RGB cameras use one of these Bayer grids: 0x16161616: 0x61616161: 0x49494949: 0x94949494: 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B */ #define FC(row,col) \ (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) #define BAYER(row,col) \ image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)] #define BAYER2(row,col) \ image[((row) >> shrink)*iwidth + ((col) >> shrink)][fc(row,col)] int CLASS fc (int row, int col) { static const char filter[16][16] = { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 }, { 0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2 }, { 2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3 }, { 0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1 }, { 3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0 }, { 2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1 }, { 2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1 }, { 1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3 }, { 2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3 }, { 1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2 }, { 0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2 }, { 2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0 }, { 1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0 }, { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 }, { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 }, { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } }; if (filters != 1) return FC(row,col); return filter[(row+top_margin) & 15][(col+left_margin) & 15]; } #ifndef __GLIBC__ char *my_memmem (char *haystack, size_t haystacklen, char *needle, size_t needlelen) { char *c; for (c = haystack; c <= haystack + haystacklen - needlelen; c++) if (!memcmp (c, needle, needlelen)) return c; return 0; } #define memmem my_memmem #endif void CLASS merror (void *ptr, char *where) { if (ptr) return; fprintf (stderr,_("%s: Out of memory in %s\n"), ifname, where); longjmp (failure, 1); } void CLASS derror() { if (!data_error) { fprintf (stderr, "%s: ", ifname); if (feof(ifp)) fprintf (stderr,_("Unexpected end of file\n")); else fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); } data_error = 1; } ushort CLASS sget2 (uchar *s) { if (order == 0x4949) /* "II" means little-endian */ return s[0] | s[1] << 8; else /* "MM" means big-endian */ return s[0] << 8 | s[1]; } ushort CLASS get2() { uchar str[2] = { 0xff,0xff }; fread (str, 1, 2, ifp); return sget2(str); } unsigned CLASS sget4 (uchar *s) { if (order == 0x4949) return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; else return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; } #define sget4(s) sget4((uchar *)s) unsigned CLASS get4() { uchar str[4] = { 0xff,0xff,0xff,0xff }; fread (str, 1, 4, ifp); return sget4(str); } unsigned CLASS getint (int type) { return type == 3 ? get2() : get4(); } float CLASS int_to_float (int i) { union { int i; float f; } u; u.i = i; return u.f; } double CLASS getreal (int type) { union { char c[8]; double d; } u; int i, rev; switch (type) { case 3: return (unsigned short) get2(); case 4: return (unsigned int) get4(); case 5: u.d = (unsigned int) get4(); return u.d / (unsigned int) get4(); case 8: return (signed short) get2(); case 9: return (signed int) get4(); case 10: u.d = (signed int) get4(); return u.d / (signed int) get4(); case 11: return int_to_float (get4()); case 12: rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); for (i=0; i < 8; i++) u.c[i ^ rev] = fgetc(ifp); return u.d; default: return fgetc(ifp); } } void CLASS read_shorts (ushort *pixel, int count) { if (fread (pixel, 2, count, ifp) < count) derror(); if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) swab (pixel, pixel, count*2); } void CLASS canon_600_fixed_wb (int temp) { static const short mul[4][5] = { { 667, 358,397,565,452 }, { 731, 390,367,499,517 }, { 1119, 396,348,448,537 }, { 1399, 485,431,508,688 } }; int lo, hi, i; float frac=0; for (lo=4; --lo; ) if (*mul[lo] <= temp) break; for (hi=0; hi < 3; hi++) if (*mul[hi] >= temp) break; if (lo != hi) frac = (float) (temp - *mul[lo]) / (*mul[hi] - *mul[lo]); for (i=1; i < 5; i++) pre_mul[i-1] = 1 / (frac * mul[hi][i] + (1-frac) * mul[lo][i]); } /* Return values: 0 = white 1 = near white 2 = not white */ int CLASS canon_600_color (int ratio[2], int mar) { int clipped=0, target, miss; if (flash_used) { if (ratio[1] < -104) { ratio[1] = -104; clipped = 1; } if (ratio[1] > 12) { ratio[1] = 12; clipped = 1; } } else { if (ratio[1] < -264 || ratio[1] > 461) return 2; if (ratio[1] < -50) { ratio[1] = -50; clipped = 1; } if (ratio[1] > 307) { ratio[1] = 307; clipped = 1; } } target = flash_used || ratio[1] < 197 ? -38 - (398 * ratio[1] >> 10) : -123 + (48 * ratio[1] >> 10); if (target - mar <= ratio[0] && target + 20 >= ratio[0] && !clipped) return 0; miss = target - ratio[0]; if (abs(miss) >= mar*4) return 2; if (miss < -20) miss = -20; if (miss > mar) miss = mar; ratio[0] = target - miss; return 1; } void CLASS canon_600_auto_wb() { int mar, row, col, i, j, st, count[] = { 0,0 }; int test[8], total[2][8], ratio[2][2], stat[2]; memset (&total, 0, sizeof total); i = canon_ev + 0.5; if (i < 10) mar = 150; else if (i > 12) mar = 20; else mar = 280 - 20 * i; if (flash_used) mar = 80; for (row=14; row < height-14; row+=4) for (col=10; col < width; col+=2) { for (i=0; i < 8; i++) test[(i & 4) + FC(row+(i >> 1),col+(i & 1))] = BAYER(row+(i >> 1),col+(i & 1)); for (i=0; i < 8; i++) if (test[i] < 150 || test[i] > 1500) goto next; for (i=0; i < 4; i++) if (abs(test[i] - test[i+4]) > 50) goto next; for (i=0; i < 2; i++) { for (j=0; j < 4; j+=2) ratio[i][j >> 1] = ((test[i*4+j+1]-test[i*4+j]) << 10) / test[i*4+j]; stat[i] = canon_600_color (ratio[i], mar); } if ((st = stat[0] | stat[1]) > 1) goto next; for (i=0; i < 2; i++) if (stat[i]) for (j=0; j < 2; j++) test[i*4+j*2+1] = test[i*4+j*2] * (0x400 + ratio[i][j]) >> 10; for (i=0; i < 8; i++) total[st][i] += test[i]; count[st]++; next: ; } if (count[0] | count[1]) { st = count[0]*200 < count[1]; for (i=0; i < 4; i++) pre_mul[i] = 1.0 / (total[st][i] + total[st][i+4]); } } void CLASS canon_600_coeff() { static const short table[6][12] = { { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, { -1203,1715,-1136,1648, 1388,-876,267,245, -1641,2153,3921,-3409 }, { -615,1127,-1563,2075, 1437,-925,509,3, -756,1268,2519,-2007 }, { -190,702,-1886,2398, 2153,-1641,763,-251, -452,964,3040,-2528 }, { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, { -807,1319,-1785,2297, 1388,-876,769,-257, -230,742,2067,-1555 } }; int t=0, i, c; float mc, yc; mc = pre_mul[1] / pre_mul[2]; yc = pre_mul[3] / pre_mul[2]; if (mc > 1 && mc <= 1.28 && yc < 0.8789) t=1; if (mc > 1.28 && mc <= 2) { if (yc < 0.8789) t=3; else if (yc <= 2) t=4; } if (flash_used) t=5; for (raw_color = i=0; i < 3; i++) FORCC rgb_cam[i][c] = table[t][i*4 + c] / 1024.0; } void CLASS canon_600_load_raw() { uchar data[1120], *dp; ushort pixel[896], *pix; int irow, row, col, val; static const short mul[4][2] = { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } }; for (irow=row=0; irow < height; irow++) { if (fread (data, 1, raw_width*5/4, ifp) < raw_width*5/4) derror(); for (dp=data, pix=pixel; dp < data+1120; dp+=10, pix+=8) { pix[0] = (dp[0] << 2) + (dp[1] >> 6 ); pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3); pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3); pix[3] = (dp[4] << 2) + (dp[1] & 3); pix[4] = (dp[5] << 2) + (dp[9] & 3); pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3); pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3); pix[7] = (dp[8] << 2) + (dp[9] >> 6 ); } for (col=0; col < width; col++) BAYER(row,col) = pixel[col]; for (col=width; col < raw_width; col++) black += pixel[col]; if ((row+=2) > height) row = 1; } if (raw_width > width) black = black / ((raw_width - width) * height) - 4; for (row=0; row < height; row++) for (col=0; col < width; col++) { if ((val = BAYER(row,col) - black) < 0) val = 0; val = val * mul[row & 3][col & 1] >> 9; BAYER(row,col) = val; } canon_600_fixed_wb(1311); canon_600_auto_wb(); canon_600_coeff(); maximum = (0x3ff - black) * 1109 >> 9; black = 0; } void CLASS remove_zeroes() { unsigned row, col, tot, n, r, c; for (row=0; row < height; row++) for (col=0; col < width; col++) if (BAYER(row,col) == 0) { tot = n = 0; for (r = row-2; r <= row+2; r++) for (c = col-2; c <= col+2; c++) if (r < height && c < width && FC(r,c) == FC(row,col) && BAYER(r,c)) tot += (n++,BAYER(r,c)); if (n) BAYER(row,col) = tot/n; } } int CLASS canon_s2is() { unsigned row; for (row=0; row < 100; row++) { fseek (ifp, row*3340 + 3284, SEEK_SET); if (getc(ifp) > 15) return 1; } return 0; } void CLASS canon_a5_load_raw() { ushort data[2565], *dp, pixel; int vbits=0, buf=0, row, col, bc=0; order = 0x4949; for (row=-top_margin; row < raw_height-top_margin; row++) { read_shorts (dp=data, raw_width * 10 / 16); for (col=-left_margin; col < raw_width-left_margin; col++) { if (vbits < 10) buf = (vbits += 16, (buf << 16) + *dp++); pixel = buf >> (vbits -= 10) & 0x3ff; if ((unsigned) row < height && (unsigned) col < width) BAYER(row,col) = pixel; else if (col > 1-left_margin && col != width) black += (bc++,pixel); } } if (bc) black /= bc; maximum = 0x3ff; if (raw_width > 1600) remove_zeroes(); } /* getbits(-1) initializes the buffer getbits(n) where 0 <= n <= 25 returns an n-bit integer */ unsigned CLASS getbits (int nbits) { static unsigned bitbuf=0; static int vbits=0, reset=0; unsigned c; if (nbits == -1) return bitbuf = vbits = reset = 0; if (nbits == 0 || reset) return 0; while (vbits < nbits) { if ((c = fgetc(ifp)) == EOF) derror(); if ((reset = zero_after_ff && c == 0xff && fgetc(ifp))) return 0; bitbuf = (bitbuf << 8) + (uchar) c; vbits += 8; } vbits -= nbits; return bitbuf << (32-nbits-vbits) >> (32-nbits); } void CLASS init_decoder() { memset (first_decode, 0, sizeof first_decode); free_decode = first_decode; } /* Construct a decode tree according the specification in *source. The first 16 bytes specify how many codes should be 1-bit, 2-bit 3-bit, etc. Bytes after that are the leaf values. For example, if the source is { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, then the code is 00 0x04 010 0x03 011 0x05 100 0x06 101 0x02 1100 0x07 1101 0x01 11100 0x08 11101 0x09 11110 0x00 111110 0x0a 1111110 0x0b 1111111 0xff */ uchar * CLASS make_decoder (const uchar *source, int level) { struct decode *cur; static int leaf; int i, next; if (level==0) leaf=0; cur = free_decode++; if (free_decode > first_decode+2048) { fprintf (stderr,_("%s: decoder table overflow\n"), ifname); longjmp (failure, 2); } for (i=next=0; i <= leaf && next < 16; ) i += source[next++]; if (i > leaf) { if (level < next) { cur->branch[0] = free_decode; make_decoder (source, level+1); cur->branch[1] = free_decode; make_decoder (source, level+1); } else cur->leaf = source[16 + leaf++]; } return (uchar *) source + 16 + leaf; } void CLASS crw_init_tables (unsigned table) { static const uchar first_tree[3][29] = { { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0, 0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff }, { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0, 0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff }, }; static const uchar second_tree[3][180] = { { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139, 0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08, 0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0, 0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42, 0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57, 0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9, 0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98, 0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6, 0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4, 0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7, 0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1, 0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64, 0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba, 0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4, 0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff }, { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140, 0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06, 0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32, 0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51, 0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26, 0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59, 0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9, 0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99, 0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85, 0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8, 0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a, 0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9, 0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8, 0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8, 0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff }, { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117, 0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08, 0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22, 0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34, 0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41, 0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48, 0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69, 0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8, 0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94, 0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a, 0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6, 0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62, 0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5, 0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3, 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff } }; if (table > 2) table = 2; init_decoder(); make_decoder ( first_tree[table], 0); second_decode = free_decode; make_decoder (second_tree[table], 0); } /* Return 0 if the image starts with compressed data, 1 if it starts with uncompressed low-order bits. In Canon compressed data, 0xff is always followed by 0x00. */ int CLASS canon_has_lowbits() { uchar test[0x4000]; int ret=1, i; fseek (ifp, 0, SEEK_SET); fread (test, 1, sizeof test, ifp); for (i=540; i < sizeof test - 1; i++) if (test[i] == 0xff) { if (test[i+1]) return 1; ret=0; } return ret; } void CLASS canon_compressed_load_raw() { ushort *pixel, *prow; int nblocks, lowbits, i, row, r, col, save, val; unsigned irow, icol; struct decode *decode, *dindex; int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2]; uchar c; crw_init_tables (tiff_compress); pixel = (ushort *) calloc (raw_width*8, sizeof *pixel); merror (pixel, "canon_compressed_load_raw()"); lowbits = canon_has_lowbits(); if (!lowbits) maximum = 0x3ff; fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET); zero_after_ff = 1; getbits(-1); for (row=0; row < raw_height; row+=8) { nblocks = MIN (8, raw_height-row) * raw_width >> 6; for (block=0; block < nblocks; block++) { memset (diffbuf, 0, sizeof diffbuf); decode = first_decode; for (i=0; i < 64; i++ ) { for (dindex=decode; dindex->branch[0]; ) dindex = dindex->branch[getbits(1)]; leaf = dindex->leaf; decode = second_decode; if (leaf == 0 && i) break; if (leaf == 0xff) continue; i += leaf >> 4; len = leaf & 15; if (len == 0) continue; diff = getbits(len); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; if (i < 64) diffbuf[i] = diff; } diffbuf[0] += carry; carry = diffbuf[0]; for (i=0; i < 64; i++ ) { if (pnum++ % raw_width == 0) base[0] = base[1] = 512; if ((pixel[(block << 6) + i] = base[i & 1] += diffbuf[i]) >> 10) derror(); } } if (lowbits) { save = ftell(ifp); fseek (ifp, 26 + row*raw_width/4, SEEK_SET); for (prow=pixel, i=0; i < raw_width*2; i++) { c = fgetc(ifp); for (r=0; r < 8; r+=2, prow++) { val = (*prow << 2) + ((c >> r) & 3); if (raw_width == 2672 && val < 512) val += 2; *prow = val; } } fseek (ifp, save, SEEK_SET); } for (r=0; r < 8; r++) { irow = row - top_margin + r; if (irow >= height) continue; for (col=0; col < raw_width; col++) { icol = col - left_margin; if (icol < width) BAYER(irow,icol) = pixel[r*raw_width+col]; else black += pixel[r*raw_width+col]; } } } free (pixel); if (raw_width > width) black /= (raw_width - width) * height; } /* Not a full implementation of Lossless JPEG, just enough to decode Canon, Kodak and Adobe DNG images. */ struct jhead { int bits, high, wide, clrs, sraw, psv, restart, vpred[4]; struct CLASS decode *huff[4]; ushort *row; }; int CLASS ljpeg_start (struct jhead *jh, int info_only) { int i, tag, len; uchar data[0x10000], *dp; init_decoder(); memset (jh, 0, sizeof *jh); for (i=0; i < 4; i++) jh->huff[i] = free_decode; jh->restart = INT_MAX; fread (data, 2, 1, ifp); if (data[1] != 0xd8) return 0; do { fread (data, 2, 2, ifp); tag = data[0] << 8 | data[1]; len = (data[2] << 8 | data[3]) - 2; if (tag <= 0xff00) return 0; fread (data, 1, len, ifp); switch (tag) { case 0xffc3: jh->sraw = data[7] == 0x21; case 0xffc0: jh->bits = data[0]; jh->high = data[1] << 8 | data[2]; jh->wide = data[3] << 8 | data[4]; jh->clrs = data[5] + jh->sraw; if (len == 9 && !dng_version) getc(ifp); break; case 0xffc4: if (info_only) break; for (dp = data; dp < data+len && *dp < 4; ) { jh->huff[*dp] = free_decode; dp = make_decoder (++dp, 0); } break; case 0xffda: jh->psv = data[1+data[0]*2]; break; case 0xffdd: jh->restart = data[0] << 8 | data[1]; } } while (tag != 0xffda); if (info_only) return 1; if (jh->sraw) { jh->huff[3] = jh->huff[2] = jh->huff[1]; jh->huff[1] = jh->huff[0]; } jh->row = (ushort *) calloc (jh->wide*jh->clrs, 4); merror (jh->row, "ljpeg_start()"); return zero_after_ff = 1; } int CLASS ljpeg_diff (struct decode *dindex) { int len, diff; while (dindex->branch[0]) dindex = dindex->branch[getbits(1)]; len = dindex->leaf; if (len == 16 && (!dng_version || dng_version >= 0x1010000)) return -32768; diff = getbits(len); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; return diff; } ushort * CLASS ljpeg_row (int jrow, struct jhead *jh) { int col, c, diff, pred; ushort mark=0, *row[3]; if (jrow * jh->wide % jh->restart == 0) { FORC4 jh->vpred[c] = 1 << (jh->bits-1); if (jrow) do mark = (mark << 8) + (c = fgetc(ifp)); while (c != EOF && mark >> 4 != 0xffd); getbits(-1); } FORC3 row[c] = jh->row + jh->wide*jh->clrs*((jrow+c) & 1); for (col=0; col < jh->wide; col++) FORC(jh->clrs) { diff = ljpeg_diff (jh->huff[c]); if (jh->sraw && c < 2 && (col | c)) pred = row[0][(c << 1)-3]; else if (col) pred = row[0][-jh->clrs]; else pred = (jh->vpred[c] += diff) - diff; if (jrow && col) switch (jh->psv) { case 1: break; case 2: pred = row[1][0]; break; case 3: pred = row[1][-jh->clrs]; break; case 4: pred = pred + row[1][0] - row[1][-jh->clrs]; break; case 5: pred = pred + ((row[1][0] - row[1][-jh->clrs]) >> 1); break; case 6: pred = row[1][0] + ((pred - row[1][-jh->clrs]) >> 1); break; case 7: pred = (pred + row[1][0]) >> 1; break; default: pred = 0; } if ((**row = pred + diff) >> jh->bits) derror(); row[0]++; row[1]++; } return row[2]; } void CLASS lossless_jpeg_load_raw() { int jwide, jrow, jcol, val, jidx, i, j, row=0, col=0; struct jhead jh; int min=INT_MAX; ushort *rp; if (!ljpeg_start (&jh, 0)) return; jwide = jh.wide * jh.clrs; for (jrow=0; jrow < jh.high; jrow++) { rp = ljpeg_row (jrow, &jh); for (jcol=0; jcol < jwide; jcol++) { val = *rp++; if (jh.bits <= 12) val = curve[val & 0xfff]; if (cr2_slice[0]) { jidx = jrow*jwide + jcol; i = jidx / (cr2_slice[1]*jh.high); if ((j = i >= cr2_slice[0])) i = cr2_slice[0]; jidx -= i * (cr2_slice[1]*jh.high); row = jidx / cr2_slice[1+j]; col = jidx % cr2_slice[1+j] + i*cr2_slice[1]; } if (raw_width == 3984 && (col -= 2) < 0) col += (row--,raw_width); if ((unsigned) (row-top_margin) < height) { if ((unsigned) (col-left_margin) < width) { BAYER(row-top_margin,col-left_margin) = val; if (min > val) min = val; } else black += val; } if (++col >= raw_width) col = (row++,0); } } free (jh.row); if (raw_width > width) black /= (raw_width - width) * height; if (!strcasecmp(make,"KODAK")) black = min; } void CLASS canon_sraw_load_raw() { struct jhead jh; short *rp=0, *ip; int jwide, slice, scol, ecol, row, col, jrow=0, jcol=0, pix[3], c; if (!ljpeg_start (&jh, 0)) return; jwide = (jh.wide >>= 1) * 4; for (ecol=slice=0; slice <= cr2_slice[0]; slice++) { scol = ecol; ecol += cr2_slice[1] >> 1; if (!cr2_slice[0] || ecol > width-1) ecol = width & -2; for (row=0; row < height; row++) { ip = (short *) image[row*width+scol]; for (col=scol; col < ecol; col+=2, jcol+=4, ip+=8) { if ((jcol %= jwide) == 0) rp = (short *) ljpeg_row (jrow++, &jh); ip[0] = rp[jcol]; ip[4] = rp[jcol+1]; ip[1] = (short) (rp[jcol+2] << 2) >> 2; ip[2] = (short) (rp[jcol+3] << 2) >> 2; } } } for (row=0; row < height; row++) { ip = (short *) image[row*width+1]; for (col=1; col < width-1; col+=2, ip+=8) { ip[1] = (ip[-3] + ip[5] + 1) >> 1; ip[2] = (ip[-2] + ip[6] + 1) >> 1; } if (col < width) { ip[1] = ip[-3]; ip[2] = ip[-2]; } ip = (short *) image[row*width]; for (col=0; col < width; col++, ip+=4) { pix[0] = ip[2] + ip[0]; pix[2] = ip[1] + ip[0]; pix[1] = ((ip[0] << 12) - ip[1]*778 - (ip[2] << 11)) >> 12; FORC3 ip[c] = CLIP((pix[c] - 512) * sraw_mul[c] >> 10); } } free (jh.row); maximum = 0x3fff; } void CLASS adobe_copy_pixel (int row, int col, ushort **rp) { unsigned r, c; r = row -= top_margin; c = col -= left_margin; if (is_raw == 2 && shot_select) (*rp)++; if (filters) { if (fuji_width) { r = row + fuji_width - 1 - (col >> 1); c = row + ((col+1) >> 1); } if (r < height && c < width) BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp; *rp += is_raw; } else { if (r < height && c < width) FORC(tiff_samples) image[row*width+col][c] = (*rp)[c] < 0x1000 ? curve[(*rp)[c]]:(*rp)[c]; *rp += tiff_samples; } if (is_raw == 2 && shot_select) (*rp)--; } void CLASS adobe_dng_load_raw_lj() { unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col; struct jhead jh; ushort *rp; while (trow < raw_height) { save = ftell(ifp); if (tile_length < INT_MAX) fseek (ifp, get4(), SEEK_SET); if (!ljpeg_start (&jh, 0)) break; jwide = jh.wide; if (filters) jwide *= jh.clrs; jwide /= is_raw; for (row=col=jrow=0; jrow < jh.high; jrow++) { rp = ljpeg_row (jrow, &jh); for (jcol=0; jcol < jwide; jcol++) { adobe_copy_pixel (trow+row, tcol+col, &rp); if (++col >= tile_width || col >= raw_width) row += 1 + (col = 0); } } fseek (ifp, save+4, SEEK_SET); if ((tcol += tile_width) >= raw_width) trow += tile_length + (tcol = 0); free (jh.row); } } void CLASS adobe_dng_load_raw_nc() { ushort *pixel, *rp; int row, col; pixel = (ushort *) calloc (raw_width * tiff_samples, sizeof *pixel); merror (pixel, "adobe_dng_load_raw_nc()"); for (row=0; row < raw_height; row++) { if (tiff_bps == 16) read_shorts (pixel, raw_width * tiff_samples); else { getbits(-1); for (col=0; col < raw_width * tiff_samples; col++) pixel[col] = getbits(tiff_bps); } for (rp=pixel, col=0; col < raw_width; col++) adobe_copy_pixel (row, col, &rp); } free (pixel); } void CLASS pentax_k10_load_raw() { static const uchar pentax_tree[] = { 0,2,3,1,1,1,1,1,1,2,0,0,0,0,0,0, 3,4,2,5,1,6,0,7,8,9,10,11,12 }; int row, col, diff; ushort vpred[2][2] = {{0,0},{0,0}}, hpred[2]; init_decoder(); make_decoder (pentax_tree, 0); getbits(-1); for (row=0; row < height; row++) for (col=0; col < raw_width; col++) { diff = ljpeg_diff (first_decode); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; if (col < width) BAYER(row,col) = hpred[col & 1]; if (hpred[col & 1] >> 12) derror(); } } void CLASS nikon_compressed_load_raw() { static const uchar nikon_tree[][32] = { { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy */ 5,4,3,6,2,7,1,0,8,9,11,10,12 }, { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy after split */ 0x39,0x5a,0x38,0x27,0x16,5,4,3,2,1,0,11,12,12 }, { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, /* 12-bit lossless */ 5,4,6,3,7,2,8,1,9,0,10,11,12 }, { 0,1,4,3,1,1,1,1,1,2,0,0,0,0,0,0, /* 14-bit lossy */ 5,6,4,7,8,3,9,2,1,0,10,11,12,13,14 }, { 0,1,5,1,1,1,1,1,1,1,2,0,0,0,0,0, /* 14-bit lossy after split */ 8,0x5c,0x4b,0x3a,0x29,7,6,5,4,3,2,1,0,13,14 }, { 0,1,4,2,2,3,1,2,0,0,0,0,0,0,0,0, /* 14-bit lossless */ 7,6,8,5,9,4,10,3,11,12,2,0,1,13,14 } }; struct decode *dindex; ushort ver0, ver1, vpred[2][2], hpred[2], csize; int i, max, step=0, huff=0, split=0, row, col, len, shl, diff; fseek (ifp, meta_offset, SEEK_SET); ver0 = fgetc(ifp); ver1 = fgetc(ifp); if (ver0 == 0x49 || ver1 == 0x58) fseek (ifp, 2110, SEEK_CUR); if (ver0 == 0x46) huff = 2; if (tiff_bps == 14) huff += 3; read_shorts (vpred[0], 4); max = 1 << tiff_bps & 0x7fff; if ((csize = get2()) > 1) step = max / (csize-1); if (ver0 == 0x44 && ver1 == 0x20 && step > 0) { for (i=0; i < csize; i++) curve[i*step] = get2(); for (i=0; i < max; i++) curve[i] = ( curve[i-i%step]*(step-i%step) + curve[i-i%step+step]*(i%step) ) / step; fseek (ifp, meta_offset+562, SEEK_SET); split = get2(); } else if (ver0 != 0x46 && csize <= 0x4001) read_shorts (curve, max=csize); init_decoder(); make_decoder (nikon_tree[huff], 0); fseek (ifp, data_offset, SEEK_SET); getbits(-1); for (row=0; row < height; row++) { if (split && row == split) { init_decoder(); make_decoder (nikon_tree[huff+1], 0); } for (col=0; col < raw_width; col++) { for (dindex=first_decode; dindex->branch[0]; ) dindex = dindex->branch[getbits(1)]; len = dindex->leaf & 15; shl = dindex->leaf >> 4; diff = ((getbits(len-shl) << 1) + 1) << shl >> 1; if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - !shl; if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; if (hpred[col & 1] >= max) derror(); if ((unsigned) (col-left_margin) < width) BAYER(row,col-left_margin) = curve[hpred[col & 1] & 0x3fff]; } } } void CLASS nikon_load_raw() { int irow, row, col, i; getbits(-1); for (irow=0; irow < height; irow++) { row = irow; if (make[0] == 'O' || model[0] == 'E') { row = irow * 2 % height + irow / (height/2); if (row == 1 && data_offset == 0) { fseek (ifp, 0, SEEK_END); fseek (ifp, ftell(ifp)/2, SEEK_SET); getbits(-1); } } for (col=0; col < raw_width; col++) { i = getbits(12); if ((unsigned) (col-left_margin) < width) BAYER(row,col-left_margin) = i; if (tiff_compress > 32768 && (col % 10) == 9) if (getbits(8)) derror(); } } } /* Figure out if a NEF file is compressed. These fancy heuristics are only needed for the D100, thanks to a bug in some cameras that tags all images as "compressed". */ int CLASS nikon_is_compressed() { uchar test[256]; int i; fseek (ifp, data_offset, SEEK_SET); fread (test, 1, 256, ifp); for (i=15; i < 256; i+=16) if (test[i]) return 1; return 0; } /* Returns 1 for a Coolpix 995, 0 for anything else. */ int CLASS nikon_e995() { int i, histo[256]; const uchar often[] = { 0x00, 0x55, 0xaa, 0xff }; memset (histo, 0, sizeof histo); fseek (ifp, -2000, SEEK_END); for (i=0; i < 2000; i++) histo[fgetc(ifp)]++; for (i=0; i < 4; i++) if (histo[often[i]] < 200) return 0; return 1; } /* Returns 1 for a Coolpix 2100, 0 for anything else. */ int CLASS nikon_e2100() { uchar t[12]; int i; fseek (ifp, 0, SEEK_SET); for (i=0; i < 1024; i++) { fread (t, 1, 12, ifp); if (((t[2] & t[4] & t[7] & t[9]) >> 4 & t[1] & t[6] & t[8] & t[11] & 3) != 3) return 0; } return 1; } void CLASS nikon_3700() { int bits, i; uchar dp[24]; static const struct { int bits; char make[12], model[15]; } table[] = { { 0x00, "PENTAX", "Optio 33WR" }, { 0x03, "NIKON", "E3200" }, { 0x32, "NIKON", "E3700" }, { 0x33, "OLYMPUS", "C740UZ" } }; fseek (ifp, 3072, SEEK_SET); fread (dp, 1, 24, ifp); bits = (dp[8] & 3) << 4 | (dp[20] & 3); for (i=0; i < sizeof table / sizeof *table; i++) if (bits == table[i].bits) { strcpy (make, table[i].make ); strcpy (model, table[i].model); } } /* Separates a Minolta DiMAGE Z2 from a Nikon E4300. */ int CLASS minolta_z2() { int i; char tail[424]; fseek (ifp, -sizeof tail, SEEK_END); fread (tail, 1, sizeof tail, ifp); for (i=0; i < sizeof tail; i++) if (tail[i]) return 1; return 0; } /* Here raw_width is in bytes, not pixels. */ void CLASS nikon_e900_load_raw() { int offset=0, irow, row, col; for (irow=0; irow < height; irow++) { row = irow * 2 % height; if (row == 1) offset = - (-offset & -4096); fseek (ifp, offset, SEEK_SET); offset += raw_width; getbits(-1); for (col=0; col < width; col++) BAYER(row,col) = getbits(10); } } void CLASS nikon_e2100_load_raw() { uchar data[4608], *dp; ushort pixel[3072], *pix; int row, col; for (row=0; row <= height; row+=2) { if (row == height) { fseek (ifp, 0, SEEK_END); fseek (ifp, ftell(ifp)/2, SEEK_SET); row = 1; } fread (data, 1, width*3/2, ifp); for (dp=data, pix=pixel; pix < pixel+width; dp+=12, pix+=8) { pix[0] = (dp[2] >> 4) + (dp[ 3] << 4); pix[1] = (dp[2] << 8) + dp[ 1]; pix[2] = (dp[7] >> 4) + (dp[ 0] << 4); pix[3] = (dp[7] << 8) + dp[ 6]; pix[4] = (dp[4] >> 4) + (dp[ 5] << 4); pix[5] = (dp[4] << 8) + dp[11]; pix[6] = (dp[9] >> 4) + (dp[10] << 4); pix[7] = (dp[9] << 8) + dp[ 8]; } for (col=0; col < width; col++) BAYER(row,col) = (pixel[col] & 0xfff); } } /* The Fuji Super CCD is just a Bayer grid rotated 45 degrees. */ void CLASS fuji_load_raw() { ushort *pixel; int wide, row, col, r, c; fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR); wide = fuji_width << !fuji_layout; pixel = (ushort *) calloc (wide, sizeof *pixel); merror (pixel, "fuji_load_raw()"); for (row=0; row < raw_height; row++) { read_shorts (pixel, wide); fseek (ifp, 2*(raw_width - wide), SEEK_CUR); for (col=0; col < wide; col++) { if (fuji_layout) { r = fuji_width - 1 - col + (row >> 1); c = col + ((row+1) >> 1); } else { r = fuji_width - 1 + row - (col >> 1); c = row + ((col+1) >> 1); } BAYER(r,c) = pixel[col]; } } free (pixel); } void CLASS jpeg_thumb (FILE *tfp); void CLASS ppm_thumb (FILE *tfp) { char *thumb; thumb_length = thumb_width*thumb_height*3; thumb = (char *) malloc (thumb_length); merror (thumb, "ppm_thumb()"); fprintf (tfp, "P6\n%d %d\n255\n", thumb_width, thumb_height); fread (thumb, 1, thumb_length, ifp); fwrite (thumb, 1, thumb_length, tfp); free (thumb); } void CLASS layer_thumb (FILE *tfp) { int i, c; char *thumb, map[][4] = { "012","102" }; colors = thumb_misc >> 5 & 7; thumb_length = thumb_width*thumb_height; thumb = (char *) calloc (colors, thumb_length); merror (thumb, "layer_thumb()"); fprintf (tfp, "P%d\n%d %d\n255\n", 5 + (colors >> 1), thumb_width, thumb_height); fread (thumb, thumb_length, colors, ifp); for (i=0; i < thumb_length; i++) FORCC putc (thumb[i+thumb_length*(map[thumb_misc >> 8][c]-'0')], tfp); free (thumb); } void CLASS rollei_thumb (FILE *tfp) { unsigned i; ushort *thumb; thumb_length = thumb_width * thumb_height; thumb = (ushort *) calloc (thumb_length, 2); merror (thumb, "rollei_thumb()"); fprintf (tfp, "P6\n%d %d\n255\n", thumb_width, thumb_height); read_shorts (thumb, thumb_length); for (i=0; i < thumb_length; i++) { putc (thumb[i] << 3, tfp); putc (thumb[i] >> 5 << 2, tfp); putc (thumb[i] >> 11 << 3, tfp); } free (thumb); } void CLASS rollei_load_raw() { uchar pixel[10]; unsigned iten=0, isix, i, buffer=0, row, col, todo[16]; isix = raw_width * raw_height * 5 / 8; while (fread (pixel, 1, 10, ifp) == 10) { for (i=0; i < 10; i+=2) { todo[i] = iten++; todo[i+1] = pixel[i] << 8 | pixel[i+1]; buffer = pixel[i] >> 2 | buffer << 6; } for ( ; i < 16; i+=2) { todo[i] = isix++; todo[i+1] = buffer >> (14-i)*5; } for (i=0; i < 16; i+=2) { row = todo[i] / raw_width - top_margin; col = todo[i] % raw_width - left_margin; if (row < height && col < width) BAYER(row,col) = (todo[i+1] & 0x3ff); } } maximum = 0x3ff; } int CLASS bayer (unsigned row, unsigned col) { return (row < height && col < width) ? BAYER(row,col) : 0; } void CLASS phase_one_flat_field (int is_float, int nc) { ushort head[8]; unsigned wide, y, x, c, rend, cend, row, col; float *mrow, num, mult[4]; read_shorts (head, 8); wide = head[2] / head[4]; mrow = (float *) calloc (nc*wide, sizeof *mrow); merror (mrow, "phase_one_flat_field()"); for (y=0; y < head[3] / head[5]; y++) { for (x=0; x < wide; x++) for (c=0; c < nc; c+=2) { num = is_float ? getreal(11) : get2()/32768.0; if (y==0) mrow[c*wide+x] = num; else mrow[(c+1)*wide+x] = (num - mrow[c*wide+x]) / head[5]; } if (y==0) continue; rend = head[1]-top_margin + y*head[5]; for (row = rend-head[5]; row < height && row < rend; row++) { for (x=1; x < wide; x++) { for (c=0; c < nc; c+=2) { mult[c] = mrow[c*wide+x-1]; mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4]; } cend = head[0]-left_margin + x*head[4]; for (col = cend-head[4]; col < width && col < cend; col++) { c = nc > 2 ? FC(row,col) : 0; if (!(c & 1)) { c = BAYER(row,col) * mult[c]; BAYER(row,col) = LIM(c,0,65535); } for (c=0; c < nc; c+=2) mult[c] += mult[c+1]; } } for (x=0; x < wide; x++) for (c=0; c < nc; c+=2) mrow[c*wide+x] += mrow[(c+1)*wide+x]; } } free (mrow); } void CLASS phase_one_correct() { unsigned entries, tag, data, save, col, row, type; int len, i, j, k, cip, val[4], dev[4], sum, max; int head[9], diff, mindiff=INT_MAX, off_412=0; static const signed char dir[12][2] = { {-1,-1}, {-1,1}, {1,-1}, {1,1}, {-2,0}, {0,-2}, {0,2}, {2,0}, {-2,-2}, {-2,2}, {2,-2}, {2,2} }; float poly[8], num, cfrac, frac, mult[2], *yval[2]; ushort curve[0x10000], *xval[2]; if (half_size || !meta_length) return; if (verbose) fprintf (stderr,_("Phase One correction...\n")); fseek (ifp, meta_offset, SEEK_SET); order = get2(); fseek (ifp, 6, SEEK_CUR); fseek (ifp, meta_offset+get4(), SEEK_SET); entries = get4(); get4(); while (entries--) { tag = get4(); len = get4(); data = get4(); save = ftell(ifp); fseek (ifp, meta_offset+data, SEEK_SET); if (tag == 0x419) { /* Polynomial curve */ for (get4(), i=0; i < 8; i++) poly[i] = getreal(11); poly[3] += (ph1.tag_210 - poly[7]) * poly[6] + 1; for (i=0; i < 0x10000; i++) { num = (poly[5]*i + poly[3])*i + poly[1]; curve[i] = LIM(num,0,65535); } goto apply; /* apply to right half */ } else if (tag == 0x41a) { /* Polynomial curve */ for (i=0; i < 4; i++) poly[i] = getreal(11); for (i=0; i < 0x10000; i++) { for (num=0, j=4; j--; ) num = num * i + poly[j]; curve[i] = LIM(num+i,0,65535); } apply: /* apply to whole image */ for (row=0; row < height; row++) for (col = (tag & 1)*ph1.split_col; col < width; col++) BAYER(row,col) = curve[BAYER(row,col)]; } else if (tag == 0x400) { /* Sensor defects */ while ((len -= 8) >= 0) { col = get2() - left_margin; row = get2() - top_margin; type = get2(); get2(); if (col >= width) continue; if (type == 131) /* Bad column */ for (row=0; row < height; row++) if (FC(row,col) == 1) { for (sum=i=0; i < 4; i++) sum += val[i] = bayer (row+dir[i][0], col+dir[i][1]); for (max=i=0; i < 4; i++) { dev[i] = abs((val[i] << 2) - sum); if (dev[max] < dev[i]) max = i; } BAYER(row,col) = (sum - val[max])/3.0 + 0.5; } else { for (sum=0, i=8; i < 12; i++) sum += bayer (row+dir[i][0], col+dir[i][1]); BAYER(row,col) = 0.5 + sum * 0.0732233 + (bayer(row,col-2) + bayer(row,col+2)) * 0.3535534; } else if (type == 129) { /* Bad pixel */ if (row >= height) continue; j = (FC(row,col) != 1) * 4; for (sum=0, i=j; i < j+8; i++) sum += bayer (row+dir[i][0], col+dir[i][1]); BAYER(row,col) = (sum + 4) >> 3; } } } else if (tag == 0x401) { /* All-color flat fields */ phase_one_flat_field (1, 2); } else if (tag == 0x416 || tag == 0x410) { phase_one_flat_field (0, 2); } else if (tag == 0x40b) { /* Red+blue flat field */ phase_one_flat_field (0, 4); } else if (tag == 0x412) { fseek (ifp, 36, SEEK_CUR); diff = abs (get2() - ph1.tag_21a); if (mindiff > diff) { mindiff = diff; off_412 = ftell(ifp) - 38; } } fseek (ifp, save, SEEK_SET); } if (off_412) { fseek (ifp, off_412, SEEK_SET); for (i=0; i < 9; i++) head[i] = get4() & 0x7fff; yval[0] = (float *) calloc (head[1]*head[3] + head[2]*head[4], 6); merror (yval[0], "phase_one_correct()"); yval[1] = (float *) (yval[0] + head[1]*head[3]); xval[0] = (ushort *) (yval[1] + head[2]*head[4]); xval[1] = (ushort *) (xval[0] + head[1]*head[3]); get2(); for (i=0; i < 2; i++) for (j=0; j < head[i+1]*head[i+3]; j++) yval[i][j] = getreal(11); for (i=0; i < 2; i++) for (j=0; j < head[i+1]*head[i+3]; j++) xval[i][j] = get2(); for (row=0; row < height; row++) for (col=0; col < width; col++) { cfrac = (float) col * head[3] / raw_width; cfrac -= cip = cfrac; num = BAYER(row,col) * 0.5; for (i=cip; i < cip+2; i++) { for (k=j=0; j < head[1]; j++) if (num < xval[0][k = head[1]*i+j]) break; frac = (j == 0 || j == head[1]) ? 0 : (xval[0][k] - num) / (xval[0][k] - xval[0][k-1]); mult[i-cip] = yval[0][k-1] * frac + yval[0][k] * (1-frac); } i = ((mult[0] * (1-cfrac) + mult[1] * cfrac) * (row + top_margin) + num) * 2; BAYER(row,col) = LIM(i,0,65535); } free (yval[0]); } } void CLASS phase_one_load_raw() { int row, col, a, b; ushort *pixel, akey, bkey, mask; fseek (ifp, ph1.key_off, SEEK_SET); akey = get2(); bkey = get2(); mask = ph1.format == 1 ? 0x5555:0x1354; fseek (ifp, data_offset + top_margin*raw_width*2, SEEK_SET); pixel = (ushort *) calloc (raw_width, sizeof *pixel); merror (pixel, "phase_one_load_raw()"); for (row=0; row < height; row++) { read_shorts (pixel, raw_width); for (col=0; col < raw_width; col+=2) { a = pixel[col+0] ^ akey; b = pixel[col+1] ^ bkey; pixel[col+0] = (a & mask) | (b & ~mask); pixel[col+1] = (b & mask) | (a & ~mask); } for (col=0; col < width; col++) BAYER(row,col) = pixel[col+left_margin]; } free (pixel); phase_one_correct(); } unsigned CLASS ph1_bits (int nbits) { static UINT64 bitbuf=0; static int vbits=0; if (nbits == -1) return bitbuf = vbits = 0; if (nbits == 0) return 0; if (vbits < nbits) { bitbuf = bitbuf << 32 | get4(); vbits += 32; } vbits -= nbits; return bitbuf << (64-nbits-vbits) >> (64-nbits); } void CLASS phase_one_load_raw_c() { static const int length[] = { 8,7,6,9,11,10,5,12,14,13 }; int *offset, len[2], pred[2], row, col, i, j; ushort *pixel; short (*black)[2]; pixel = (ushort *) calloc (raw_width + raw_height*4, 2); merror (pixel, "phase_one_load_raw_c()"); offset = (int *) (pixel + raw_width); fseek (ifp, strip_offset, SEEK_SET); for (row=0; row < raw_height; row++) offset[row] = get4(); black = (short (*)[2]) offset + raw_height; fseek (ifp, ph1.black_off, SEEK_SET); if (ph1.black_off) read_shorts ((ushort *) black[0], raw_height*2); for (i=0; i < 256; i++) curve[i] = i*i / 3.969 + 0.5; for (row=0; row < raw_height; row++) { fseek (ifp, data_offset + offset[row], SEEK_SET); ph1_bits(-1); pred[0] = pred[1] = 0; for (col=0; col < raw_width; col++) { if (col >= (raw_width & -8)) len[0] = len[1] = 14; else if ((col & 7) == 0) for (i=0; i < 2; i++) { for (j=0; j < 5 && !ph1_bits(1); j++); if (j--) len[i] = length[j*2 + ph1_bits(1)]; } if ((i = len[col & 1]) == 14) pixel[col] = pred[col & 1] = ph1_bits(16); else pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1)); if (pred[col & 1] >> 16) derror(); if (ph1.format == 5 && pixel[col] < 256) pixel[col] = curve[pixel[col]]; } if ((unsigned) (row-top_margin) < height) for (col=0; col < width; col++) { i = (pixel[col+left_margin] << 2) - ph1.black + black[row][col >= ph1.split_col]; if (i > 0) BAYER(row-top_margin,col) = i; } } free (pixel); phase_one_correct(); maximum = 0xfffc - ph1.black; } void CLASS hasselblad_load_raw() { struct jhead jh; struct decode *dindex; int row, col, pred[2], len[2], diff, i; if (!ljpeg_start (&jh, 0)) return; free (jh.row); ph1_bits(-1); for (row=-top_margin; row < height; row++) { pred[0] = pred[1] = 0x8000; for (col=-left_margin; col < raw_width-left_margin; col+=2) { for (i=0; i < 2; i++) { for (dindex=jh.huff[0]; dindex->branch[0]; ) dindex = dindex->branch[ph1_bits(1)]; len[i] = dindex->leaf; } for (i=0; i < 2; i++) { diff = ph1_bits(len[i]); if ((diff & (1 << (len[i]-1))) == 0) diff -= (1 << len[i]) - 1; pred[i] += diff; if (row >= 0 && (unsigned)(col+i) < width) BAYER(row,col+i) = pred[i]; } } } maximum = 0xffff; } void CLASS leaf_hdr_load_raw() { ushort *pixel; unsigned tile=0, r, c, row, col; pixel = (ushort *) calloc (raw_width, sizeof *pixel); merror (pixel, "leaf_hdr_load_raw()"); FORC(tiff_samples) for (r=0; r < raw_height; r++) { if (r % tile_length == 0) { fseek (ifp, data_offset + 4*tile++, SEEK_SET); fseek (ifp, get4() + 2*left_margin, SEEK_SET); } if (filters && c != shot_select) continue; read_shorts (pixel, raw_width); if ((row = r - top_margin) >= height) continue; for (col=0; col < width; col++) if (filters) BAYER(row,col) = pixel[col]; else image[row*width+col][c] = pixel[col]; } free (pixel); if (!filters) { maximum = 0xffff; raw_color = 1; } } void CLASS unpacked_load_raw(); void CLASS sinar_4shot_load_raw() { ushort *pixel; unsigned shot, row, col, r, c; if ((shot = shot_select) || half_size) { if (shot) shot--; if (shot > 3) shot = 3; fseek (ifp, data_offset + shot*4, SEEK_SET); fseek (ifp, get4(), SEEK_SET); unpacked_load_raw(); return; } free (image); image = (ushort (*)[4]) calloc ((iheight=height)*(iwidth=width), sizeof *image); merror (image, "sinar_4shot_load_raw()"); pixel = (ushort *) calloc (raw_width, sizeof *pixel); merror (pixel, "sinar_4shot_load_raw()"); for (shot=0; shot < 4; shot++) { fseek (ifp, data_offset + shot*4, SEEK_SET); fseek (ifp, get4(), SEEK_SET); for (row=0; row < raw_height; row++) { read_shorts (pixel, raw_width); if ((r = row-top_margin - (shot >> 1 & 1)) >= height) continue; for (col=0; col < raw_width; col++) { if ((c = col-left_margin - (shot & 1)) >= width) continue; image[r*width+c][FC(row,col)] = pixel[col]; } } } free (pixel); shrink = filters = 0; } void CLASS imacon_full_load_raw() { int row, col; for (row=0; row < height; row++) for (col=0; col < width; col++) read_shorts (image[row*width+col], 3); } void CLASS packed_12_load_raw() { int row, col; if (raw_width * 2 < width * 3) raw_width = raw_width * 3 / 2; /* Convert raw_width to bytes */ getbits(-1); for (row=0; row < height; row++) { for (col=0; col < left_margin; col++) getbits(12); for (col=0; col < width; col++) BAYER(row,col) = getbits(12); for (col = (width+left_margin)*3/2; col < raw_width; col++) if (getbits(8) && raw_width-col < 35 && width != 3896) derror(); } } void CLASS unpacked_load_raw() { ushort *pixel; int row, col, bits=0; while (1 << ++bits < maximum); fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR); pixel = (ushort *) calloc (width, sizeof *pixel); merror (pixel, "unpacked_load_raw()"); for (row=0; row < height; row++) { read_shorts (pixel, width); fseek (ifp, 2*(raw_width - width), SEEK_CUR); for (col=0; col < width; col++) if ((BAYER2(row,col) = pixel[col]) >> bits) derror(); } free (pixel); } void CLASS nokia_load_raw() { uchar *data, *dp; ushort *pixel, *pix; int dwide, row, c; dwide = raw_width * 5 / 4; data = (uchar *) malloc (dwide + raw_width*2); merror (data, "nokia_load_raw()"); pixel = (ushort *) (data + dwide); for (row=0; row < raw_height; row++) { if (fread (data, 1, dwide, ifp) < dwide) derror(); for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=5, pix+=4) FORC4 pix[c] = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); if (row < top_margin) FORC(width) black += pixel[c]; else FORC(width) BAYER(row-top_margin,c) = pixel[c]; } free (data); if (top_margin) black /= top_margin * width; maximum = 0x3ff; } unsigned CLASS pana_bits (int nbits) { static uchar buf[16], vbits=0; if (!vbits && fread (buf, 1, 16, ifp) < 16) derror(); vbits = (vbits - nbits) & 127; return (buf[(vbits >> 3)+1] << 8 | buf[vbits >> 3]) >> (vbits & 7) & ~(-1 << nbits); } void CLASS panasonic_load_raw() { int row, col, i, j, sh=0, pred[2], nonz[2]; raw_width = (raw_width+13)/14*14; for (row=0; row < height; row++) for (col=0; col < raw_width; col++) { if ((i = col % 14) < 2) nonz[i] = pred[i] = pana_bits(12); else { if (i % 3 == 2) sh = 4 >> (3 - pana_bits(2)); if ((j = pana_bits(8))) { if ((pred[i & 1] -= 0x80 << sh) < 0 || sh == 4) pred[i & 1] &= ~(-1 << sh); pred[i & 1] += nonz[i & 1] ? j << sh : j; nonz[i & 1] = 1; } } if (col < width) if ((BAYER(row,col) = pred[col & 1]) >> 12) derror(); } } void CLASS olympus_e300_load_raw() { uchar *data, *dp; ushort *pixel, *pix; int dwide, row, col; dwide = raw_width * 16 / 10; fseek (ifp, dwide*top_margin, SEEK_CUR); data = (uchar *) malloc (dwide + raw_width*2); merror (data, "olympus_e300_load_raw()"); pixel = (ushort *) (data + dwide); for (row=0; row < height; row++) { if (fread (data, 1, dwide, ifp) < dwide) derror(); for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=3, pix+=2) { if (((dp-data) & 15) == 15) if (*dp++ && pix < pixel+width+left_margin) derror(); pix[0] = dp[1] << 8 | dp[0]; pix[1] = dp[2] << 4 | dp[1] >> 4; } for (col=0; col < width; col++) BAYER(row,col) = (pixel[col+left_margin] & 0xfff); } free (data); maximum >>= 4; black >>= 4; } void CLASS olympus_e410_load_raw() { int row, col, nbits, sign, low, high, i, w, n, nw; int acarry[2][3], *carry, pred, diff; fseek (ifp, 7, SEEK_CUR); getbits(-1); for (row=0; row < height; row++) { memset (acarry, 0, sizeof acarry); for (col=0; col < width; col++) { carry = acarry[col & 1]; i = 2 * (carry[2] < 3); for (nbits=2+i; (ushort) carry[0] >> (nbits+i); nbits++); sign = getbits(1) * -1; low = getbits(2); for (high=0; high < 12; high++) if (getbits(1)) break; if (high == 12) high = getbits(16-nbits) >> 1; carry[0] = (high << nbits) | getbits(nbits); diff = (carry[0] ^ sign) + carry[1]; carry[1] = (diff*3 + carry[1]) >> 5; carry[2] = carry[0] > 16 ? 0 : carry[2]+1; if (row < 2 && col < 2) pred = 0; else if (row < 2) pred = BAYER(row,col-2); else if (col < 2) pred = BAYER(row-2,col); else { w = BAYER(row,col-2); n = BAYER(row-2,col); nw = BAYER(row-2,col-2); if ((w < nw && nw < n) || (n < nw && nw < w)) { if (ABS(w-nw) > 32 || ABS(n-nw) > 32) pred = w + n - nw; else pred = (w + n) >> 1; } else pred = ABS(w-nw) > ABS(n-nw) ? w : n; } if ((BAYER(row,col) = pred + ((diff << 2) | low)) >> 12) derror(); } } } void CLASS olympus_cseries_load_raw() { int irow, row, col; for (irow=0; irow < height; irow++) { row = irow * 2 % height + irow / (height/2); if (row < 2) { fseek (ifp, data_offset - row*(-width*height*3/4 & -2048), SEEK_SET); getbits(-1); } for (col=0; col < width; col++) BAYER(row,col) = getbits(12); } black >>= 4; } void CLASS minolta_rd175_load_raw() { uchar pixel[768]; unsigned irow, box, row, col; for (irow=0; irow < 1481; irow++) { if (fread (pixel, 1, 768, ifp) < 768) derror(); box = irow / 82; row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box-12)*2); switch (irow) { case 1477: case 1479: continue; case 1476: row = 984; break; case 1480: row = 985; break; case 1478: row = 985; box = 1; } if ((box < 12) && (box & 1)) { for (col=0; col < 1533; col++, row ^= 1) if (col != 1) BAYER(row,col) = (col+1) & 2 ? pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1; BAYER(row,1) = pixel[1] << 1; BAYER(row,1533) = pixel[765] << 1; } else for (col=row & 1; col < 1534; col+=2) BAYER(row,col) = pixel[col/2] << 1; } maximum = 0xff << 1; } void CLASS casio_qv5700_load_raw() { uchar data[3232], *dp; ushort pixel[2576], *pix; int row, col; for (row=0; row < height; row++) { fread (data, 1, 3232, ifp); for (dp=data, pix=pixel; dp < data+3220; dp+=5, pix+=4) { pix[0] = (dp[0] << 2) + (dp[1] >> 6); pix[1] = (dp[1] << 4) + (dp[2] >> 4); pix[2] = (dp[2] << 6) + (dp[3] >> 2); pix[3] = (dp[3] << 8) + (dp[4] ); } for (col=0; col < width; col++) BAYER(row,col) = (pixel[col] & 0x3ff); } maximum = 0x3fc; } void CLASS quicktake_100_load_raw() { uchar pixel[484][644]; static const short gstep[16] = { -89,-60,-44,-32,-22,-15,-8,-2,2,8,15,22,32,44,60,89 }; static const short rstep[6][4] = { { -3,-1,1,3 }, { -5,-1,1,5 }, { -8,-2,2,8 }, { -13,-3,3,13 }, { -19,-4,4,19 }, { -28,-6,6,28 } }; static const short curve[256] = { 0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, 28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53, 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,74,75,76,77,78, 79,80,81,82,83,84,86,88,90,92,94,97,99,101,103,105,107,110,112,114,116, 118,120,123,125,127,129,131,134,136,138,140,142,144,147,149,151,153,155, 158,160,162,164,166,168,171,173,175,177,179,181,184,186,188,190,192,195, 197,199,201,203,205,208,210,212,214,216,218,221,223,226,230,235,239,244, 248,252,257,261,265,270,274,278,283,287,291,296,300,305,309,313,318,322, 326,331,335,339,344,348,352,357,361,365,370,374,379,383,387,392,396,400, 405,409,413,418,422,426,431,435,440,444,448,453,457,461,466,470,474,479, 483,487,492,496,500,508,519,531,542,553,564,575,587,598,609,620,631,643, 654,665,676,687,698,710,721,732,743,754,766,777,788,799,810,822,833,844, 855,866,878,889,900,911,922,933,945,956,967,978,989,1001,1012,1023 }; int rb, row, col, sharp, val=0; getbits(-1); memset (pixel, 0x80, sizeof pixel); for (row=2; row < height+2; row++) { for (col=2+(row & 1); col < width+2; col+=2) { val = ((pixel[row-1][col-1] + 2*pixel[row-1][col+1] + pixel[row][col-2]) >> 2) + gstep[getbits(4)]; pixel[row][col] = val = LIM(val,0,255); if (col < 4) pixel[row][col-2] = pixel[row+1][~row & 1] = val; if (row == 2) pixel[row-1][col+1] = pixel[row-1][col+3] = val; } pixel[row][col] = val; } for (rb=0; rb < 2; rb++) for (row=2+rb; row < height+2; row+=2) for (col=3-(row & 1); col < width+2; col+=2) { if (row < 4 || col < 4) sharp = 2; else { val = ABS(pixel[row-2][col] - pixel[row][col-2]) + ABS(pixel[row-2][col] - pixel[row-2][col-2]) + ABS(pixel[row][col-2] - pixel[row-2][col-2]); sharp = val < 4 ? 0 : val < 8 ? 1 : val < 16 ? 2 : val < 32 ? 3 : val < 48 ? 4 : 5; } val = ((pixel[row-2][col] + pixel[row][col-2]) >> 1) + rstep[sharp][getbits(2)]; pixel[row][col] = val = LIM(val,0,255); if (row < 4) pixel[row-2][col+2] = val; if (col < 4) pixel[row+2][col-2] = val; } for (row=2; row < height+2; row++) for (col=3-(row & 1); col < width+2; col+=2) { val = ((pixel[row][col-1] + (pixel[row][col] << 2) + pixel[row][col+1]) >> 1) - 0x100; pixel[row][col] = LIM(val,0,255); } for (row=0; row < height; row++) for (col=0; col < width; col++) BAYER(row,col) = curve[pixel[row+2][col+2]]; maximum = 0x3ff; } const int * CLASS make_decoder_int (const int *source, int level) { struct decode *cur; cur = free_decode++; if (level < source[0]) { cur->branch[0] = free_decode; source = make_decoder_int (source, level+1); cur->branch[1] = free_decode; source = make_decoder_int (source, level+1); } else { cur->leaf = source[1]; source += 2; } return source; } int CLASS radc_token (int tree) { int t; static struct decode *dstart[18], *dindex; static const int *s, source[] = { 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8, 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8, 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8, 2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8, 2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8, 2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8, 2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8, 2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8, 2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4, 2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8, 1,0, 2,2, 2,-2, 1,-3, 1,3, 2,-17, 2,-5, 2,5, 2,17, 2,-7, 2,2, 2,9, 2,18, 2,-18, 2,-9, 2,-2, 2,7, 2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79, 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76, 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37 }; if (free_decode == first_decode) for (s=source, t=0; t < 18; t++) { dstart[t] = free_decode; s = make_decoder_int (s, 0); } if (tree == 18) { if (kodak_cbpp == 243) return (getbits(6) << 2) + 2; /* most DC50 photos */ else return (getbits(5) << 3) + 4; /* DC40, Fotoman Pixtura */ } for (dindex = dstart[tree]; dindex->branch[0]; ) dindex = dindex->branch[getbits(1)]; return dindex->leaf; } #define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--) #define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \ : (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) void CLASS kodak_radc_load_raw() { int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; init_decoder(); getbits(-1); for (i=0; i < sizeof(buf)/sizeof(short); i++) buf[0][0][i] = 2048; for (row=0; row < height; row+=4) { FORC3 mul[c] = getbits(6); FORC3 { val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c]; s = val > 65564 ? 10:12; x = ~(-1 << (s-1)); val <<= 12-s; for (i=0; i < sizeof(buf[0])/sizeof(short); i++) buf[c][0][i] = (buf[c][0][i] * val + x) >> s; last[c] = mul[c]; for (r=0; r <= !c; r++) { buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; for (tree=1, col=width/2; col > 0; ) { if ((tree = radc_token(tree))) { col -= 2; if (tree == 8) FORYX buf[c][y][x] = radc_token(tree+10) * mul[c]; else FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR; } else do { nreps = (col > 2) ? radc_token(9) + 1 : 1; for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) { col -= 2; FORYX buf[c][y][x] = PREDICTOR; if (rep & 1) { step = radc_token(10) << 4; FORYX buf[c][y][x] += step; } } } while (nreps == 9); } for (y=0; y < 2; y++) for (x=0; x < width/2; x++) { val = (buf[c][y+1][x] << 4) / mul[c]; if (val < 0) val = 0; if (c) BAYER(row+y*2+c-1,x*2+2-c) = val; else BAYER(row+r*2+y,x*2+y) = val; } memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); } } for (y=row; y < row+4; y++) for (x=0; x < width; x++) if ((x+y) & 1) { r = x ? x-1 : x+1; s = x+1 < width ? x+1 : x-1; val = (BAYER(y,x)-2048)*2 + (BAYER(y,r)+BAYER(y,s))/2; if (val < 0) val = 0; BAYER(y,x) = val; } } maximum = 0xfff; use_gamma = 0; } #undef FORYX #undef PREDICTOR #ifdef NO_JPEG void CLASS kodak_jpeg_load_raw() {} #else METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo) { static uchar jpeg_buffer[4096]; size_t nbytes; nbytes = fread (jpeg_buffer, 1, 4096, ifp); swab (jpeg_buffer, jpeg_buffer, nbytes); cinfo->src->next_input_byte = jpeg_buffer; cinfo->src->bytes_in_buffer = nbytes; return TRUE; } void CLASS kodak_jpeg_load_raw() { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY buf; JSAMPLE (*pixel)[3]; int row, col; cinfo.err = jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); jpeg_stdio_src (&cinfo, ifp); cinfo.src->fill_input_buffer = fill_input_buffer; jpeg_read_header (&cinfo, TRUE); jpeg_start_decompress (&cinfo); if ((cinfo.output_width != width ) || (cinfo.output_height*2 != height ) || (cinfo.output_components != 3 )) { fprintf (stderr,_("%s: incorrect JPEG dimensions\n"), ifname); jpeg_destroy_decompress (&cinfo); longjmp (failure, 3); } buf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1); while (cinfo.output_scanline < cinfo.output_height) { row = cinfo.output_scanline * 2; jpeg_read_scanlines (&cinfo, buf, 1); pixel = (JSAMPLE (*)[3]) buf[0]; for (col=0; col < width; col+=2) { BAYER(row+0,col+0) = pixel[col+0][1] << 1; BAYER(row+1,col+1) = pixel[col+1][1] << 1; BAYER(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; BAYER(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; } } jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); maximum = 0xff << 1; } #endif void CLASS kodak_dc120_load_raw() { static const int mul[4] = { 162, 192, 187, 92 }; static const int add[4] = { 0, 636, 424, 212 }; uchar pixel[848]; int row, shift, col; for (row=0; row < height; row++) { if (fread (pixel, 1, 848, ifp) < 848) derror(); shift = row * mul[row & 3] + add[row & 3]; for (col=0; col < width; col++) BAYER(row,col) = (ushort) pixel[(col + shift) % 848]; } maximum = 0xff; } void CLASS eight_bit_load_raw() { uchar *pixel; unsigned row, col, val, lblack=0; pixel = (uchar *) calloc (raw_width, sizeof *pixel); merror (pixel, "eight_bit_load_raw()"); fseek (ifp, top_margin*raw_width, SEEK_CUR); for (row=0; row < height; row++) { if (fread (pixel, 1, raw_width, ifp) < raw_width) derror(); for (col=0; col < raw_width; col++) { val = curve[pixel[col]]; if ((unsigned) (col-left_margin) < width) BAYER(row,col-left_margin) = val; else lblack += val; } } free (pixel); if (raw_width > width+1) black = lblack / ((raw_width - width) * height); if (!strncmp(model,"DC2",3)) black = 0; maximum = curve[0xff]; } void CLASS kodak_262_load_raw() { static const uchar kodak_tree[2][26] = { { 0,1,5,1,1,2,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 }, { 0,3,1,1,1,1,1,2,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 } }; struct decode *decode[2]; uchar *pixel; int *strip, ns, i, row, col, chess, pi=0, pi1, pi2, pred, val; init_decoder(); for (i=0; i < 2; i++) { decode[i] = free_decode; make_decoder (kodak_tree[i], 0); } ns = (raw_height+63) >> 5; pixel = (uchar *) malloc (raw_width*32 + ns*4); merror (pixel, "kodak_262_load_raw()"); strip = (int *) (pixel + raw_width*32); order = 0x4d4d; for (i=0; i < ns; i++) strip[i] = get4(); for (row=0; row < raw_height; row++) { if ((row & 31) == 0) { fseek (ifp, strip[row >> 5], SEEK_SET); getbits(-1); pi = 0; } for (col=0; col < raw_width; col++) { chess = (row + col) & 1; pi1 = chess ? pi-2 : pi-raw_width-1; pi2 = chess ? pi-2*raw_width : pi-raw_width+1; if (col <= chess) pi1 = -1; if (pi1 < 0) pi1 = pi2; if (pi2 < 0) pi2 = pi1; if (pi1 < 0 && col > 1) pi1 = pi2 = pi-2; pred = (pi1 < 0) ? 0 : (pixel[pi1] + pixel[pi2]) >> 1; pixel[pi] = val = pred + ljpeg_diff (decode[chess]); if (val >> 8) derror(); val = curve[pixel[pi++]]; if ((unsigned) (col-left_margin) < width) BAYER(row,col-left_margin) = val; else black += val; } } free (pixel); if (raw_width > width) black /= (raw_width - width) * height; } int CLASS kodak_65000_decode (short *out, int bsize) { uchar c, blen[768]; ushort raw[6]; INT64 bitbuf=0; int save, bits=0, i, j, len, diff; save = ftell(ifp); bsize = (bsize + 3) & -4; for (i=0; i < bsize; i+=2) { c = fgetc(ifp); if ((blen[i ] = c & 15) > 12 || (blen[i+1] = c >> 4) > 12 ) { fseek (ifp, save, SEEK_SET); for (i=0; i < bsize; i+=8) { read_shorts (raw, 6); out[i ] = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12; out[i+1] = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12; for (j=0; j < 6; j++) out[i+2+j] = raw[j] & 0xfff; } return 1; } } if ((bsize & 7) == 4) { bitbuf = fgetc(ifp) << 8; bitbuf += fgetc(ifp); bits = 16; } for (i=0; i < bsize; i++) { len = blen[i]; if (bits < len) { for (j=0; j < 32; j+=8) bitbuf += (INT64) fgetc(ifp) << (bits+(j^8)); bits += 32; } diff = bitbuf & (0xffff >> (16-len)); bitbuf >>= len; bits -= len; if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; out[i] = diff; } return 0; } void CLASS kodak_65000_load_raw() { short buf[256]; int row, col, len, pred[2], ret, i; for (row=0; row < height; row++) for (col=0; col < width; col+=256) { pred[0] = pred[1] = 0; len = MIN (256, width-col); ret = kodak_65000_decode (buf, len); for (i=0; i < len; i++) if ((BAYER(row,col+i) = curve[ret ? buf[i] : (pred[i & 1] += buf[i])]) >> 12) derror(); } } void CLASS kodak_ycbcr_load_raw() { short buf[384], *bp; int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3]; ushort *ip; for (row=0; row < height; row+=2) for (col=0; col < width; col+=128) { len = MIN (128, width-col); kodak_65000_decode (buf, len*3); y[0][1] = y[1][1] = cb = cr = 0; for (bp=buf, i=0; i < len; i+=2, bp+=2) { cb += bp[4]; cr += bp[5]; rgb[1] = -((cb + cr + 2) >> 2); rgb[2] = rgb[1] + cb; rgb[0] = rgb[1] + cr; for (j=0; j < 2; j++) for (k=0; k < 2; k++) { if ((y[j][k] = y[j][k^1] + *bp++) >> 10) derror(); ip = image[(row+j)*width + col+i+k]; FORC3 ip[c] = curve[LIM(y[j][k]+rgb[c], 0, 0xfff)]; } } } } void CLASS kodak_rgb_load_raw() { short buf[768], *bp; int row, col, len, c, i, rgb[3]; ushort *ip=image[0]; for (row=0; row < height; row++) for (col=0; col < width; col+=256) { len = MIN (256, width-col); kodak_65000_decode (buf, len*3); memset (rgb, 0, sizeof rgb); for (bp=buf, i=0; i < len; i++, ip+=4) FORC3 if ((ip[c] = rgb[c] += *bp++) >> 12) derror(); } } void CLASS kodak_thumb_load_raw() { int row, col; colors = thumb_misc >> 5; for (row=0; row < height; row++) for (col=0; col < width; col++) read_shorts (image[row*width+col], colors); maximum = (1 << (thumb_misc & 31)) - 1; } void CLASS sony_decrypt (unsigned *data, int len, int start, int key) { static unsigned pad[128], p; if (start) { for (p=0; p < 4; p++) pad[p] = key = key * 48828125 + 1; pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31; for (p=4; p < 127; p++) pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31; for (p=0; p < 127; p++) pad[p] = htonl(pad[p]); } while (len--) *data++ ^= pad[p++ & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127]; } void CLASS sony_load_raw() { uchar head[40]; ushort *pixel; unsigned i, key, row, col; fseek (ifp, 200896, SEEK_SET); fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR); order = 0x4d4d; key = get4(); fseek (ifp, 164600, SEEK_SET); fread (head, 1, 40, ifp); sony_decrypt ((unsigned int *) head, 10, 1, key); for (i=26; i-- > 22; ) key = key << 8 | head[i]; fseek (ifp, data_offset, SEEK_SET); pixel = (ushort *) calloc (raw_width, sizeof *pixel); merror (pixel, "sony_load_raw()"); for (row=0; row < height; row++) { if (fread (pixel, 2, raw_width, ifp) < raw_width) derror(); sony_decrypt ((unsigned int *) pixel, raw_width/2, !row, key); for (col=9; col < left_margin; col++) black += ntohs(pixel[col]); for (col=0; col < width; col++) if ((BAYER(row,col) = ntohs(pixel[col+left_margin])) >> 14) derror(); } free (pixel); if (left_margin > 9) black /= (left_margin-9) * height; maximum = 0x3ff0; } void CLASS sony_arw_load_raw() { int col, row, len, diff, sum=0; getbits(-1); for (col = raw_width; col--; ) for (row=0; row < raw_height+1; row+=2) { if (row == raw_height) row = 1; len = 4 - getbits(2); if (len == 3 && getbits(1)) len = 0; if (len == 4) while (len < 17 && !getbits(1)) len++; diff = getbits(len); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; if ((sum += diff) >> 12) derror(); if (row < height) BAYER(row,col) = sum; } } void CLASS sony_arw2_load_raw() { uchar *data, *dp; ushort pix[16]; int row, col, val, max, min, imax, imin, sh, bit, i; data = (uchar *) malloc (raw_width*tiff_bps >> 3); merror (data, "sony_arw2_load_raw()"); for (row=0; row < height; row++) { fread (data, 1, raw_width*tiff_bps >> 3, ifp); if (tiff_bps == 8) { for (dp=data, col=0; col < width-30; dp+=16) { max = 0x7ff & (val = sget4(dp)); min = 0x7ff & val >> 11; imax = 0x0f & val >> 22; imin = 0x0f & val >> 26; for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = max; else if (i == imin) pix[i] = min; else { pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; if (pix[i] > 0x7ff) pix[i] = 0x7ff; bit += 7; } for (i=0; i < 16; i++, col+=2) BAYER(row,col) = curve[pix[i] << 1] >> 1; col -= col & 1 ? 1:31; } } else if (tiff_bps == 12) for (dp=data, col=0; col < width; dp+=3, col+=2) { BAYER(row,col) = ((dp[1] << 8 | dp[0]) & 0xfff) << 1; BAYER(row,col+1) = (dp[2] << 4 | dp[1] >> 4) << 1; } } free (data); } #define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) /* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ void CLASS smal_decode_segment (unsigned seg[2][2], int holes) { uchar hist[3][13] = { { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, { 3, 3, 0, 0, 63, 47, 31, 15, 0 } }; int low, high=0xff, carry=0, nbits=8; int s, count, bin, next, i, sym[3]; uchar diff, pred[]={0,0}; ushort data=0, range=0; unsigned pix, row, col; fseek (ifp, seg[0][1]+1, SEEK_SET); getbits(-1); for (pix=seg[0][0]; pix < seg[1][0]; pix++) { for (s=0; s < 3; s++) { data = data << nbits | getbits(nbits); if (carry < 0) carry = (nbits += carry+1) < 1 ? nbits-1 : 0; while (--nbits >= 0) if ((data >> nbits & 0xff) == 0xff) break; if (nbits > 0) data = ((data & ((1 << (nbits-1)) - 1)) << 1) | ((data + (((data & (1 << (nbits-1)))) << 1)) & (-1 << nbits)); if (nbits >= 0) { data += getbits(1); carry = nbits - 8; } count = ((((data-range+1) & 0xffff) << 2) - 1) / (high >> 4); for (bin=0; hist[s][bin+5] > count; bin++); low = hist[s][bin+5] * (high >> 4) >> 2; if (bin) high = hist[s][bin+4] * (high >> 4) >> 2; high -= low; for (nbits=0; high << nbits < 128; nbits++); range = (range+low) << nbits; high <<= nbits; next = hist[s][1]; if (++hist[s][2] > hist[s][3]) { next = (next+1) & hist[s][0]; hist[s][3] = (hist[s][next+4] - hist[s][next+5]) >> 2; hist[s][2] = 1; } if (hist[s][hist[s][1]+4] - hist[s][hist[s][1]+5] > 1) { if (bin < hist[s][1]) for (i=bin; i < hist[s][1]; i++) hist[s][i+5]--; else if (next <= bin) for (i=hist[s][1]; i < bin; i++) hist[s][i+5]++; } hist[s][1] = next; sym[s] = bin; } diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3); if (sym[0] & 4) diff = diff ? -diff : 0x80; if (ftell(ifp) + 12 >= seg[1][1]) diff = 0; pred[pix & 1] += diff; row = pix / raw_width - top_margin; col = pix % raw_width - left_margin; if (row < height && col < width) BAYER(row,col) = pred[pix & 1]; if (!(pix & 1) && HOLE(row)) pix += 2; } maximum = 0xff; } void CLASS smal_v6_load_raw() { unsigned seg[2][2]; fseek (ifp, 16, SEEK_SET); seg[0][0] = 0; seg[0][1] = get2(); seg[1][0] = raw_width * raw_height; seg[1][1] = INT_MAX; smal_decode_segment (seg, 0); use_gamma = 0; } int CLASS median4 (int *p) { int min, max, sum, i; min = max = sum = p[0]; for (i=1; i < 4; i++) { sum += p[i]; if (min > p[i]) min = p[i]; if (max < p[i]) max = p[i]; } return (sum - min - max) >> 1; } void CLASS fill_holes (int holes) { int row, col, val[4]; for (row=2; row < height-2; row++) { if (!HOLE(row)) continue; for (col=1; col < width-1; col+=4) { val[0] = BAYER(row-1,col-1); val[1] = BAYER(row-1,col+1); val[2] = BAYER(row+1,col-1); val[3] = BAYER(row+1,col+1); BAYER(row,col) = median4(val); } for (col=2; col < width-2; col+=4) if (HOLE(row-2) || HOLE(row+2)) BAYER(row,col) = (BAYER(row,col-2) + BAYER(row,col+2)) >> 1; else { val[0] = BAYER(row,col-2); val[1] = BAYER(row,col+2); val[2] = BAYER(row-2,col); val[3] = BAYER(row+2,col); BAYER(row,col) = median4(val); } } } void CLASS smal_v9_load_raw() { unsigned seg[256][2], offset, nseg, holes, i; fseek (ifp, 67, SEEK_SET); offset = get4(); nseg = fgetc(ifp); fseek (ifp, offset, SEEK_SET); for (i=0; i < nseg*2; i++) seg[0][i] = get4() + data_offset*(i & 1); fseek (ifp, 78, SEEK_SET); holes = fgetc(ifp); fseek (ifp, 88, SEEK_SET); seg[nseg][0] = raw_height * raw_width; seg[nseg][1] = get4() + data_offset; for (i=0; i < nseg; i++) smal_decode_segment (seg+i, holes); if (holes) fill_holes (holes); } /* RESTRICTED code starts here */ void CLASS foveon_decoder (unsigned size, unsigned code) { static unsigned huff[1024]; struct decode *cur; int i, len; if (!code) { for (i=0; i < size; i++) huff[i] = get4(); init_decoder(); } cur = free_decode++; if (free_decode > first_decode+2048) { fprintf (stderr,_("%s: decoder table overflow\n"), ifname); longjmp (failure, 2); } if (code) for (i=0; i < size; i++) if (huff[i] == code) { cur->leaf = i; return; } if ((len = code >> 27) > 26) return; code = (len+1) << 27 | (code & 0x3ffffff) << 1; cur->branch[0] = free_decode; foveon_decoder (size, code); cur->branch[1] = free_decode; foveon_decoder (size, code+1); } void CLASS foveon_thumb (FILE *tfp) { unsigned bwide, row, col, bitbuf=0, bit=1, c, i; char *buf; struct decode *dindex; short pred[3]; bwide = get4(); fprintf (tfp, "P6\n%d %d\n255\n", thumb_width, thumb_height); if (bwide > 0) { if (bwide < thumb_width*3) return; buf = (char *) malloc (bwide); merror (buf, "foveon_thumb()"); for (row=0; row < thumb_height; row++) { fread (buf, 1, bwide, ifp); fwrite (buf, 3, thumb_width, tfp); } free (buf); return; } foveon_decoder (256, 0); for (row=0; row < thumb_height; row++) { memset (pred, 0, sizeof pred); if (!bit) get4(); for (bit=col=0; col < thumb_width; col++) FORC3 { for (dindex=first_decode; dindex->branch[0]; ) { if ((bit = (bit-1) & 31) == 31) for (i=0; i < 4; i++) bitbuf = (bitbuf << 8) + fgetc(ifp); dindex = dindex->branch[bitbuf >> bit & 1]; } pred[c] += dindex->leaf; fputc (pred[c], tfp); } } } void CLASS foveon_load_camf() { unsigned key, i, val; fseek (ifp, meta_offset, SEEK_SET); key = get4(); fread (meta_data, 1, meta_length, ifp); for (i=0; i < meta_length; i++) { key = (key * 1597 + 51749) % 244944; val = key * (INT64) 301593171 >> 24; meta_data[i] ^= ((((key << 8) - val) >> 1) + val) >> 17; } } void CLASS foveon_load_raw() { struct decode *dindex; short diff[1024]; unsigned bitbuf=0; int pred[3], fixed, row, col, bit=-1, c, i; fixed = get4(); read_shorts ((ushort *) diff, 1024); if (!fixed) foveon_decoder (1024, 0); for (row=0; row < height; row++) { memset (pred, 0, sizeof pred); if (!bit && !fixed && atoi(model+2) < 14) get4(); for (col=bit=0; col < width; col++) { if (fixed) { bitbuf = get4(); FORC3 pred[2-c] += diff[bitbuf >> c*10 & 0x3ff]; } else FORC3 { for (dindex=first_decode; dindex->branch[0]; ) { if ((bit = (bit-1) & 31) == 31) for (i=0; i < 4; i++) bitbuf = (bitbuf << 8) + fgetc(ifp); dindex = dindex->branch[bitbuf >> bit & 1]; } pred[c] += diff[dindex->leaf]; if (pred[c] >> 16 && ~pred[c] >> 16) derror(); } FORC3 image[row*width+col][c] = pred[c]; } } if (document_mode) for (i=0; i < height*width*4; i++) if ((short) image[0][i] < 0) image[0][i] = 0; foveon_load_camf(); } const char * CLASS foveon_camf_param (const char *block, const char *param) { unsigned idx, num; char *pos, *cp, *dp; for (idx=0; idx < meta_length; idx += sget4(pos+8)) { pos = meta_data + idx; if (strncmp (pos, "CMb", 3)) break; if (pos[3] != 'P') continue; if (strcmp (block, pos+sget4(pos+12))) continue; cp = pos + sget4(pos+16); num = sget4(cp); dp = pos + sget4(cp+4); while (num--) { cp += 8; if (!strcmp (param, dp+sget4(cp))) return dp+sget4(cp+4); } } return 0; } void * CLASS foveon_camf_matrix (unsigned dim[3], const char *name) { unsigned i, idx, type, ndim, size, *mat; char *pos, *cp, *dp; double dsize; for (idx=0; idx < meta_length; idx += sget4(pos+8)) { pos = meta_data + idx; if (strncmp (pos, "CMb", 3)) break; if (pos[3] != 'M') continue; if (strcmp (name, pos+sget4(pos+12))) continue; dim[0] = dim[1] = dim[2] = 1; cp = pos + sget4(pos+16); type = sget4(cp); if ((ndim = sget4(cp+4)) > 3) break; dp = pos + sget4(cp+8); for (i=ndim; i--; ) { cp += 12; dim[i] = sget4(cp); } if ((dsize = (double) dim[0]*dim[1]*dim[2]) > meta_length/4) break; mat = (unsigned *) malloc ((size = dsize) * 4); merror (mat, "foveon_camf_matrix()"); for (i=0; i < size; i++) if (type && type != 6) mat[i] = sget4(dp + i*4); else mat[i] = sget4(dp + i*2) & 0xffff; return mat; } fprintf (stderr,_("%s: \"%s\" matrix not found!\n"), ifname, name); return 0; } int CLASS foveon_fixed (void *ptr, int size, const char *name) { void *dp; unsigned dim[3]; dp = foveon_camf_matrix (dim, name); if (!dp) return 0; memcpy (ptr, dp, size*4); free (dp); return 1; } float CLASS foveon_avg (short *pix, int range[2], float cfilt) { int i; float val, min=FLT_MAX, max=-FLT_MAX, sum=0; for (i=range[0]; i <= range[1]; i++) { sum += val = pix[i*4] + (pix[i*4]-pix[(i-1)*4]) * cfilt; if (min > val) min = val; if (max < val) max = val; } if (range[1] - range[0] == 1) return sum/2; return (sum - min - max) / (range[1] - range[0] - 1); } short * CLASS foveon_make_curve (double max, double mul, double filt) { short *curve; unsigned i, size; double x; if (!filt) filt = 0.8; size = 4*M_PI*max / filt; if (size == UINT_MAX) size--; curve = (short *) calloc (size+1, sizeof *curve); merror (curve, "foveon_make_curve()"); curve[0] = size; for (i=0; i < size; i++) { x = i*filt/max/4; curve[i+1] = (cos(x)+1)/2 * tanh(i*filt/mul) * mul + 0.5; } return curve; } void CLASS foveon_make_curves (short **curvep, float dq[3], float div[3], float filt) { double mul[3], max=0; int c; FORC3 mul[c] = dq[c]/div[c]; FORC3 if (max < mul[c]) max = mul[c]; FORC3 curvep[c] = foveon_make_curve (max, mul[c], filt); } int CLASS foveon_apply_curve (short *curve, int i) { if (abs(i) >= curve[0]) return 0; return i < 0 ? -curve[1-i] : curve[1+i]; } #define image ((short (*)[4]) image) void CLASS foveon_interpolate() { static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 }; short *pix, prev[3], *curve[8], (*shrink)[3]; float cfilt=0, ddft[3][3][2], ppm[3][3][3]; float cam_xyz[3][3], correct[3][3], last[3][3], trans[3][3]; float chroma_dq[3], color_dq[3], diag[3][3], div[3]; float (*black)[3], (*sgain)[3], (*sgrow)[3]; float fsum[3], val, frow, num; int row, col, c, i, j, diff, sgx, irow, sum, min, max, limit; int dscr[2][2], dstb[4], (*smrow[7])[3], total[4], ipix[3]; int work[3][3], smlast, smred, smred_p=0, dev[3]; int satlev[3], keep[4], active[4]; unsigned dim[3], *badpix; double dsum=0, trsum[3]; char str[128]; const char* cp; if (verbose) fprintf (stderr,_("Foveon interpolation...\n")); foveon_fixed (dscr, 4, "DarkShieldColRange"); foveon_fixed (ppm[0][0], 27, "PostPolyMatrix"); foveon_fixed (satlev, 3, "SaturationLevel"); foveon_fixed (keep, 4, "KeepImageArea"); foveon_fixed (active, 4, "ActiveImageArea"); foveon_fixed (chroma_dq, 3, "ChromaDQ"); foveon_fixed (color_dq, 3, foveon_camf_param ("IncludeBlocks", "ColorDQ") ? "ColorDQ" : "ColorDQCamRGB"); if (foveon_camf_param ("IncludeBlocks", "ColumnFilter")) foveon_fixed (&cfilt, 1, "ColumnFilter"); memset (ddft, 0, sizeof ddft); if (!foveon_camf_param ("IncludeBlocks", "DarkDrift") || !foveon_fixed (ddft[1][0], 12, "DarkDrift")) for (i=0; i < 2; i++) { foveon_fixed (dstb, 4, i ? "DarkShieldBottom":"DarkShieldTop"); for (row = dstb[1]; row <= dstb[3]; row++) for (col = dstb[0]; col <= dstb[2]; col++) FORC3 ddft[i+1][c][1] += (short) image[row*width+col][c]; FORC3 ddft[i+1][c][1] /= (dstb[3]-dstb[1]+1) * (dstb[2]-dstb[0]+1); } if (!(cp = foveon_camf_param ("WhiteBalanceIlluminants", model2))) { fprintf (stderr,_("%s: Invalid white balance \"%s\"\n"), ifname, model2); return; } foveon_fixed (cam_xyz, 9, cp); foveon_fixed (correct, 9, foveon_camf_param ("WhiteBalanceCorrections", model2)); memset (last, 0, sizeof last); for (i=0; i < 3; i++) for (j=0; j < 3; j++) FORC3 last[i][j] += correct[i][c] * cam_xyz[c][j]; #define LAST(x,y) last[(i+x)%3][(c+y)%3] for (i=0; i < 3; i++) FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1); #undef LAST FORC3 div[c] = diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583; sprintf (str, "%sRGBNeutral", model2); if (foveon_camf_param ("IncludeBlocks", str)) foveon_fixed (div, 3, str); num = 0; FORC3 if (num < div[c]) num = div[c]; FORC3 div[c] /= num; memset (trans, 0, sizeof trans); for (i=0; i < 3; i++) for (j=0; j < 3; j++) FORC3 trans[i][j] += rgb_cam[i][c] * last[c][j] * div[j]; FORC3 trsum[c] = trans[c][0] + trans[c][1] + trans[c][2]; dsum = (6*trsum[0] + 11*trsum[1] + 3*trsum[2]) / 20; for (i=0; i < 3; i++) FORC3 last[i][c] = trans[i][c] * dsum / trsum[i]; memset (trans, 0, sizeof trans); for (i=0; i < 3; i++) for (j=0; j < 3; j++) FORC3 trans[i][j] += (i==c ? 32 : -1) * last[c][j] / 30; foveon_make_curves (curve, color_dq, div, cfilt); FORC3 chroma_dq[c] /= 3; foveon_make_curves (curve+3, chroma_dq, div, cfilt); FORC3 dsum += chroma_dq[c] / div[c]; curve[6] = foveon_make_curve (dsum, dsum, cfilt); curve[7] = foveon_make_curve (dsum*2, dsum*2, cfilt); sgain = (float (*)[3]) foveon_camf_matrix (dim, "SpatialGain"); if (!sgain) return; sgrow = (float (*)[3]) calloc (dim[1], sizeof *sgrow); sgx = (width + dim[1]-2) / (dim[1]-1); black = (float (*)[3]) calloc (height, sizeof *black); for (row=0; row < height; row++) { for (i=0; i < 6; i++) ddft[0][0][i] = ddft[1][0][i] + row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); FORC3 black[row][c] = ( foveon_avg (image[row*width]+c, dscr[0], cfilt) + foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3 - ddft[0][c][0] ) / 4 - ddft[0][c][1]; } memcpy (black, black+8, sizeof *black*8); memcpy (black+height-11, black+height-22, 11*sizeof *black); memcpy (last, black, sizeof last); for (row=1; row < height-1; row++) { FORC3 if (last[1][c] > last[0][c]) { if (last[1][c] > last[2][c]) black[row][c] = (last[0][c] > last[2][c]) ? last[0][c]:last[2][c]; } else if (last[1][c] < last[2][c]) black[row][c] = (last[0][c] < last[2][c]) ? last[0][c]:last[2][c]; memmove (last, last+1, 2*sizeof last[0]); memcpy (last[2], black[row+1], sizeof last[2]); } FORC3 black[row][c] = (last[0][c] + last[1][c])/2; FORC3 black[0][c] = (black[1][c] + black[3][c])/2; val = 1 - exp(-1/24.0); memcpy (fsum, black, sizeof fsum); for (row=1; row < height; row++) FORC3 fsum[c] += black[row][c] = (black[row][c] - black[row-1][c])*val + black[row-1][c]; memcpy (last[0], black[height-1], sizeof last[0]); FORC3 fsum[c] /= height; for (row = height; row--; ) FORC3 last[0][c] = black[row][c] = (black[row][c] - fsum[c] - last[0][c])*val + last[0][c]; memset (total, 0, sizeof total); for (row=2; row < height; row+=4) for (col=2; col < width; col+=4) { FORC3 total[c] += (short) image[row*width+col][c]; total[3]++; } for (row=0; row < height; row++) FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0); for (row=0; row < height; row++) { for (i=0; i < 6; i++) ddft[0][0][i] = ddft[1][0][i] + row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); pix = image[row*width]; memcpy (prev, pix, sizeof prev); frow = row / (height-1.0) * (dim[2]-1); if ((irow = frow) == dim[2]-1) irow--; frow -= irow; for (i=0; i < dim[1]; i++) FORC3 sgrow[i][c] = sgain[ irow *dim[1]+i][c] * (1-frow) + sgain[(irow+1)*dim[1]+i][c] * frow; for (col=0; col < width; col++) { FORC3 { diff = pix[c] - prev[c]; prev[c] = pix[c]; ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt - ddft[0][c][1] - ddft[0][c][0] * ((float) col/width - 0.5) - black[row][c] ); } FORC3 { work[0][c] = ipix[c] * ipix[c] >> 14; work[2][c] = ipix[c] * work[0][c] >> 14; work[1][2-c] = ipix[(c+1) % 3] * ipix[(c+2) % 3] >> 14; } FORC3 { for (val=i=0; i < 3; i++) for ( j=0; j < 3; j++) val += ppm[c][i][j] * work[i][j]; ipix[c] = floor ((ipix[c] + floor(val)) * ( sgrow[col/sgx ][c] * (sgx - col%sgx) + sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / div[c]); if (ipix[c] > 32000) ipix[c] = 32000; pix[c] = ipix[c]; } pix += 4; } } free (black); free (sgrow); free (sgain); if ((badpix = (unsigned int *) foveon_camf_matrix (dim, "BadPixels"))) { for (i=0; i < dim[0]; i++) { col = (badpix[i] >> 8 & 0xfff) - keep[0]; row = (badpix[i] >> 20 ) - keep[1]; if ((unsigned)(row-1) > height-3 || (unsigned)(col-1) > width-3) continue; memset (fsum, 0, sizeof fsum); for (sum=j=0; j < 8; j++) if (badpix[i] & (1 << j)) { FORC3 fsum[c] += (short) image[(row+hood[j*2])*width+col+hood[j*2+1]][c]; sum++; } if (sum) FORC3 image[row*width+col][c] = fsum[c]/sum; } free (badpix); } /* Array for 5x5 Gaussian averaging of red values */ smrow[6] = (int (*)[3]) calloc (width*5, sizeof **smrow); merror (smrow[6], "foveon_interpolate()"); for (i=0; i < 5; i++) smrow[i] = smrow[6] + i*width; /* Sharpen the reds against these Gaussian averages */ for (smlast=-1, row=2; row < height-2; row++) { while (smlast < row+2) { for (i=0; i < 6; i++) smrow[(i+5) % 6] = smrow[i]; pix = image[++smlast*width+2]; for (col=2; col < width-2; col++) { smrow[4][col][0] = (pix[0]*6 + (pix[-4]+pix[4])*4 + pix[-8]+pix[8] + 8) >> 4; pix += 4; } } pix = image[row*width+2]; for (col=2; col < width-2; col++) { smred = ( 6 * smrow[2][col][0] + 4 * (smrow[1][col][0] + smrow[3][col][0]) + smrow[0][col][0] + smrow[4][col][0] + 8 ) >> 4; if (col == 2) smred_p = smred; i = pix[0] + ((pix[0] - ((smred*7 + smred_p) >> 3)) >> 3); if (i > 32000) i = 32000; pix[0] = i; smred_p = smred; pix += 4; } } /* Adjust the brighter pixels for better linearity */ min = 0xffff; FORC3 { i = satlev[c] / div[c]; if (min > i) min = i; } limit = min * 9 >> 4; for (pix=image[0]; pix < image[height*width]; pix+=4) { if (pix[0] <= limit || pix[1] <= limit || pix[2] <= limit) continue; min = max = pix[0]; for (c=1; c < 3; c++) { if (min > pix[c]) min = pix[c]; if (max < pix[c]) max = pix[c]; } if (min >= limit*2) { pix[0] = pix[1] = pix[2] = max; } else { i = 0x4000 - ((min - limit) << 14) / limit; i = 0x4000 - (i*i >> 14); i = i*i >> 14; FORC3 pix[c] += (max - pix[c]) * i >> 14; } } /* Because photons that miss one detector often hit another, the sum R+G+B is much less noisy than the individual colors. So smooth the hues without smoothing the total. */ for (smlast=-1, row=2; row < height-2; row++) { while (smlast < row+2) { for (i=0; i < 6; i++) smrow[(i+5) % 6] = smrow[i]; pix = image[++smlast*width+2]; for (col=2; col < width-2; col++) { FORC3 smrow[4][col][c] = (pix[c-4]+2*pix[c]+pix[c+4]+2) >> 2; pix += 4; } } pix = image[row*width+2]; for (col=2; col < width-2; col++) { FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] - ((smrow[1][col][c] + 2*smrow[2][col][c] + smrow[3][col][c]) >> 2)); sum = (dev[0] + dev[1] + dev[2]) >> 3; FORC3 pix[c] += dev[c] - sum; pix += 4; } } for (smlast=-1, row=2; row < height-2; row++) { while (smlast < row+2) { for (i=0; i < 6; i++) smrow[(i+5) % 6] = smrow[i]; pix = image[++smlast*width+2]; for (col=2; col < width-2; col++) { FORC3 smrow[4][col][c] = (pix[c-8]+pix[c-4]+pix[c]+pix[c+4]+pix[c+8]+2) >> 2; pix += 4; } } pix = image[row*width+2]; for (col=2; col < width-2; col++) { for (total[3]=375, sum=60, c=0; c < 3; c++) { for (total[c]=i=0; i < 5; i++) total[c] += smrow[i][col][c]; total[3] += total[c]; sum += pix[c]; } if (sum < 0) sum = 0; j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174; FORC3 pix[c] += foveon_apply_curve (curve[6], ((j*total[c] + 0x8000) >> 16) - pix[c]); pix += 4; } } /* Transform the image to a different colorspace */ for (pix=image[0]; pix < image[height*width]; pix+=4) { FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]); sum = (pix[0]+pix[1]+pix[1]+pix[2]) >> 2; FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]-sum); FORC3 { for (dsum=i=0; i < 3; i++) dsum += trans[c][i] * pix[i]; if (dsum < 0) dsum = 0; if (dsum > 24000) dsum = 24000; ipix[c] = dsum + 0.5; } FORC3 pix[c] = ipix[c]; } /* Smooth the image bottom-to-top and save at 1/4 scale */ shrink = (short (*)[3]) calloc ((width/4) * (height/4), sizeof *shrink); merror (shrink, "foveon_interpolate()"); for (row = height/4; row--; ) for (col=0; col < width/4; col++) { ipix[0] = ipix[1] = ipix[2] = 0; for (i=0; i < 4; i++) for (j=0; j < 4; j++) FORC3 ipix[c] += image[(row*4+i)*width+col*4+j][c]; FORC3 if (row+2 > height/4) shrink[row*(width/4)+col][c] = ipix[c] >> 4; else shrink[row*(width/4)+col][c] = (shrink[(row+1)*(width/4)+col][c]*1840 + ipix[c]*141 + 2048) >> 12; } /* From the 1/4-scale image, smooth right-to-left */ for (row=0; row < (height & ~3); row++) { ipix[0] = ipix[1] = ipix[2] = 0; if ((row & 3) == 0) for (col = width & ~3 ; col--; ) FORC3 smrow[0][col][c] = ipix[c] = (shrink[(row/4)*(width/4)+col/4][c]*1485 + ipix[c]*6707 + 4096) >> 13; /* Then smooth left-to-right */ ipix[0] = ipix[1] = ipix[2] = 0; for (col=0; col < (width & ~3); col++) FORC3 smrow[1][col][c] = ipix[c] = (smrow[0][col][c]*1485 + ipix[c]*6707 + 4096) >> 13; /* Smooth top-to-bottom */ if (row == 0) memcpy (smrow[2], smrow[1], sizeof **smrow * width); else for (col=0; col < (width & ~3); col++) FORC3 smrow[2][col][c] = (smrow[2][col]