PageRenderTime 62ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/Source/System/Image/FileIO/OSGGIFImageFileType.cpp

https://github.com/msteners/OpenSGDevMaster_Toolbox
C++ | 2188 lines | 1472 code | 324 blank | 392 comment | 257 complexity | 74bcb18a183c1325f76a96256b127897 MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause
  1. /*---------------------------------------------------------------------------*\
  2. * OpenSG *
  3. * *
  4. * *
  5. * Copyright (C) 2000-2002 by the OpenSG Forum *
  6. * *
  7. * www.opensg.org *
  8. * *
  9. * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
  10. * *
  11. \*---------------------------------------------------------------------------*/
  12. /*---------------------------------------------------------------------------*\
  13. * License *
  14. * *
  15. * This library is free software; you can redistribute it and/or modify it *
  16. * under the terms of the GNU Library General Public License as published *
  17. * by the Free Software Foundation, version 2. *
  18. * *
  19. * This library is distributed in the hope that it will be useful, but *
  20. * WITHOUT ANY WARRANTY; without even the implied warranty of *
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
  22. * Library General Public License for more details. *
  23. * *
  24. * You should have received a copy of the GNU Library General Public *
  25. * License along with this library; if not, write to the Free Software *
  26. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
  27. * *
  28. \*---------------------------------------------------------------------------*/
  29. /*---------------------------------------------------------------------------*\
  30. * Changes *
  31. * *
  32. * *
  33. * *
  34. * *
  35. * *
  36. * *
  37. \*---------------------------------------------------------------------------*/
  38. //-------------------------------
  39. // Includes
  40. //-------------------------------
  41. #include <cstdlib>
  42. #include <cstdio>
  43. #include <setjmp.h>
  44. #include <cstring>
  45. #include <cctype>
  46. #include "OSGConfig.h"
  47. #ifdef OSG_SGI_LIB
  48. #include <limits>
  49. #endif
  50. #include "OSGGIFImageFileType.h"
  51. #include "OSGLog.h"
  52. #ifndef OSG_DO_DOC
  53. # ifdef OSG_WITH_GIF
  54. # define OSG_GIF_ARG(ARG) ARG
  55. # else
  56. # define OSG_GIF_ARG(ARG)
  57. # endif
  58. #else
  59. # define OSG_GIF_ARG(ARG) ARG
  60. #endif
  61. #ifdef OSG_WITH_GIF
  62. /*! \class OSG::GIFImageFileType
  63. \ingroup GrpSystemImage
  64. Image File Type to read/write and store/restore Image objects as
  65. GIF data.
  66. All the type specific code is included in the class. Does
  67. not depend on external libs.
  68. You have to --enable-gif in the configure line to enable
  69. the singleton object.
  70. */
  71. //--- GIF-INCLUDE START ----------------------------------------------------
  72. #define GIF_MAXCOLORS 256
  73. typedef enum
  74. {
  75. gif_image,
  76. gif_comment,
  77. gif_text
  78. } GIFStreamType;
  79. typedef enum
  80. {
  81. gif_no_disposal = 0,
  82. gif_keep_disposal = 1,
  83. gif_color_restore = 2,
  84. gif_image_restore = 3
  85. }
  86. GIFDisposalType;
  87. typedef struct
  88. {
  89. int transparent; /* transparency index */
  90. int delayTime; /* Time in 1/100 of a second */
  91. int inputFlag; /* wait for input after display */
  92. GIFDisposalType disposal;
  93. } GIF89info;
  94. typedef struct GIFData
  95. {
  96. GIF89info info;
  97. int x, y;
  98. int width, height;
  99. GIFStreamType type;
  100. union
  101. {
  102. struct
  103. {
  104. int cmapSize;
  105. unsigned char cmapData[GIF_MAXCOLORS][3];
  106. unsigned char *data;
  107. int interlaced;
  108. } image;
  109. struct
  110. {
  111. int fg, bg;
  112. int cellWidth, cellHeight;
  113. int len;
  114. char *text;
  115. } text;
  116. struct
  117. {
  118. int len;
  119. char *text;
  120. } comment;
  121. } data;
  122. struct GIFData *next;
  123. } GIFData;
  124. typedef struct
  125. {
  126. int width, height;
  127. int colorResolution;
  128. int colorMapSize;
  129. int cmapSize;
  130. unsigned char cmapData[GIF_MAXCOLORS][3];
  131. int background;
  132. int aspectRatio;
  133. GIFData *data;
  134. } GIFStream;
  135. static GIFStream *GIFRead (std::istream &is);
  136. int GIFTest (char *);
  137. int GIFWrite (char *, GIFStream *, int);
  138. static int GIFWriteFP(FILE *, GIFStream *, int);
  139. static int GIFFree (GIFStream *);
  140. #endif
  141. //--- GIF INCLUDE END ----------------------------------------------------
  142. OSG_USING_NAMESPACE
  143. static const Char8 *suffixArray[] =
  144. {
  145. "gif"
  146. };
  147. GIFImageFileType GIFImageFileType::_the("image/gif",
  148. suffixArray,
  149. sizeof(suffixArray));
  150. //-------------------------------------------------------------------------
  151. /*! Tries to fill the image object with the data read from
  152. the given fileName. Returns true on success.
  153. */
  154. bool GIFImageFileType::read( Image *OSG_GIF_ARG(pImage),
  155. std::istream &OSG_GIF_ARG(is),
  156. const std::string &OSG_GIF_ARG(mimetype))
  157. {
  158. bool retCode = false;
  159. #ifdef OSG_WITH_GIF
  160. Image::PixelFormat pixelFormat = Image::OSG_INVALID_PF;
  161. GIFStream *gifStream = GIFRead(is);
  162. GIFData *gifData = 0;
  163. bool isColor;
  164. int i, j, destI, lineSize, lineEnd;
  165. unsigned red, green, blue;
  166. int transparentIndex;
  167. int width = 0, height = 0, channel = 0;
  168. int xOff = 0, yOff = 0;
  169. unsigned char *srcData = 0, *destData = 0;
  170. int colorIndex;
  171. unsigned frameCount = 0, currentFrame = 0;
  172. unsigned char *colorMap = 0;
  173. // int imageSize = 0;
  174. int colorMapSize;
  175. Time frameDelay;
  176. if(gifStream)
  177. {
  178. frameCount = 0;
  179. for(gifData = gifStream->data; gifData; gifData = gifData->next)
  180. {
  181. if(gifData->type == gif_image)
  182. frameCount++;
  183. }
  184. }
  185. FDEBUG(("GIF Frames: %d\n", frameCount));
  186. if(gifStream)
  187. {
  188. for(gifData = gifStream->data; gifData; gifData = gifData->next)
  189. {
  190. switch(gifData->type)
  191. {
  192. case gif_image:
  193. if(frameCount)
  194. {
  195. FDEBUG(("Try to copy GIF Anim Frame %d/%d\n",
  196. (currentFrame + 1), frameCount));
  197. }
  198. // get the att.
  199. transparentIndex = gifData->info.transparent;
  200. frameDelay = float(gifData->info.delayTime) / 100.0f;
  201. width = gifData->width;
  202. height = gifData->height;
  203. xOff = gifData->x;
  204. yOff = gifData->y;
  205. // check if the movie is color or greyscale
  206. isColor = false;
  207. if(gifData->data.image.cmapSize > 0)
  208. {
  209. colorMapSize = gifData->data.image.cmapSize;
  210. colorMap =
  211. reinterpret_cast<unsigned char *>(
  212. gifData->data.image.cmapData);
  213. // cout << "INFO: Use gifData colorMap" << endl;
  214. }
  215. else if(gifStream->cmapSize > 0)
  216. {
  217. colorMapSize = gifStream->cmapSize;
  218. colorMap =
  219. reinterpret_cast<unsigned char *>(
  220. gifStream->cmapData);
  221. // cout << "INFO: Use gifStream colorMap" << endl;
  222. }
  223. else
  224. {
  225. FWARNING(("Bad color map in "
  226. "GIFImageFileType::read()\n"));
  227. colorMapSize = 0;
  228. }
  229. for(i = 0; i < colorMapSize; i++)
  230. {
  231. if(i != transparentIndex)
  232. {
  233. red = colorMap[i * 3 + 0];
  234. green = colorMap[i * 3 + 1];
  235. blue = colorMap[i * 3 + 2];
  236. if(red != green || red != blue)
  237. {
  238. isColor = true;
  239. break;
  240. }
  241. }
  242. }
  243. // calculate the movie channel
  244. channel =
  245. (isColor ? 3 : 1) + (transparentIndex >= 0 ? 1 : 0);
  246. if(currentFrame)
  247. {
  248. // is not the first frame
  249. if((channel == pImage->getBpp()) &&
  250. (width == pImage->getWidth()) &&
  251. (height == pImage->getHeight()))
  252. {
  253. destData = pImage->editData(0, currentFrame);
  254. }
  255. else
  256. {
  257. destData = pImage->editData(0, currentFrame);
  258. // This is probably wrong, but it's a start
  259. switch(gifData->info.disposal)
  260. {
  261. case gif_no_disposal:
  262. break;
  263. case gif_keep_disposal:
  264. memcpy(destData,
  265. pImage->getData(0,
  266. currentFrame - 1),
  267. pImage->getWidth () *
  268. pImage->getHeight() *
  269. channel);
  270. break;
  271. case gif_color_restore:
  272. {
  273. unsigned char r,g,b,a;
  274. Int32 bgindex = gifStream->background;
  275. unsigned char *d = destData;
  276. r = colorMap[bgindex * 3 + 0];
  277. g = colorMap[bgindex * 3 + 1];
  278. b = colorMap[bgindex * 3 + 2];
  279. a = (bgindex == transparentIndex) ?
  280. 0 : 255;
  281. for(UInt32 pixel =
  282. pImage->getWidth () *
  283. pImage->getHeight();
  284. pixel > 0; --pixel, d += channel)
  285. {
  286. d[0] = r;
  287. d[1] = g;
  288. d[2] = b;
  289. if(channel == 4)
  290. d[3] = a;
  291. }
  292. }
  293. break;
  294. case gif_image_restore:
  295. memcpy(destData,
  296. pImage->getData(
  297. 0,
  298. (currentFrame >= 2) ?
  299. (currentFrame - 2) : 0),
  300. pImage->getWidth () *
  301. pImage->getHeight() *
  302. channel);
  303. break;
  304. default:
  305. FWARNING(("Unknown GIF disposal "
  306. "mode %d\n",
  307. gifData->info.disposal));
  308. break;
  309. }
  310. }
  311. }
  312. else
  313. {
  314. switch(channel)
  315. {
  316. case 1:
  317. pixelFormat = Image::OSG_L_PF;
  318. break;
  319. case 2:
  320. pixelFormat = Image::OSG_LA_PF;
  321. break;
  322. case 3:
  323. pixelFormat = Image::OSG_RGB_PF;
  324. break;
  325. case 4:
  326. pixelFormat = Image::OSG_RGBA_PF;
  327. break;
  328. };
  329. pImage->set(pixelFormat,
  330. width,
  331. height,
  332. 1, 1,
  333. frameCount, frameDelay);
  334. destData = pImage->editData();
  335. }
  336. // copy the image data)
  337. lineSize = pImage->getWidth() * channel;
  338. lineEnd = width * channel + xOff * channel;
  339. srcData = gifData->data.image.data;
  340. destData =
  341. destData + ((pImage->getHeight() - yOff - 1)*lineSize);
  342. switch(channel)
  343. {
  344. case 1: // Greyscale without Alpha
  345. destI = 0;
  346. for(i = width * height; i--;)
  347. {
  348. destData[destI++] = colorMap[*srcData++ *3];
  349. if(destI >= lineSize)
  350. {
  351. destI = 0;
  352. destData -= lineSize;
  353. }
  354. }
  355. break;
  356. case 2: // Greyscale with Alpha
  357. destI = 0;
  358. for(i = width * height; i--;)
  359. {
  360. colorIndex = *srcData++;
  361. if(colorIndex == transparentIndex)
  362. {
  363. destData[destI++] = 0;
  364. destData[destI++] = 0;
  365. }
  366. else
  367. {
  368. destData[destI++] = colorMap[colorIndex*3];
  369. destData[destI++] = 255;
  370. }
  371. if(destI >= lineSize)
  372. {
  373. destI = 0;
  374. destData -= lineSize;
  375. }
  376. }
  377. break;
  378. case 3: // RGB without Alpha
  379. destI = 0;
  380. for(i = width * height; i--;)
  381. {
  382. colorIndex = *srcData++;
  383. for(j = 0; j < 3; j++)
  384. {
  385. destData[destI++] =
  386. colorMap[colorIndex * 3 + j];
  387. }
  388. if(destI >= lineSize)
  389. {
  390. destI = 0;
  391. destData -= lineSize;
  392. }
  393. }
  394. break;
  395. case 4: // RGB with Alpha
  396. destI = xOff * 4;
  397. for(i = width * height; i--;)
  398. {
  399. colorIndex = *srcData++;
  400. if(colorIndex == transparentIndex)
  401. {
  402. #if 0
  403. for(j = 0; j < 3; j++)
  404. destData[destI++] = 0; // RGB
  405. destData[destI++] = 0; // ALPHA
  406. #endif
  407. destI += 4;
  408. }
  409. else
  410. {
  411. for(j = 0; j < 3; j++)
  412. {
  413. destData[destI++] =
  414. colorMap[colorIndex * 3 + j];// RGB
  415. }
  416. destData[destI++] = 255; // ALPHA
  417. }
  418. if(destI >= lineEnd)
  419. {
  420. destI = xOff * 4;
  421. destData -= lineSize;
  422. }
  423. }
  424. break;
  425. }
  426. retCode = true;
  427. currentFrame++;
  428. break;
  429. case gif_comment:
  430. break;
  431. case gif_text:
  432. break;
  433. }
  434. }
  435. GIFFree(gifStream);
  436. }
  437. else
  438. {
  439. retCode = false;
  440. }
  441. #endif
  442. return retCode;
  443. }
  444. //-------------------------------------------------------------------------
  445. /*! Tries to write the image object to the given fileName.
  446. Returns true on success.
  447. */
  448. bool GIFImageFileType::write(const Image * ,
  449. std::ostream &,
  450. const std::string &)
  451. {
  452. #ifdef OSG_WITH_GIF
  453. SWARNING << getMimeType() << " write is not implemented " << endLog;
  454. #else
  455. SWARNING << getMimeType()
  456. << " write is not compiled into the current binary "
  457. << endLog;
  458. #endif
  459. return false;
  460. }
  461. //-------------------------------------------------------------------------
  462. /*!
  463. Tries to determine the mime type of the data provided by an input stream
  464. by searching for magic bytes. Returns the mime type or an empty string
  465. when the function could not determine the mime type.
  466. */
  467. std::string GIFImageFileType::determineMimetypeFromStream(std::istream &is)
  468. {
  469. char filecode[4];
  470. is.read(filecode, 4);
  471. is.seekg(-4, std::ios::cur);
  472. return strncmp(filecode, "GIF8", 4) == 0 ?
  473. std::string(getMimeType()) : std::string();
  474. }
  475. bool GIFImageFileType::validateHeader(const Char8 *fileName, bool &implemented)
  476. {
  477. implemented = true;
  478. if(fileName == NULL)
  479. return false;
  480. FILE *file = fopen(fileName, "rb");
  481. if(file == NULL)
  482. return false;
  483. std::string magic;
  484. magic.resize(4);
  485. fread(static_cast<void *>(&magic[0]), 4, 1, file);
  486. fclose(file);
  487. if(magic == "GIF8")
  488. {
  489. return true;
  490. }
  491. return false;
  492. }
  493. //-------------------------------------------------------------------------
  494. /*! Constructor used for the singleton object
  495. */
  496. GIFImageFileType::GIFImageFileType(const Char8 *mimeType,
  497. const Char8 *suffixArray[],
  498. UInt16 suffixByteCount) :
  499. Inherited(mimeType,suffixArray, suffixByteCount)
  500. {
  501. }
  502. //-------------------------------------------------------------------------
  503. /*! Destructor
  504. */
  505. GIFImageFileType::~GIFImageFileType(void)
  506. {
  507. }
  508. #ifdef OSG_WITH_GIF
  509. //--- GIF-READ START ----------------------------------------------------
  510. /*
  511. ** Copyright 1994, Home Pages, Inc.
  512. **
  513. ** Please read the file COPYRIGHT for specific information.
  514. **
  515. ** Home Pages, Inc.
  516. ** 257 Castro St. Suite 219
  517. ** Mountain View, CA 94041
  518. **
  519. ** Phone: 1 415 903 5353
  520. ** Fax: 1 415 903 5345
  521. **
  522. ** EMail: support@homepages.com
  523. **
  524. */
  525. /* +-------------------------------------------------------------------+ */
  526. /* | Copyright 1990 - 1994, David Koblas. (koblas@netcom.com) | */
  527. /* | Permission to use, copy, modify, and distribute this software | */
  528. /* | and its documentation for any purpose and without fee is hereby | */
  529. /* | granted, provided that the above copyright notice appear in all | */
  530. /* | copies and that both that copyright notice and this permission | */
  531. /* | notice appear in supporting documentation. This software is | */
  532. /* | provided "as is" without express or implied warranty. | */
  533. /* +-------------------------------------------------------------------+ */
  534. #define GIF_TRUE 1
  535. #define GIF_FALSE 0
  536. #define MAX_LWZ_BITS 12
  537. #define INTERLACE 0x40
  538. #define LOCALCOLORMAP 0x80
  539. #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
  540. #define ReadOK(is, buffer, len) (is.read(reinterpret_cast<char*>(buffer), \
  541. len).gcount() == len)
  542. #define MKINT(a, b) (((b) << 8) | (a))
  543. #define NEW(x) (static_cast<x *>(malloc(sizeof(x))))
  544. /***************************************************************************
  545. *
  546. * ERROR() -- should not return
  547. * INFO_MSG() -- info message, can be ignored
  548. *
  549. ***************************************************************************/
  550. #if 0
  551. #define INFO_MSG(fmt) pm_message fmt
  552. #define ERROR(str) pm_error(str)
  553. #else
  554. #if 0
  555. #define INFO_MSG(fmt)
  556. #define ERROR(str) do { RWSetMsg(str); longjmp(setjmp_buffer, 1); } while(0)
  557. #else
  558. #define INFO_MSG(fmt) { FINFO(("Info loading gif: '%s'!\n", fmt)); }
  559. #define GIF_ERROR(str) { FWARNING(("Error loading gif: '%s'!\n", str)); \
  560. longjmp(setjmp_buffer, 1); }
  561. #endif
  562. #endif
  563. /***************************************************************************/
  564. static int readColorMap(std::istream &, int, unsigned char [GIF_MAXCOLORS][3]);
  565. static int GetDataBlock(std::istream &, unsigned char *);
  566. static void readImage (std::istream &, int, int, int, unsigned char *);
  567. static jmp_buf setjmp_buffer;
  568. static int verbose = GIF_FALSE;
  569. //static int showComment = GIF_FALSE;
  570. /* */
  571. static GIFStream *GIFRead(std::istream &is)
  572. {
  573. unsigned char buf[256];
  574. unsigned char c;
  575. GIFStream *gifStream = 0;
  576. GIFData *cur, **end;
  577. GIF89info info = {0, 0, 0, gif_no_disposal};
  578. int resetInfo = GIF_TRUE;
  579. int n;
  580. if(setjmp(setjmp_buffer))
  581. goto out;
  582. if(!ReadOK(is, buf, 6))
  583. {
  584. GIF_ERROR("error reading magic number");
  585. }
  586. if(strncmp(reinterpret_cast<char *>(buf), "GIF", 3) != 0)
  587. GIF_ERROR("not a GIF file");
  588. if((strncmp((reinterpret_cast<char *>(buf)) + 3, "87a", 3) != 0) &&
  589. (strncmp((reinterpret_cast<char *>(buf)) + 3, "89a", 3) != 0))
  590. {
  591. GIF_ERROR("bad version number, not '87a' or '89a'");
  592. }
  593. if(!ReadOK(is, buf, 7))
  594. {
  595. GIF_ERROR("failed to read screen descriptor");
  596. }
  597. gifStream = NEW(GIFStream);
  598. gifStream->width = MKINT(buf[0], buf[1]);
  599. gifStream->height = MKINT(buf[2], buf[3]);
  600. gifStream->cmapSize = 2 << (buf[4] & 0x07);
  601. gifStream->colorMapSize = gifStream->cmapSize;
  602. gifStream->colorResolution = (int(buf[4] & 0x70) >> 3) + 1;
  603. gifStream->background = buf[5];
  604. gifStream->aspectRatio = buf[6];
  605. gifStream->data = NULL;
  606. end = &gifStream->data;
  607. /*
  608. ** Global colormap is present.
  609. */
  610. if(BitSet(buf[4], LOCALCOLORMAP))
  611. {
  612. if(readColorMap(is, gifStream->cmapSize, gifStream->cmapData))
  613. {
  614. GIF_ERROR("unable to get global colormap");
  615. }
  616. }
  617. else
  618. {
  619. gifStream->cmapSize = 0;
  620. gifStream->background = -1;
  621. }
  622. if(gifStream->aspectRatio != 0 && gifStream->aspectRatio != 49)
  623. {
  624. INFO_MSG(("warning - non-square pixels"));
  625. }
  626. while(ReadOK(is, &c, 1) && c != ';')
  627. {
  628. if(resetInfo)
  629. {
  630. info.disposal = static_cast<GIFDisposalType>(0);
  631. info.inputFlag = 0;
  632. info.delayTime = 0;
  633. info.transparent = -1;
  634. resetInfo = GIF_FALSE;
  635. }
  636. cur = NULL;
  637. if(c == '!')
  638. { /* Extension */
  639. if(!ReadOK(is, &c, 1))
  640. {
  641. GIF_ERROR("EOF / read error on extention function code");
  642. }
  643. if(c == 0xf9)
  644. { /* graphic control */
  645. (void) GetDataBlock(is, buf);
  646. info.disposal =
  647. static_cast<GIFDisposalType>((buf[0] >> 2) & 0x7);
  648. info.inputFlag = (buf[0] >> 1) & 0x1;
  649. info.delayTime = MKINT(buf[1], buf[2]);
  650. if(BitSet(buf[0], 0x1))
  651. info.transparent = buf[3];
  652. while(GetDataBlock(is, buf) != 0)
  653. ;
  654. }
  655. else if(c == 0xfe || c == 0x01)
  656. {
  657. int len = 0;
  658. int size = 256;
  659. char *text = NULL;
  660. /*
  661. ** Comment or Plain Text
  662. */
  663. cur = NEW(GIFData);
  664. if(c == 0x01)
  665. {
  666. (void) GetDataBlock(is, buf);
  667. cur->type = gif_text;
  668. cur->info = info;
  669. cur->x = MKINT(buf[0], buf[1]);
  670. cur->y = MKINT(buf[2], buf[3]);
  671. cur->width = MKINT(buf[4], buf[5]);
  672. cur->height = MKINT(buf[6], buf[7]);
  673. cur->data.text.cellWidth = buf[8];
  674. cur->data.text.cellHeight = buf[9];
  675. cur->data.text.fg = buf[10];
  676. cur->data.text.bg = buf[11];
  677. resetInfo = GIF_TRUE;
  678. }
  679. else
  680. {
  681. cur->type = gif_comment;
  682. }
  683. text = static_cast<char *>(malloc(size));
  684. while((n = GetDataBlock(is, buf)) != 0)
  685. {
  686. if(n + len >= size)
  687. {
  688. text = static_cast<char *>(realloc(text, size += 256));
  689. }
  690. memcpy(text + len, buf, n);
  691. len += n;
  692. }
  693. if(c == 0x01)
  694. {
  695. cur->data.text.len = len;
  696. cur->data.text.text = text;
  697. }
  698. else
  699. {
  700. cur->data.comment.len = len;
  701. cur->data.comment.text = text;
  702. }
  703. }
  704. else
  705. {
  706. /*
  707. ** Unrecogonized extension, consume it.
  708. */
  709. while(GetDataBlock(is, buf) > 0)
  710. ;
  711. }
  712. }
  713. else if(c == ',')
  714. {
  715. if(!ReadOK(is, buf, 9))
  716. {
  717. GIF_ERROR("couldn't read left/top/width/height");
  718. }
  719. cur = NEW(GIFData);
  720. cur->type = gif_image;
  721. cur->info = info;
  722. cur->x = MKINT(buf[0], buf[1]);
  723. cur->y = MKINT(buf[2], buf[3]);
  724. cur->width = MKINT(buf[4], buf[5]);
  725. cur->height = MKINT(buf[6], buf[7]);
  726. cur->data.image.cmapSize = 1 << ((buf[8] & 0x07) + 1);
  727. if(BitSet(buf[8], LOCALCOLORMAP))
  728. {
  729. if(readColorMap(is, cur->data.image.cmapSize,
  730. cur->data.image.cmapData))
  731. {
  732. GIF_ERROR("unable to get local colormap");
  733. }
  734. }
  735. else
  736. {
  737. cur->data.image.cmapSize = 0;
  738. }
  739. cur->data.image.data = static_cast<unsigned char *>(
  740. malloc(cur->width * cur->height));
  741. cur->data.image.interlaced = BitSet(buf[8], INTERLACE);
  742. readImage(is, BitSet(buf[8], INTERLACE), cur->width, cur->height,
  743. cur->data.image.data);
  744. resetInfo = GIF_TRUE;
  745. }
  746. else
  747. {
  748. FINFO(("Info loading gif: bogus character 0x%02x, ignoring",
  749. int(c)));
  750. }
  751. if(cur != NULL)
  752. {
  753. *end = cur;
  754. end = &cur->next;
  755. cur->next = NULL;
  756. }
  757. }
  758. if(c != ';')
  759. GIF_ERROR("EOF / data stream");
  760. out:
  761. return gifStream;
  762. }
  763. /* */
  764. static int GIFFreeData(GIFData *gifData)
  765. {
  766. int retCode = 0;
  767. if(gifData)
  768. {
  769. switch(gifData->type)
  770. {
  771. case gif_image:
  772. if(gifData->data.image.data)
  773. {
  774. free(gifData->data.image.data);
  775. }
  776. break;
  777. case gif_comment:
  778. if(gifData->data.comment.text)
  779. {
  780. free(gifData->data.comment.text);
  781. }
  782. break;
  783. case gif_text:
  784. if(gifData->data.text.text)
  785. {
  786. free(gifData->data.text.text);
  787. }
  788. break;
  789. }
  790. retCode = 1;
  791. }
  792. else
  793. retCode = 0;
  794. return retCode;
  795. }
  796. /* */
  797. static int GIFFree(GIFStream *gifStream)
  798. {
  799. int retCode = 1;
  800. GIFData *gifData, *gifNext;
  801. if(gifStream)
  802. {
  803. gifData = gifStream->data;
  804. while(gifData)
  805. {
  806. gifNext = gifData->next;
  807. GIFFreeData(gifData);
  808. free(gifData);
  809. gifData = gifNext;
  810. }
  811. }
  812. return retCode;
  813. }
  814. /* */
  815. static int readColorMap(std::istream &is, int size, unsigned char data[GIF_MAXCOLORS][3])
  816. {
  817. int i;
  818. unsigned char rgb[3 * GIF_MAXCOLORS];
  819. unsigned char *cp = rgb;
  820. if(!ReadOK(is, rgb, size * 3))
  821. return GIF_TRUE;
  822. for(i = 0; i < size; i++)
  823. {
  824. data[i][0] = *cp++;
  825. data[i][1] = *cp++;
  826. data[i][2] = *cp++;
  827. }
  828. return GIF_FALSE;
  829. }
  830. /*
  831. **
  832. */
  833. static int ZeroDataBlock = GIF_FALSE;
  834. /* */
  835. static int GetDataBlock(std::istream &is, unsigned char *buf)
  836. {
  837. unsigned char count;
  838. if(!ReadOK(is, &count, 1))
  839. {
  840. INFO_MSG(("error in getting DataBlock size"));
  841. return -1;
  842. }
  843. ZeroDataBlock = count == 0;
  844. if((count != 0) && (!ReadOK(is, buf, count)))
  845. {
  846. INFO_MSG(("error in reading DataBlock"));
  847. return -1;
  848. }
  849. return count;
  850. }
  851. /*
  852. **
  853. **
  854. */
  855. /*
  856. ** Pulled out of nextCode
  857. */
  858. static int curbit, lastbit, get_done, last_byte;
  859. static int return_clear;
  860. /*
  861. ** Out of nextLWZ
  862. */
  863. static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
  864. static int code_size, set_code_size;
  865. static int max_code, max_code_size;
  866. static int clear_code, end_code;
  867. /* */
  868. static void initLWZ(int input_code_size)
  869. {
  870. // static int inited = GIF_FALSE;
  871. set_code_size = input_code_size;
  872. code_size = set_code_size + 1;
  873. clear_code = 1 << set_code_size ;
  874. end_code = clear_code + 1;
  875. max_code_size = 2 * clear_code;
  876. max_code = clear_code + 2;
  877. curbit = lastbit = 0;
  878. last_byte = 2;
  879. get_done = GIF_FALSE;
  880. return_clear = GIF_TRUE;
  881. sp = stack;
  882. }
  883. /* */
  884. static int nextCode(std::istream &is, int code_size)
  885. {
  886. static unsigned char buf[280];
  887. static int maskTbl[16] =
  888. {
  889. 0x0000,
  890. 0x0001,
  891. 0x0003,
  892. 0x0007,
  893. 0x000f,
  894. 0x001f,
  895. 0x003f,
  896. 0x007f,
  897. 0x00ff,
  898. 0x01ff,
  899. 0x03ff,
  900. 0x07ff,
  901. 0x0fff,
  902. 0x1fff,
  903. 0x3fff,
  904. 0x7fff,
  905. };
  906. int i, j, ret, end;
  907. if(return_clear)
  908. {
  909. return_clear = GIF_FALSE;
  910. return clear_code;
  911. }
  912. end = curbit + code_size;
  913. if(end >= lastbit)
  914. {
  915. int count;
  916. if(get_done)
  917. {
  918. if(curbit >= lastbit)
  919. {
  920. GIF_ERROR("ran off the end of my bits");
  921. }
  922. return -1;
  923. }
  924. buf[0] = buf[last_byte - 2];
  925. buf[1] = buf[last_byte - 1];
  926. if((count = GetDataBlock(is, &buf[2])) == 0)
  927. get_done = GIF_TRUE;
  928. last_byte = 2 + count;
  929. curbit = (curbit - lastbit) + 16;
  930. lastbit = (2 + count) * 8;
  931. end = curbit + code_size;
  932. }
  933. j = end / 8;
  934. i = curbit / 8;
  935. if(i == j)
  936. ret = buf[i];
  937. else if(i + 1 == j)
  938. ret = buf[i] | (buf[i + 1] << 8);
  939. else
  940. {
  941. ret = buf[i] | (buf[i + 1] << 8) | (buf[i + 2] << 16);
  942. }
  943. ret = (ret >> (curbit % 8)) & maskTbl[code_size];
  944. curbit += code_size;
  945. return ret;
  946. }
  947. #define readLWZ(fd) ((sp > stack) ? *--sp : nextLWZ(fd))
  948. /* */
  949. static int nextLWZ(std::istream &is)
  950. {
  951. static int table[2][(1 << MAX_LWZ_BITS)];
  952. static int firstcode, oldcode;
  953. int code, incode;
  954. register int i;
  955. while((code = nextCode(is, code_size)) >= 0)
  956. {
  957. if(code == clear_code)
  958. {
  959. for(i = 0; i < clear_code; ++i)
  960. {
  961. table[0][i] = 0;
  962. table[1][i] = i;
  963. }
  964. for(; i < (1 << MAX_LWZ_BITS); ++i)
  965. table[0][i] = table[1][i] = 0;
  966. code_size = set_code_size + 1;
  967. max_code_size = 2 * clear_code;
  968. max_code = clear_code + 2;
  969. sp = stack;
  970. do
  971. {
  972. firstcode = oldcode = nextCode(is, code_size);
  973. } while(firstcode == clear_code);
  974. return firstcode;
  975. }
  976. if(code == end_code)
  977. {
  978. int count;
  979. unsigned char buf[260];
  980. if(ZeroDataBlock)
  981. return -2;
  982. while((count = GetDataBlock(is, buf)) > 0)
  983. ;
  984. if(count != 0)
  985. {
  986. INFO_MSG(("missing EOD in data stream"));
  987. }
  988. return -2;
  989. }
  990. incode = code;
  991. if(code >= max_code)
  992. {
  993. *sp++ = firstcode;
  994. code = oldcode;
  995. }
  996. while(code >= clear_code)
  997. {
  998. *sp++ = table[1][code];
  999. if(code == table[0][code])
  1000. {
  1001. GIF_ERROR("circular table entry BIG ERROR");
  1002. }
  1003. code = table[0][code];
  1004. }
  1005. *sp++ = firstcode = table[1][code];
  1006. if((code = max_code) < (1 << MAX_LWZ_BITS))
  1007. {
  1008. table[0][code] = oldcode;
  1009. table[1][code] = firstcode;
  1010. ++max_code;
  1011. if((max_code >= max_code_size) &&
  1012. (max_code_size < (1 << MAX_LWZ_BITS)))
  1013. {
  1014. max_code_size *= 2;
  1015. ++code_size;
  1016. }
  1017. }
  1018. oldcode = incode;
  1019. if(sp > stack)
  1020. return *--sp;
  1021. }
  1022. return code;
  1023. }
  1024. /* */
  1025. static void readImage(std::istream &is, int interlace, int width, int height,
  1026. unsigned char *data)
  1027. {
  1028. unsigned char *dp, c;
  1029. int v, xpos = 0, ypos = 0;
  1030. // int pass = 0;
  1031. /*
  1032. ** Initialize the Compression routines
  1033. */
  1034. if(!ReadOK(is, &c, 1))
  1035. {
  1036. GIF_ERROR("EOF / read error on image data");
  1037. }
  1038. initLWZ(c);
  1039. if(verbose)
  1040. {
  1041. FINFO(("Info loading gif: reading %d by %d%s GIF image",
  1042. width, height, interlace ? " interlaced" : ""));
  1043. }
  1044. if(interlace)
  1045. {
  1046. int i;
  1047. int pass = 0, step = 8;
  1048. for(i = 0; i < height; i++)
  1049. {
  1050. dp = &data[width * ypos];
  1051. for(xpos = 0; xpos < width; xpos++)
  1052. {
  1053. if((v = readLWZ(is)) < 0)
  1054. goto fini;
  1055. *dp++ = v;
  1056. }
  1057. if((ypos += step) >= height)
  1058. {
  1059. do
  1060. {
  1061. if(pass++ > 0)
  1062. step /= 2;
  1063. ypos = step / 2;
  1064. } while(ypos > height);
  1065. }
  1066. }
  1067. }
  1068. else
  1069. {
  1070. dp = data;
  1071. for(ypos = 0; ypos < height; ypos++)
  1072. {
  1073. for(xpos = 0; xpos < width; xpos++)
  1074. {
  1075. if((v = readLWZ(is)) < 0)
  1076. goto fini;
  1077. *dp++ = v;
  1078. }
  1079. }
  1080. }
  1081. fini:
  1082. if(readLWZ(is) >= 0)
  1083. {
  1084. INFO_MSG(("too much input data, ignoring extra..."));
  1085. }
  1086. return;
  1087. }
  1088. //--- GIF-READ END ------------------------------------------------------
  1089. //--- GIF-WRITE START ---------------------------------------------------
  1090. /*
  1091. ** Copyright 1994, Home Pages, Inc.
  1092. **
  1093. ** Please read the file COPYRIGHT for specific information.
  1094. **
  1095. ** Home Pages, Inc.
  1096. ** 257 Castro St. Suite 219
  1097. ** Mountain View, CA 94041
  1098. **
  1099. ** Phone: 1 415 903 5353
  1100. ** Fax: 1 415 903 5345
  1101. **
  1102. ** EMail: support@homepages.com
  1103. **
  1104. */
  1105. /* +-------------------------------------------------------------------+ */
  1106. /* | Copyright 1993, David Koblas (koblas@netcom.com) | */
  1107. /* | | */
  1108. /* | Permission to use, copy, modify, and to distribute this software | */
  1109. /* | and its documentation for any purpose is hereby granted without | */
  1110. /* | fee, provided that the above copyright notice appear in all | */
  1111. /* | copies and that both that copyright notice and this permission | */
  1112. /* | notice appear in supporting documentation. There is no | */
  1113. /* | representations about the suitability of this software for | */
  1114. /* | any purpose. this software is provided "as is" without express | */
  1115. /* | or implied warranty. | */
  1116. /* | | */
  1117. /* +-------------------------------------------------------------------+ */
  1118. /* ppmtogif.c - read a portable pixmap and produce a GIF file
  1119. **
  1120. ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>.A
  1121. ** Lempel-Zim compression based on "compress".
  1122. **
  1123. ** Copyright (C) 1989 by Jef Poskanzer.
  1124. **
  1125. ** Permission to use, copy, modify, and distribute this software and its
  1126. ** documentation for any purpose and without fee is hereby granted, provided
  1127. ** that the above copyright notice appear in all copies and that both that
  1128. ** copyright notice and this permission notice appear in supporting
  1129. ** documentation. This software is provided "as is" without express or
  1130. ** implied warranty.
  1131. **
  1132. ** The Graphics Interchange Format(c) is the Copyright property of
  1133. ** CompuServe Incorporated. GIF(sm) is a Service Mark property of
  1134. ** CompuServe Incorporated.
  1135. */
  1136. #define GIF_TRUE 1
  1137. #define GIF_FALSE 0
  1138. #define PUTBYTE(v, fp) putc(v, fp)
  1139. #define PUTWORD(v, fp) \
  1140. do \
  1141. { \
  1142. putc(((v) & 0xff), fp); \
  1143. putc((((v) >> 8) & 0xff), fp); \
  1144. } while(0)
  1145. /*
  1146. * a code_int must be able to hold 2**BITS values of type int, and also -1
  1147. */
  1148. typedef int code_int;
  1149. typedef long int count_int;
  1150. static void putImage(FILE *, int, int, int, int, unsigned char *);
  1151. static void putColorMap(FILE *, int, unsigned char[GIF_MAXCOLORS][3]);
  1152. static void putDataBlocks(FILE *fp, int, unsigned char *);
  1153. static void putGif89Info(FILE *, GIF89info *);
  1154. static void output(code_int code);
  1155. static void cl_block(void);
  1156. static void cl_hash(count_int hsize);
  1157. static void char_init(void);
  1158. static void char_out(int c);
  1159. static void flush_char(void);
  1160. /*
  1161. **
  1162. */
  1163. struct cval
  1164. {
  1165. int idx, cnt;
  1166. };
  1167. /* */
  1168. static int cvalCMP(struct cval *a, struct cval *b)
  1169. {
  1170. return b->cnt - a->cnt;
  1171. }
  1172. /* */
  1173. static int optimizeCMAP(GIFStream *stream)
  1174. {
  1175. GIFData *cur = 0, *img = 0;
  1176. int count = 0;
  1177. for(cur = stream->data; cur != NULL; cur = cur->next)
  1178. {
  1179. if(cur->type == gif_image)
  1180. {
  1181. img = cur;
  1182. count++;
  1183. }
  1184. }
  1185. /*
  1186. ** No images, no optimizations...
  1187. ** or too many images...
  1188. */
  1189. if(count == 0 || count > 1)
  1190. return 0;
  1191. /*
  1192. ** One image, nice and simple...
  1193. ** Insure there is a global colormap, and optimize the
  1194. ** image too it.
  1195. */
  1196. {
  1197. int size;
  1198. unsigned char *dp = img->data.image.data;
  1199. unsigned char *ep = dp + img->width * img->height;
  1200. struct cval vals[256];
  1201. int i;
  1202. // int j;
  1203. unsigned char tmap[256][3], rmap[256];
  1204. if((size = img->data.image.cmapSize) == 0)
  1205. size = stream->cmapSize;
  1206. for(i = 0; i < size; i++)
  1207. {
  1208. vals[i].idx = i;
  1209. vals[i].cnt = 0;
  1210. }
  1211. for(dp = img->data.image.data, i = 0; dp < ep; i++, dp++)
  1212. vals[*dp].cnt++;
  1213. /*
  1214. ** Quite, I'm doing a bubble sort... ACK!
  1215. */
  1216. qsort(vals, size, sizeof(vals[0]),
  1217. reinterpret_cast<int(*) (const void *, const void *)>(cvalCMP));
  1218. for(i = 0; i < size; i++)
  1219. if(vals[i].idx != i)
  1220. break;
  1221. /*
  1222. ** Already sorted, no change!
  1223. */
  1224. if(i == size)
  1225. return 1;
  1226. for(i = 0; i < size; i++)
  1227. rmap[vals[i].idx] = i;
  1228. /*
  1229. ** Now reorder the colormap, and the image
  1230. */
  1231. for(dp = img->data.image.data, i = 0; dp < ep; i++, dp++)
  1232. *dp = rmap[*dp];
  1233. if(img->info.transparent != -1)
  1234. {
  1235. img->info.transparent = rmap[img->info.transparent];
  1236. }
  1237. /*
  1238. ** Toast the local colormap
  1239. */
  1240. if(img->data.image.cmapSize != 0)
  1241. {
  1242. for(i = 0; i < size; i++)
  1243. {
  1244. stream->cmapData[i][0] = img->data.image.cmapData[i][0];
  1245. stream->cmapData[i][1] = img->data.image.cmapData[i][1];
  1246. stream->cmapData[i][2] = img->data.image.cmapData[i][2];
  1247. }
  1248. img->data.image.cmapSize = 0;
  1249. stream->cmapSize = size;
  1250. }
  1251. /*
  1252. ** Now finally reorer the colormap
  1253. */
  1254. for(i = 0; i < size; i++)
  1255. {
  1256. tmap[i][0] = stream->cmapData[i][0];
  1257. tmap[i][1] = stream->cmapData[i][1];
  1258. tmap[i][2] = stream->cmapData[i][2];
  1259. }
  1260. for(i = 0; i < size; i++)
  1261. {
  1262. stream->cmapData[rmap[i]][0] = tmap[i][0];
  1263. stream->cmapData[rmap[i]][1] = tmap[i][1];
  1264. stream->cmapData[rmap[i]][2] = tmap[i][2];
  1265. }
  1266. }
  1267. return 1;
  1268. }
  1269. /*
  1270. ** Return the ceiling log of n
  1271. */
  1272. static int binaryLog(int val)
  1273. {
  1274. int i;
  1275. if(val == 0)
  1276. return 0;
  1277. for(i = 1; i <= 8; i++)
  1278. if(val <= (1 << i))
  1279. return i;
  1280. return 8;
  1281. }
  1282. #ifdef __sgi
  1283. #pragma set woff 1209
  1284. #endif
  1285. /* */
  1286. static int GIFWriteFP(FILE *fp, GIFStream *stream, int optimize)
  1287. {
  1288. GIFData *cur;
  1289. int flag = GIF_FALSE;
  1290. int c;
  1291. int globalBitsPP = 0;
  1292. int resolution;
  1293. if(fp == NULL)
  1294. return GIF_TRUE;
  1295. if(stream == NULL)
  1296. return GIF_FALSE;
  1297. /*
  1298. ** First find if this is a 87A or an 89A GIF image
  1299. ** also, figure out the color resolution of the image.
  1300. */
  1301. resolution = binaryLog(stream->cmapSize) - 1;
  1302. for(cur = stream->data; !flag && cur != NULL; cur = cur->next)
  1303. {
  1304. if(cur->type == gif_text || cur->type == gif_comment)
  1305. {
  1306. flag = GIF_TRUE;
  1307. }
  1308. else if(cur->type == gif_image)
  1309. {
  1310. int v = binaryLog(cur->data.image.cmapSize);
  1311. if(v > resolution)
  1312. resolution = v;
  1313. /*
  1314. ** Uses one of the 89 extensions.
  1315. */
  1316. if(cur->info.transparent != -1 ||
  1317. cur->info.delayTime != 0 ||
  1318. cur->info.inputFlag != 0 ||
  1319. cur->info.disposal != 0)
  1320. flag = GIF_TRUE;
  1321. }
  1322. }
  1323. /*
  1324. **
  1325. */
  1326. if(optimize)
  1327. optimize = optimizeCMAP(stream);
  1328. fwrite(flag ? "GIF89a" : "GIF87a", 1, 6, fp);
  1329. PUTWORD(stream->width, fp);
  1330. PUTWORD(stream->height, fp);
  1331. /*
  1332. ** assume 256 entry color resution, and non sorted colormap
  1333. */
  1334. c = ((resolution & 0x07) << 5) | 0x00;
  1335. if(stream->cmapSize != 0)
  1336. {
  1337. globalBitsPP = binaryLog(stream->cmapSize);
  1338. c |= 0x80;
  1339. c |= globalBitsPP - 1;
  1340. }
  1341. /*
  1342. ** Is the global colormap optimized?
  1343. */
  1344. if(optimize)
  1345. c |= 0x08;
  1346. PUTBYTE(c, fp);
  1347. PUTBYTE(stream->background, fp);
  1348. PUTBYTE(stream->aspectRatio, fp);
  1349. putColorMap(fp, stream->cmapSize, stream->cmapData);
  1350. for(cur = stream->data; cur != NULL; cur = cur->next)
  1351. {
  1352. if(cur->type == gif_image)
  1353. {
  1354. int bpp;
  1355. putGif89Info(fp, &cur->info);
  1356. PUTBYTE(0x2c, fp);
  1357. PUTWORD(cur->x, fp);
  1358. PUTWORD(cur->y, fp);
  1359. PUTWORD(cur->width, fp);
  1360. PUTWORD(cur->height, fp);
  1361. c = cur->data.image.interlaced ? 0x40 : 0x00;
  1362. if(cur->data.image.cmapSize != 0)
  1363. {
  1364. bpp = binaryLog(cur->data.image.cmapSize);
  1365. c |= 0x80;
  1366. c |= bpp;
  1367. }
  1368. else
  1369. {
  1370. bpp = globalBitsPP;
  1371. }
  1372. PUTBYTE(c, fp);
  1373. putColorMap(fp, cur->data.image.cmapSize, cur->data.image.cmapData);
  1374. putImage(fp, cur->data.image.interlaced, bpp, cur->width,
  1375. cur->height, cur->data.image.data);
  1376. }
  1377. else if(cur->type == gif_comment)
  1378. {
  1379. PUTBYTE('!', fp);
  1380. PUTBYTE(0xfe, fp);
  1381. putDataBlocks(
  1382. fp,
  1383. cur->data.comment.len,
  1384. reinterpret_cast<unsigned char *>(cur->data.comment.text));
  1385. }
  1386. else if(cur->type == gif_text)
  1387. {
  1388. putGif89Info(fp, &cur->info);
  1389. PUTBYTE('!', fp);
  1390. PUTBYTE(0x01, fp);
  1391. PUTWORD(cur->x, fp);
  1392. PUTWORD(cur->y, fp);
  1393. PUTWORD(cur->width, fp);
  1394. PUTWORD(cur->height, fp);
  1395. PUTBYTE(cur->data.text.cellWidth, fp);
  1396. PUTBYTE(cur->data.text.cellHeight, fp);
  1397. PUTBYTE(cur->data.text.fg, fp);
  1398. PUTBYTE(cur->data.text.bg, fp);
  1399. putDataBlocks(
  1400. fp,
  1401. cur->data.text.len,
  1402. reinterpret_cast<unsigned char *>(cur->data.text.text));
  1403. }
  1404. }
  1405. /*
  1406. ** Write termination
  1407. */
  1408. PUTBYTE(';', fp);
  1409. return GIF_FALSE;
  1410. }
  1411. #ifdef __sgi
  1412. #pragma reset woff 1209
  1413. #endif
  1414. /* */
  1415. int GIFWrite(char *file, GIFStream *stream, int optimize)
  1416. {
  1417. if(stream != NULL)
  1418. {
  1419. FILE *fp = fopen(file, "wb");
  1420. if(fp != NULL)
  1421. {
  1422. int s = GIFWriteFP(fp, stream, optimize);
  1423. fclose(fp);
  1424. return s;
  1425. }
  1426. }
  1427. return GIF_TRUE;
  1428. }
  1429. /* */
  1430. static void putColorMap(FILE *fp, int size, unsigned char data[GIF_MAXCOLORS][3])
  1431. {
  1432. int i;
  1433. for(i = 0; i < size; i++)
  1434. {
  1435. PUTBYTE(data[i][0], fp);
  1436. PUTBYTE(data[i][1], fp);
  1437. PUTBYTE(data[i][2], fp);
  1438. }
  1439. }
  1440. /* */
  1441. static void putDataBlocks(FILE *fp, int size, unsigned char *data)
  1442. {
  1443. int n;
  1444. while(size > 0)
  1445. {
  1446. n = size > 255 ? 255 : size;
  1447. PUTBYTE(n, fp);
  1448. fwrite(data, 1, n, fp);
  1449. data += n;
  1450. size -= n;
  1451. }
  1452. PUTBYTE(0, fp); /* End Block */
  1453. }
  1454. #ifdef __sgi
  1455. #pragma set woff 1209
  1456. #endif
  1457. /* */
  1458. static void putGif89Info(FILE *fp, GIF89info *info)
  1459. {
  1460. unsigned char c;
  1461. if(info->transparent == -1 &&
  1462. info->delayTime == 0 &&
  1463. info->inputFlag == 0 &&
  1464. info->disposal == 0)
  1465. return;
  1466. PUTBYTE('!', fp);
  1467. PUTBYTE(0xf9, fp);
  1468. PUTBYTE(4, fp);
  1469. c = (info->inputFlag ? 0x02 : 0x00) | ((info->disposal & 0x07) << 2) | ((info->transparent != -1) ? 0x01 : 0x00);
  1470. PUTBYTE(c, fp);
  1471. PUTWORD(info->delayTime, fp);
  1472. PUTBYTE(info->transparent, fp);
  1473. /*
  1474. ** End
  1475. */
  1476. PUTBYTE(0, fp);
  1477. }
  1478. #ifdef __sgi
  1479. #pragma reset woff 1209
  1480. #endif
  1481. /***************************************************************************
  1482. *
  1483. * GIFCOMPR.C - GIF Image compression routines
  1484. *
  1485. * Lempel-Ziv compression based on 'compress'. GIF modifications by
  1486. * David Rowley (mgardi@watdcsu.waterloo.edu)
  1487. *
  1488. ***************************************************************************/
  1489. /*
  1490. * General DEFINEs
  1491. */
  1492. #define BITS 12
  1493. #define HSIZE 5003 /* 80% occupancy */
  1494. #ifdef NO_UCHAR
  1495. typedef char char_type;
  1496. #else /*NO_UCHAR*/
  1497. typedef unsigned char char_type;
  1498. #endif /*NO_UCHAR*/
  1499. /*
  1500. *
  1501. * GIF Image compression - modified 'compress'
  1502. *
  1503. * Based on: compress.c - File compression ala IEEE Computer, June 1984.
  1504. *
  1505. * By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
  1506. * Jim McKie (decvax!mcvax!jim)
  1507. * Steve Davies (decvax!vax135!petsd!peora!srd)
  1508. * Ken Turkowski (decvax!decwrl!turtlevax!ken)
  1509. * James A. Woods (decvax!ihnp4!ames!jaw)
  1510. * Joe Orost (decvax!vax135!petsd!joe)
  1511. *
  1512. */
  1513. #define ARGVAL() (*++(*argv) || (--argc && *++argv))
  1514. static int n_bits; /* number of bits/code */
  1515. static int maxbits; /* user settable max # bits/code */
  1516. static code_int maxcode; /* maximum code, given n_bits */
  1517. static code_int maxmaxcode; /* should NEVER generate this code */
  1518. #define MAXCODE(n_bits) ((static_cast<code_int>(1) << (n_bits)) - 1)
  1519. static count_int htab[HSIZE];
  1520. static unsigned short codetab[HSIZE];
  1521. #define HashTabOf(i) htab[i]
  1522. #define CodeTabOf(i) codetab[i]
  1523. static code_int hsize; /* for dynamic table sizing */
  1524. static unsigned long cur_accum;
  1525. static int cur_bits;
  1526. /*
  1527. * To save much memory, we overlay the table used by compress() with those
  1528. * used by decompress(). The tab_prefix table is the same size and type
  1529. * as the codetab. The tab_suffix table needs 2**BITS characters. We
  1530. * get this from the beginning of htab. The output stack uses the rest
  1531. * of htab, and contains characters. There is plenty of room for any
  1532. * possible stack (stack used to be 8000 characters).
  1533. */
  1534. #define tab_prefixof(i) CodeTabOf(i)
  1535. #define tab_suffixof(i) ((char_type *) (htab))[i]
  1536. #define de_stack ((char_type *) &tab_suffixof((code_int) 1 << BITS))
  1537. static code_int free_ent; /* first unused entry */
  1538. /*
  1539. * block compression parameters -- after all codes are used up,
  1540. * and compression rate changes, start over.
  1541. */
  1542. static int clear_flg;
  1543. // static int offset = 0;
  1544. /*
  1545. * compress stdin to stdout
  1546. *
  1547. * Algorithm: use open addressing double hashing (no chaining) on the
  1548. * prefix code / next character combination. We do a variant of Knuth's
  1549. * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
  1550. * secondary probe. Here, the modular division first probe is gives way
  1551. * to a faster exclusive-or manipulation. Also do block compression with
  1552. * an adaptive reset, whereby the code table is cleared when the compression
  1553. * ratio decreases, but after the table fills. The variable-length output
  1554. * codes are re-sized at this point, and a special CLEAR code is generated
  1555. * for the decompressor. Late addition: construct the table according to
  1556. * file size for noticeable speed improvement on small files. Please direct
  1557. * questions about this implementation to ames!jaw.
  1558. */
  1559. static int g_init_bits;
  1560. static FILE *g_outfile;
  1561. static int ClearCode;
  1562. static int EOFCode;
  1563. /* */
  1564. #ifdef __sgi
  1565. #pragma set woff 1209
  1566. #endif
  1567. static void putImage(FILE *fp, int interlaced, int bpp, int width, int height,
  1568. unsigned char *data)
  1569. {
  1570. // unsigned char *end = data + width * height;
  1571. int left = interlaced ? width : width * height;
  1572. int cury = 0, pass = 0;
  1573. unsigned char *dp = data;
  1574. long fcode;
  1575. code_int v, i, ent, disp, hsize_reg;
  1576. int c, hshift;
  1577. // int skip = 8;
  1578. if(bpp <= 1)
  1579. {
  1580. g_init_bits = 3;
  1581. PUTBYTE(2, fp);
  1582. }
  1583. else
  1584. {
  1585. g_init_bits = bpp + 1;
  1586. PUTBYTE(bpp, fp);
  1587. }
  1588. /*
  1589. ** Set up the globals: g_init_bits - initial number of bits
  1590. ** g_outfile - pointer to output file
  1591. */
  1592. g_outfile = fp;
  1593. /*
  1594. ** Set up the necessary values
  1595. */
  1596. // offset = 0;
  1597. clear_flg = GIF_FALSE;
  1598. maxbits = BITS;
  1599. maxmaxcode = 1 << BITS;
  1600. maxcode = MAXCODE(n_bits = g_init_bits);
  1601. hsize = HSIZE;
  1602. cur_accum = 0;
  1603. cur_bits = 0;
  1604. ClearCode = (1 << (g_init_bits - 1));
  1605. EOFCode = ClearCode + 1;
  1606. free_ent = ClearCode + 2;
  1607. char_init(); /* clear the output accumulator */
  1608. hshift = 0;
  1609. for(fcode = long(hsize); fcode < 65536; fcode *= 2)
  1610. ++hshift;
  1611. hshift = 8 - hshift; /* set hash code range bound */
  1612. hsize_reg = hsize;
  1613. cl_hash(count_int(hsize)); /* clear hash table */
  1614. output(code_int(ClearCode));
  1615. ent = *dp++;
  1616. do
  1617. {
  1618. again:
  1619. /*
  1620. ** Fetch the next pixel
  1621. */
  1622. c = *dp++;
  1623. if(--left == 0)
  1624. {
  1625. if(interlaced)
  1626. {
  1627. do
  1628. {
  1629. switch(pass)
  1630. {
  1631. case 0:
  1632. cury += 8;
  1633. if(cury >= height)
  1634. {
  1635. pass++;
  1636. cury = 4;
  1637. }
  1638. break;
  1639. case 1:
  1640. cury += 8;
  1641. if(cury >= height)
  1642. {
  1643. pass++;
  1644. cury = 2;
  1645. }
  1646. break;
  1647. case 2:
  1648. cury += 4;
  1649. if(cury >= height)
  1650. {
  1651. pass++;
  1652. cury = 1;
  1653. }
  1654. break;
  1655. case 3:
  1656. cury += 2;
  1657. break;
  1658. }
  1659. } while(pass < 3 && cury >= height);
  1660. if(cury >= height)
  1661. goto done;
  1662. dp = data + cury * width;
  1663. left = width;
  1664. c = *dp++;
  1665. }
  1666. else
  1667. {
  1668. goto done;
  1669. }
  1670. }
  1671. /*
  1672. ** Now output it...
  1673. */
  1674. fcode = long((long(c) << maxbits) + ent);
  1675. i = ((code_int(c) << hshift) ^ ent); /* xor hashing */
  1676. v = HashTabOf(i);
  1677. if(v == fcode)
  1678. {
  1679. ent = CodeTabOf(i);
  1680. goto again;
  1681. }
  1682. else if(v >= 0)
  1683. {
  1684. /*
  1685. ** secondary hash (after G. Knott)
  1686. */
  1687. disp = hsize_reg - i;
  1688. if(i == 0)
  1689. disp = 1;
  1690. do
  1691. {
  1692. if((i -= disp) < 0)
  1693. i += hsize_reg;
  1694. v = HashTabOf(i);
  1695. if(v == fcode)
  1696. {
  1697. ent = CodeTabOf(i);
  1698. goto again;
  1699. }
  1700. } while(v > 0);
  1701. }
  1702. output(code_int(ent));
  1703. ent = c;
  1704. if(free_ent < maxmaxcode)
  1705. {
  1706. CodeTabOf(i) = free_ent++; /* code -> hashtable */
  1707. HashTabOf(i) = fcode;
  1708. }
  1709. else
  1710. {
  1711. cl_block();
  1712. }
  1713. } while(1);
  1714. done:
  1715. /*
  1716. ** Put out the final code.
  1717. **/
  1718. output(code_int(ent));
  1719. output(code_int(EOFCode));
  1720. /*
  1721. ** End block byte
  1722. */
  1723. PUTBYTE(0x00, fp);
  1724. }
  1725. #ifdef __sgi
  1726. #pragma reset woff 1209
  1727. #endif
  1728. /*****************************************************************
  1729. * TAG( output )
  1730. *
  1731. * Output the given code.
  1732. * Inputs:
  1733. * code: A n_bits-bit integer. If == -1, then EOF. This assumes
  1734. * that n_bits =< (long)wordsize - 1.
  1735. * Outputs:
  1736. * Outputs code to the file.
  1737. * Assumptions:
  1738. * Chars are 8 bits long.
  1739. * Algorithm:
  1740. * Maintain a BITS character long buffer (so that 8 codes will
  1741. * fit in it exactly). Use the VAX insv instruction to insert each
  1742. * code in turn. When the buffer fills up empty it and start over.
  1743. */
  1744. static unsigned long masks[] = { 0x0000,
  1745. 0x0001, 0x0003, 0x0007, 0x000F,
  1746. 0x001F, 0x003F, 0x007F, 0x00FF,
  1747. 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
  1748. 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
  1749. static void output(code_int code)
  1750. {
  1751. cur_accum &= masks[cur_bits];
  1752. if(cur_bits > 0)
  1753. {
  1754. cur_accum |= (long(code) << cur_bits);
  1755. }
  1756. else
  1757. cur_accum = code;
  1758. cur_bits += n_bits;
  1759. while(cur_bits >= 8)
  1760. {
  1761. char_out(static_cast<unsigned int>(cur_accum & 0xff));
  1762. cur_accum >>= 8;
  1763. cur_bits -= 8;
  1764. }
  1765. /*
  1766. ** If the next entry is going to be too big for the code size,
  1767. ** then increase it, if possible.
  1768. */
  1769. if(free_ent > maxcode || clear_flg)
  1770. {
  1771. if(clear_flg)
  1772. {
  1773. maxcode = MAXCODE(n_bits = g_init_bits);
  1774. clear_flg = GIF_FALSE;
  1775. }
  1776. else
  1777. {
  1778. ++n_bits;
  1779. if(n_bits == maxbits)
  1780. maxcode = maxmaxcode;
  1781. else
  1782. maxcode = MAXCODE(n_bits);
  1783. }
  1784. }
  1785. if(code == EOFCode)
  1786. {
  1787. /*
  1788. ** At EOF, write the rest of the buffer.
  1789. */
  1790. while(cur_bits > 0)
  1791. {
  1792. char_out(static_cast<unsigned int>(cur_accum & 0xff));
  1793. cur_accum >>= 8;
  1794. cur_bits -= 8;
  1795. }
  1796. flush_char();
  1797. fflush(g_outfile);
  1798. }
  1799. }
  1800. /*
  1801. * Clear out the hash table
  1802. */
  1803. static void cl_block(void)
  1804. {
  1805. cl_hash(count_int(hsize));
  1806. free_ent = ClearCode + 2;
  1807. clear_flg = GIF_TRUE;
  1808. output(code_int(ClearCode));
  1809. }
  1810. /* */
  1811. static void cl_hash(count_int hsize) /* reset code table */
  1812. {
  1813. int i;
  1814. for(i = 0; i < hsize; i++)
  1815. htab[i] = -1;
  1816. }
  1817. /******************************************************************************
  1818. *
  1819. * GIF Specific routines
  1820. *
  1821. ******************************************************************************/
  1822. /*
  1823. ** Number of characters so far in this 'packet'
  1824. */
  1825. static int a_count;
  1826. /*
  1827. ** Define the storage for the packet accumulator
  1828. */
  1829. static char accum[256];
  1830. /*
  1831. ** Set up the 'byte output' routine
  1832. */
  1833. static void char_init(void)
  1834. {
  1835. a_count = 0;
  1836. }
  1837. /*
  1838. ** Add a character to the end of the current packet, and if it is 254
  1839. ** characters, flush the packet to disk.
  1840. */
  1841. static void char_out(int c)
  1842. {
  1843. accum[a_count++] = c;
  1844. if(a_count == 255)
  1845. flush_char();
  1846. }
  1847. /*
  1848. ** Flush the packet to disk, and reset the accumulator
  1849. */
  1850. static void flush_char(void)
  1851. {
  1852. if(a_count != 0)
  1853. {
  1854. PUTBYTE(a_count, g_outfile);
  1855. fwrite(accum, 1, a_count, g_outfile);
  1856. a_count = 0;
  1857. }
  1858. }
  1859. //--- GIF-WRITE END -----------------------------------------------------
  1860. #endif