TDE graphics utilities
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

480 lines
13KB

  1. /* Fax file input processing
  2. Copyright (C) 1990, 1995 Frank D. Cringle.
  3. This file is part of viewfax - g3/g4 fax processing software.
  4. viewfax is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by the
  6. Free Software Foundation; either version 2 of the License, or (at your
  7. option) any later version.
  8. This program is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <unistd.h>
  18. #include <errno.h>
  19. #include <string.h>
  20. #include <sys/stat.h>
  21. #include <sys/time.h>
  22. #include <fcntl.h>
  23. #include "faxexpand.h"
  24. #include <tqstring.h>
  25. #include <tqfile.h>
  26. #include <kapplication.h>
  27. #include <klocale.h>
  28. #include <kdebug.h>
  29. void statusbarupdate(char* name,int width,int height,char* res);
  30. extern void kfaxerror(const TQString& title, const TQString& error);
  31. #define FAXMAGIC "\000PC Research, Inc\000\000\000\000\000\000"
  32. /* Enter an argument in the linked list of pages */
  33. struct pagenode *
  34. notefile(const char *name, int type)
  35. {
  36. struct pagenode *newnode = (struct pagenode *) xmalloc(sizeof *newnode);
  37. *newnode = defaultpage;
  38. if (firstpage == NULL){
  39. firstpage = newnode;
  40. auxpage = firstpage;
  41. }
  42. newnode->prev = lastpage;
  43. newnode->next = NULL;
  44. if (lastpage != NULL)
  45. lastpage->next = newnode;
  46. lastpage = newnode;
  47. // kdDebug() << "Adding new node " << newnode << endl;
  48. newnode->pathname = (char*) malloc (strlen(name) +1);
  49. if(!newnode->pathname){
  50. kfaxerror(i18n("Sorry"),i18n("Out of memory\n"));
  51. exit(1);
  52. }
  53. strcpy(newnode->pathname,name);
  54. newnode->type = type;
  55. if ((newnode->name = strrchr(newnode->pathname, '/')) != NULL)
  56. newnode->name++;
  57. else
  58. newnode->name = newnode->pathname;
  59. if (newnode->width == 0)
  60. newnode->width = 1728;
  61. if (newnode->vres < 0)
  62. newnode->vres = !(newnode->name[0] == 'f' && newnode->name[1] == 'n');
  63. newnode->extra = NULL;
  64. return newnode;
  65. }
  66. static t32bits
  67. get4(unsigned char *p, int endian)
  68. {
  69. return endian ? (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3] :
  70. p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
  71. }
  72. static int
  73. get2(unsigned char *p, int endian)
  74. {
  75. return endian ? (p[0]<<8)|p[1] : p[0]|(p[1]<<8);
  76. }
  77. /* generate pagenodes for the images in a tiff file */
  78. int
  79. notetiff(const char *name)
  80. {
  81. FILE *tf;
  82. unsigned char header[8];
  83. static const char littleTIFF[5] = "\x49\x49\x2a\x00";
  84. static const char bigTIFF[5] = "\x4d\x4d\x00\x2a";
  85. int endian;
  86. t32bits IFDoff;
  87. struct pagenode *pn = NULL;
  88. TQString str;
  89. if ((tf = fopen(name, "r")) == NULL) {
  90. TQString mesg = i18n("Unable to open:\n%1\n").arg(TQFile::decodeName(name));
  91. kfaxerror(i18n("Sorry"), mesg);
  92. return 0;
  93. }
  94. if (fread(header, 8, 1, tf) == 0) {
  95. nottiff:
  96. fclose(tf);
  97. (void) notefile(name,FAX_RAW);
  98. return 0;
  99. }
  100. if (memcmp(header, &littleTIFF, 4) == 0)
  101. endian = 0;
  102. else if (memcmp(header, &bigTIFF, 4) == 0)
  103. endian = 1;
  104. else
  105. goto nottiff;
  106. IFDoff = get4(header+4, endian);
  107. if (IFDoff & 1)
  108. goto nottiff;
  109. do { /* for each page */
  110. unsigned char buf[8];
  111. unsigned char *dir = NULL , *dp = NULL;
  112. int ndirent;
  113. pixnum iwidth = defaultpage.width ? defaultpage.width : 1728;
  114. pixnum iheight = defaultpage.height ? defaultpage.height : 2339;
  115. int inverse = defaultpage.inverse;
  116. int lsbfirst = 0;
  117. int t4opt = 0, comp = 0;
  118. int orient = defaultpage.orient;
  119. double yres = defaultpage.vres ? 196.0 : 98.0;
  120. struct strip *strips = NULL;
  121. unsigned long rowsperstrip = 0;
  122. t32bits nstrips = 1;
  123. if (fseek(tf, IFDoff, SEEK_SET) < 0) {
  124. realbad:
  125. str = i18n("Invalid tiff file:\n%1\n").arg(TQFile::decodeName(name));
  126. kfaxerror(i18n("Sorry"),str);
  127. bad:
  128. if (strips)
  129. free(strips);
  130. if (dir)
  131. free(dir);
  132. fclose(tf);
  133. return 1;
  134. }
  135. if (fread(buf, 2, 1, tf) == 0)
  136. goto realbad;
  137. ndirent = get2(buf, endian);
  138. dir = (unsigned char *) xmalloc(12*ndirent+4);
  139. if (fread(dir, 12*ndirent+4, 1, tf) == 0)
  140. goto realbad;
  141. for (dp = dir; ndirent; ndirent--, dp += 12) {
  142. /* for each directory entry */
  143. int tag, ftype;
  144. t32bits count, value = 0;
  145. tag = get2(dp, endian);
  146. ftype = get2(dp+2, endian);
  147. count = get4(dp+4, endian);
  148. switch(ftype) { /* value is offset to list if count*size > 4 */
  149. case 3: /* short */
  150. value = get2(dp+8, endian);
  151. break;
  152. case 4: /* long */
  153. value = get4(dp+8, endian);
  154. break;
  155. case 5: /* offset to rational */
  156. value = get4(dp+8, endian);
  157. break;
  158. }
  159. switch(tag) {
  160. case 256: /* ImageWidth */
  161. iwidth = value;
  162. break;
  163. case 257: /* ImageLength */
  164. iheight = value;
  165. break;
  166. case 259: /* Compression */
  167. comp = value;
  168. break;
  169. case 262: /* PhotometricInterpretation */
  170. inverse ^= (value == 1);
  171. break;
  172. case 266: /* FillOrder */
  173. lsbfirst = (value == 2);
  174. break;
  175. case 273: /* StripOffsets */
  176. nstrips = count;
  177. strips = (struct strip *) xmalloc(count * sizeof *strips);
  178. if (count == 1 || (count == 2 && ftype == 3)) {
  179. strips[0].offset = value;
  180. if (count == 2)
  181. strips[1].offset = get2(dp+10, endian);
  182. break;
  183. }
  184. if (fseek(tf, value, SEEK_SET) < 0)
  185. goto realbad;
  186. for (count = 0; count < nstrips; count++) {
  187. if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 0)
  188. goto realbad;
  189. strips[count].offset = (ftype == 3) ?
  190. get2(buf, endian) : get4(buf, endian);
  191. }
  192. break;
  193. case 274: /* Qt::Orientation */
  194. switch(value) {
  195. default: /* row0 at top, col0 at left */
  196. orient = 0;
  197. break;
  198. case 2: /* row0 at top, col0 at right */
  199. orient = TURN_M;
  200. break;
  201. case 3: /* row0 at bottom, col0 at right */
  202. orient = TURN_U;
  203. break;
  204. case 4: /* row0 at bottom, col0 at left */
  205. orient = TURN_U|TURN_M;
  206. break;
  207. case 5: /* row0 at left, col0 at top */
  208. orient = TURN_M|TURN_L;
  209. break;
  210. case 6: /* row0 at right, col0 at top */
  211. orient = TURN_U|TURN_L;
  212. break;
  213. case 7: /* row0 at right, col0 at bottom */
  214. orient = TURN_U|TURN_M|TURN_L;
  215. break;
  216. case 8: /* row0 at left, col0 at bottom */
  217. orient = TURN_L;
  218. break;
  219. }
  220. break;
  221. case 278: /* RowsPerStrip */
  222. rowsperstrip = value;
  223. break;
  224. case 279: /* StripByteCounts */
  225. if (count != nstrips) {
  226. str = i18n("In file %1\nStripsPerImage tag 273=%2,tag279=%3\n")
  227. .arg(TQFile::decodeName(name)).arg(nstrips).arg(count);
  228. kfaxerror(i18n("Message"),str);
  229. goto realbad;
  230. }
  231. if (count == 1 || (count == 2 && ftype == 3)) {
  232. strips[0].size = value;
  233. if (count == 2)
  234. strips[1].size = get2(dp+10, endian);
  235. break;
  236. }
  237. if (fseek(tf, value, SEEK_SET) < 0)
  238. goto realbad;
  239. for (count = 0; count < nstrips; count++) {
  240. if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 0)
  241. goto realbad;
  242. strips[count].size = (ftype == 3) ?
  243. get2(buf, endian) : get4(buf, endian);
  244. }
  245. break;
  246. case 283: /* YResolution */
  247. if (fseek(tf, value, SEEK_SET) < 0 ||
  248. fread(buf, 8, 1, tf) == 0)
  249. goto realbad;
  250. yres = get4(buf, endian) / get4(buf+4, endian);
  251. break;
  252. case 292: /* T4Options */
  253. t4opt = value;
  254. break;
  255. case 293: /* T6Options */
  256. /* later */
  257. break;
  258. case 296: /* ResolutionUnit */
  259. if (value == 3)
  260. yres *= 2.54;
  261. break;
  262. }
  263. }
  264. IFDoff = get4(dp, endian);
  265. free(dir);
  266. dir = NULL;
  267. if (comp == 5) {
  268. // compression type 5 is LZW compression
  269. kfaxerror(i18n("Sorry"),i18n("Due to patent reasons KFax can not handle LZW (Lempel-Ziv & Welch) "
  270. "compressed Fax files.\n"));
  271. goto bad;
  272. }
  273. if (comp < 2 || comp > 4) {
  274. kfaxerror(i18n("Sorry"),i18n("This version can only handle Fax files\n"));
  275. goto bad;
  276. }
  277. pn = notefile(name,FAX_TIFF);
  278. pn->nstrips = nstrips;
  279. pn->rowsperstrip = nstrips > 1 ? rowsperstrip : iheight;
  280. pn->strips = strips;
  281. pn->width = iwidth;
  282. pn->height = iheight;
  283. pn->inverse = inverse;
  284. pn->lsbfirst = lsbfirst;
  285. pn->orient = orient;
  286. pn->vres = (yres > 150); /* arbitrary threshold for fine resolution */
  287. if (comp == 2)
  288. pn->expander = MHexpand;
  289. else if (comp == 3)
  290. pn->expander = (t4opt & 1) ? g32expand : g31expand;
  291. else
  292. pn->expander = g4expand;
  293. } while (IFDoff);
  294. fclose(tf);
  295. return 1;
  296. }
  297. /* report error and remove bad file from the list */
  298. static void
  299. badfile(struct pagenode *pn)
  300. {
  301. struct pagenode *p;
  302. if (errno)
  303. perror(pn->pathname);
  304. if (pn == firstpage) {
  305. if (pn->next == NULL){
  306. kfaxerror(i18n("Sorry"),i18n("Bad Fax File"));
  307. return;
  308. }
  309. else{
  310. firstpage = thispage = firstpage->next;
  311. firstpage->prev = NULL;
  312. }
  313. }
  314. else
  315. for (p = firstpage; p; p = p->next)
  316. if (p->next == pn) {
  317. thispage = p;
  318. p->next = pn->next;
  319. if (pn->next)
  320. pn->next->prev = p;
  321. break;
  322. }
  323. if (pn) free(pn);
  324. pn = NULL;
  325. }
  326. /* rearrange input bits into t16bits lsb-first chunks */
  327. static void
  328. normalize(struct pagenode *pn, int revbits, int swapbytes, size_t length)
  329. {
  330. t32bits *p = (t32bits *) pn->data;
  331. switch ((revbits<<1)|swapbytes) {
  332. case 0:
  333. break;
  334. case 1:
  335. for ( ; length; length -= 4) {
  336. t32bits t = *p;
  337. *p++ = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
  338. }
  339. break;
  340. case 2:
  341. for ( ; length; length -= 4) {
  342. t32bits t = *p;
  343. t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
  344. t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
  345. *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
  346. }
  347. break;
  348. case 3:
  349. for ( ; length; length -= 4) {
  350. t32bits t = *p;
  351. t = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
  352. t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
  353. t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
  354. *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
  355. }
  356. }
  357. }
  358. /* get compressed data into memory */
  359. unsigned char *
  360. getstrip(struct pagenode *pn, int strip)
  361. {
  362. int fd;
  363. size_t offset, roundup;
  364. struct stat sbuf;
  365. unsigned char *Data;
  366. union { t16bits s; unsigned char b[2]; } so;
  367. TQString str;
  368. #define ShortOrder so.b[1]
  369. so.s = 1;
  370. if ((fd = open(pn->pathname, O_RDONLY, 0)) < 0) {
  371. badfile(pn);
  372. return NULL;
  373. }
  374. if (pn->strips == NULL) {
  375. if (fstat(fd, &sbuf) != 0) {
  376. close(fd);
  377. badfile(pn);
  378. return NULL;
  379. }
  380. offset = 0;
  381. pn->length = sbuf.st_size;
  382. }
  383. else if (strip < pn->nstrips) {
  384. offset = pn->strips[strip].offset;
  385. pn->length = pn->strips[strip].size;
  386. }
  387. else {
  388. str = i18n("Trying to expand too many strips\n%1%n").arg(TQFile::decodeName(pn->pathname));
  389. kfaxerror(i18n("Warning"),str);
  390. return NULL;
  391. }
  392. /* round size to full boundary plus t32bits */
  393. roundup = (pn->length + 7) & ~3;
  394. Data = (unsigned char *) xmalloc(roundup);
  395. /* clear the last 2 t32bits, to force the expander to terminate
  396. even if the file ends in the middle of a fax line */
  397. *((t32bits *) Data + roundup/4 - 2) = 0;
  398. *((t32bits *) Data + roundup/4 - 1) = 0;
  399. /* we expect to get it in one gulp... */
  400. if (lseek(fd, offset, SEEK_SET) < 0 ||
  401. (uint) read(fd, Data, pn->length) != pn->length) {
  402. badfile(pn);
  403. free(Data);
  404. close(fd);
  405. return NULL;
  406. }
  407. close(fd);
  408. pn->data = (t16bits *) Data;
  409. if (pn->strips == NULL && memcmp(Data, FAXMAGIC, sizeof(FAXMAGIC)) == 0) {
  410. /* handle ghostscript / PC Research fax file */
  411. if (Data[24] != 1 || Data[25] != 0){
  412. str = i18n("Only the first page of the PC Research multipage file\n%1\nwill be shown\n")
  413. .arg(TQFile::decodeName(pn->pathname));
  414. kfaxerror(i18n("Message"),str);
  415. }
  416. pn->length -= 64;
  417. pn->vres = Data[29];
  418. pn->data += 32;
  419. roundup -= 64;
  420. }
  421. normalize(pn, !pn->lsbfirst, ShortOrder, roundup);
  422. if (pn->height == 0)
  423. pn->height = G3count(pn, pn->expander == g32expand);
  424. if (pn->height == 0) {
  425. str = i18n("No fax found in file:\n%1\n").arg(TQFile::decodeName(pn->pathname));
  426. kfaxerror(i18n("Sorry"),str);
  427. errno = 0;
  428. badfile(pn);
  429. free(Data);
  430. return NULL;
  431. }
  432. if (pn->strips == NULL)
  433. pn->rowsperstrip = pn->height;
  434. if (verbose && strip == 0)
  435. kdWarning() << pn->name << "\n\twidth = " << pn->width << "\n\theight = "
  436. << pn->height << "\n\tresolution = " << (pn->vres ? "fine" : "normal") << endl;
  437. // statusbarupdate(pn->name,pn->width,pn->height,pn->vres ? "fine" : "normal");
  438. return Data;
  439. }