2 // Copyright (c) 1998-1999 Matra Datavision
3 // Copyright (c) 1999-2012 OPEN CASCADE SAS
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
21 // Read()/Write() code is taken from ZOV's sources from Xw package.
22 // _convert24to8() sources and all concerned code is taken from
23 // EUG's code of WNT_ImageProcessor.
25 #define TEST //GG_140699
26 // Check GIF format first.
29 //it is important to undefine NOGDI and enforce including <windows.h> before
30 //Standard_Macro.hxx defines it and includes <windows.h> making GDI-related
31 //stuff unavailable and causing compilation errors
36 #include <AlienImage_GIFAlienData.ixx>
37 #include <AlienImage_GIFLZWDict.hxx>
39 #include <Aspect_GenericColorMap.hxx>
40 #include <Aspect_ColorMapEntry.hxx>
41 #include <Image_Convertor.hxx>
42 #include <Image_DitheringMethod.hxx>
49 # include <OSD_Timer.hxx>
52 #define STGMGR_ALLOC(size) Standard::Allocate(size)
53 #define STGMGR_FREE(buf,size) Standard::Free((void*&)buf)
54 #define COLORS_SIZE 256*sizeof(BYTE)
55 #define RED ((PBYTE)myRedColors)
56 #define GREEN ((PBYTE)myGreenColors)
57 #define BLUE ((PBYTE)myBlueColors)
58 #define PIXEL ((PBYTE)myData)
60 #define ZERO_COLORS() \
61 memset (myRedColors, 0, COLORS_SIZE); \
62 memset (myGreenColors, 0, COLORS_SIZE); \
63 memset (myBlueColors, 0, COLORS_SIZE);
65 #define _ADD_PIXEL(idx) \
68 *((PBYTE)myData + y*width + x) = ((BYTE)(idx)); \
71 if (!isInterlace) ++y; \
72 else switch (pass) { \
73 case 0: y += 8; if (y >= height) ++pass, y = 4; break; \
74 case 1: y += 8; if (y >= height) ++pass, y = 2; break; \
75 case 2: y += 4; if (y >= height) ++pass, y = 1; break; \
81 //================================================================
82 AlienImage_GIFAlienData::AlienImage_GIFAlienData()
83 : AlienImage_AlienImageData ()
94 //================================================================
95 void AlienImage_GIFAlienData::Clear ()
98 STGMGR_FREE (myRedColors, COLORS_SIZE);
102 STGMGR_FREE (myGreenColors, COLORS_SIZE);
103 myGreenColors = NULL;
106 STGMGR_FREE (myBlueColors, COLORS_SIZE);
111 STGMGR_FREE (myData, myWidth*myHeight);
113 myWidth = myHeight = 0;
117 //================================================================
118 Standard_Boolean AlienImage_GIFAlienData::Read (OSD_File& file)
120 Standard_Integer nFileSize = file.Size(), nReadCount;
121 unsigned *OutCode=NULL, *Prefix=NULL, *Suffix=NULL,
122 BitMask, CodeSize, ClearCode, EOFCode, FreeCode, x, y, pass, width, height,
123 InitCodeSize, MaxCode, ReadMask, FirstFree, OutCount, BitOffset,
124 ByteOffset, Code, CurCode, OldCode=0, FinChar=0, InCode;
125 int isInterlace, hasColormap;
128 PBYTE pFileStream = NULL;
129 // Allocate memory to read the file
131 (PBYTE) STGMGR_ALLOC (nFileSize);
132 PBYTE rasterPtr = NULL, ptr1;
133 pFileStream = pFileBuffer + 10;
137 cout << "AlienImage_GIFAlienData::Read () starts" << endl << flush;
141 // Read file into memory
142 file.Read ((void*&)pFileBuffer, nFileSize, nReadCount);
143 if (nFileSize != nReadCount) {
144 cout << "GIFAlienData::Read() : BAD file size." << endl << flush;
149 if( strncmp ((char*)pFileBuffer, "GIF87a", 6) &&
150 strncmp ((char*)pFileBuffer, "GIF89a", 6) )
154 // Determine if the image has colormap
155 byte = *pFileStream++; // Color descriptor byte (M#CR0#BP)
156 hasColormap = byte & 0x80;
157 ncolors = hasColormap ? 1<<((byte & 0x07) + 1): 1<<8;
158 BitMask = ncolors - 1;
160 pFileStream += 2; // Skip background byte and following zero byte
161 if (ncolors > 0 && ncolors <= 256) { // Allocate Color Table entries
162 myRedColors = STGMGR_ALLOC (COLORS_SIZE);
163 myGreenColors = STGMGR_ALLOC (COLORS_SIZE);
164 myBlueColors = STGMGR_ALLOC (COLORS_SIZE);
167 for (i=0; i<ncolors; i++) {
168 // Fill in array of XColor's used
169 // Note, that if there's no colormap specified then I use gray scale
170 RED [i] = ((BYTE)(hasColormap ? *pFileStream++: i));
171 GREEN[i] = ((BYTE)(hasColormap ? *pFileStream++: i));
172 BLUE [i] = ((BYTE)(hasColormap ? *pFileStream++: i));
175 cout << "GIFAlienData::Read() : There's no colormap"
176 << " in the image (or too big): " << ncolors << endl << flush;
180 // Skip extension blocks if any.
181 // Format: <'!'><size><...><size><...><0>
182 while (*pFileStream == '!') {
183 pFileStream += 2; // skip code byte followed '!' sign
185 pFileStream += (unsigned)(1 + *(PBYTE)pFileStream);
189 if (*pFileStream++ != ',') { // must be an image descriptor
190 cout << "GIFAlienData::Read() : There's no separator"
191 << " following the colormap" << endl << flush;
195 pFileStream += 2*2; // Skip image left & top offsets
196 width = (unsigned) *pFileStream++;
197 width += ((unsigned)*pFileStream++) << 8;
198 height = (unsigned) *pFileStream++;
199 height += ((unsigned)*pFileStream++) << 8;
201 byte = *pFileStream++;
202 isInterlace = byte & 0x40;
204 cout << "GIFAlienData::Read() : Can't read GIF image"
205 << " with locally defined colormap" << endl << flush;
209 // Allocate the pixel buffer
210 rasterPtr = (PBYTE) STGMGR_ALLOC (nFileSize);
212 OutCode = (unsigned *) STGMGR_ALLOC (1025 * sizeof (unsigned int));
213 Prefix = (unsigned *) STGMGR_ALLOC (4096 * sizeof (unsigned int));
214 Suffix = (unsigned *) STGMGR_ALLOC (4096 * sizeof (unsigned int));
216 // Decode compressed raster data.
217 CodeSize = *pFileStream++;
218 ClearCode = 1 << CodeSize;
219 EOFCode = ClearCode + 1;
220 FreeCode = FirstFree = EOFCode + 1;
223 InitCodeSize = CodeSize;
224 MaxCode = 1 << CodeSize;
225 ReadMask = MaxCode - 1;
228 // Read encoded data to a continuous array pointed to by rasterPtr
230 byte = byte1 = *pFileStream++;
232 *ptr1++ = *pFileStream++;
233 if ((long) (ptr1 - rasterPtr) > nFileSize) {// Currupt file
234 cout << "GIFAlienData::Read() : BAD file size." << endl << flush;
238 // The file data has been already read
239 STGMGR_FREE (pFileBuffer, nFileSize);
242 // Allocate image data
245 myData = STGMGR_ALLOC (myWidth*myHeight);
247 x = y = pass = OutCount = BitOffset = ByteOffset = 0;
248 // Fetch the next code (3 to 12 bits) from the raster data stream
249 Code = rasterPtr[0] + (((unsigned) rasterPtr[1]) << 8);
251 Code += ((unsigned) rasterPtr[2]) << 16;
253 Code >>= BitOffset & 0x7;
254 BitOffset += CodeSize;
257 while (Code != EOFCode) {
258 if (Code == ClearCode) {
259 // Read the next code
260 CodeSize = InitCodeSize;
261 MaxCode = 1 << CodeSize;
262 ReadMask = MaxCode - 1;
263 FreeCode = FirstFree;
264 ByteOffset = BitOffset >> 3;
265 Code = rasterPtr[ByteOffset]
266 + (((unsigned) rasterPtr[ByteOffset + 1]) << 8);
269 Code += ((unsigned) rasterPtr[ByteOffset + 2]) << 16;
271 Code >>= BitOffset & 0x7;
272 BitOffset += CodeSize;
275 CurCode = OldCode = Code;
276 FinChar = CurCode & BitMask;
278 _ADD_PIXEL (FinChar);
280 CurCode = InCode = Code;
281 if (CurCode >= FreeCode) {
283 OutCode[OutCount++] = FinChar;
285 while (CurCode > BitMask) {
286 if (OutCount > 1024) {
287 cout << "GIFAlienData::Read() : BAD file size." << endl << flush;
290 OutCode [OutCount++] = Suffix [CurCode];
291 CurCode = Prefix [CurCode];
293 FinChar = CurCode & BitMask;
294 OutCode [OutCount++] = FinChar;
295 for (i = OutCount - 1; i >= 0; --i)
296 _ADD_PIXEL (OutCode [i]);
299 Prefix [FreeCode] = OldCode;
300 Suffix [FreeCode] = FinChar;
303 if (FreeCode >= MaxCode) {
307 ReadMask = (1 << CodeSize) - 1;
312 ByteOffset = BitOffset >> 3;
313 Code = (unsigned) rasterPtr[ByteOffset]
314 + (((unsigned) rasterPtr[ByteOffset + 1]) << 8);
317 Code += ((unsigned) rasterPtr[ByteOffset + 2]) << 16;
319 Code >>= (BitOffset & 0x7);
320 BitOffset += CodeSize;
322 } // while (Code != EOFCode)
324 // Free allocated memory
325 STGMGR_FREE (rasterPtr, nFileSize);
326 STGMGR_FREE (OutCode, 1025 * sizeof (unsigned int));
327 STGMGR_FREE (Prefix, 4096 * sizeof (unsigned int));
328 STGMGR_FREE (Suffix, 4096 * sizeof (unsigned int));
332 cout << "AlienImage_GIFAlienData::Read () finished\n" << endl << flush;
334 return Standard_True;
337 // cout << "GIFAlienData::Read() : Read file error." << endl << flush;
338 if (pFileBuffer) STGMGR_FREE (pFileBuffer, nFileSize);
339 if (OutCode) STGMGR_FREE (OutCode, 1025 * sizeof (unsigned int));
340 if (Prefix) STGMGR_FREE (Prefix, 4096 * sizeof (unsigned int));
341 if (Suffix) STGMGR_FREE (Suffix, 4096 * sizeof (unsigned int));
343 STGMGR_FREE (myRedColors, COLORS_SIZE);
347 STGMGR_FREE (myGreenColors, COLORS_SIZE);
348 myGreenColors = NULL;
351 STGMGR_FREE (myBlueColors, COLORS_SIZE);
355 STGMGR_FREE (myData, myWidth*myHeight);
357 myWidth = myHeight = 0;
360 return Standard_False;
363 //================================================================
364 Standard_Boolean AlienImage_GIFAlienData::Write (OSD_File& file) const
368 BYTE image_sep = 0x2C; // gif colormap delimiter
370 BYTE colors256 [256][3];
376 cout << "AlienImage_GIFAlienData::Write () starts" << endl << flush;
379 // Check if image is loaded
380 if (myData == NULL || myRedColors == NULL ||
381 myGreenColors == NULL || myBlueColors == NULL ||
382 myWidth == 0 || myHeight == 0)
383 goto _ExitWriteError;
386 memcpy (sd.gifID, "GIF87a", 6);
387 sd.scrnWidth = SWAP_WORD ((WORD) myWidth );
388 sd.scrnHeight = SWAP_WORD ((WORD) myHeight);
389 sd.scrnFlag = 0x80 | ( ( 7/*[=depth-1]*/ << 4 ) & 0x70 ) | 0x07;
392 id.imgWidth = SWAP_WORD ((WORD) myWidth );
393 id.imgHeight = SWAP_WORD ((WORD) myHeight);
395 // +-+-+-+-+-+-----+ M=0 - Use global color map, ignore 'pixel'
396 // |M|I|0|0|0|pixel| 10 M=1 - Local color map follows, use 'pixel'
397 // +-+-+-+-+-+-----+ I=0 - Image formatted in Sequential order
398 // I=1 - Image formatted in Interlaced order
399 // pixel+1 - # bits per pixel for this image
400 id.imgFlag = 0x07; // Global color map, Sequential order, 8 bits per pixel
402 for (i = 0; i < 256; i++) {
403 colors256[i] [0/*R*/] = RED [i];
404 colors256[i] [1/*G*/] = GREEN [i];
405 colors256[i] [2/*B*/] = BLUE [i];
408 // Write off the buffers
409 file.Write (&sd, 11); // Screen descriptor
411 goto _ExitWriteError;
413 file.Write (&wZero, 2); // Zero word
415 goto _ExitWriteError;
417 file.Write (colors256, 256*3); // Colormap
419 goto _ExitWriteError;
421 file.Write (&image_sep, 1); // Separator
423 goto _ExitWriteError;
425 file.Write (&id, 9); // Image descriptor
427 goto _ExitWriteError;
429 // Write off the image data
430 if (!_lzw_encode (file, (PBYTE) myData, myWidth, myHeight, myWidth))
431 goto _ExitWriteError;
433 file.Write (&bEnd, 1); // End of image
435 goto _ExitWriteError;
437 // Return SUCCESS status if there were no errors.
441 cout << "AlienImage_GIFAlienData::Write () finished\n" << endl << flush;
443 return Standard_True;
447 file.Seek (0, OSD_FromBeginning);
448 return Standard_False;
451 //================================================================
452 Handle_Image_Image AlienImage_GIFAlienData::ToImage () const
456 cout << "AlienImage_GIFAlienData::ToImage () starts" << endl << flush;
459 Standard_Integer i, x, y, LowX, LowY;
460 Standard_Real r, g, b;
461 Aspect_ColorMapEntry entry;
462 Aspect_IndexPixel index;
463 Quantity_Color color;
466 Handle(Aspect_GenericColorMap) aColorMap =
467 new Aspect_GenericColorMap ();
468 for (i = 0; i < 256; i++) {
469 r = ((float)RED [i] / 255.);
470 g = ((float)GREEN [i] / 255.);
471 b = ((float)BLUE [i] / 255.);
472 color.SetValues (r, g, b, Quantity_TOC_RGB);
473 entry.SetValue (i, color);
474 aColorMap -> AddEntry (entry);
478 Handle(Image_Image) theImage =
479 new Image_PseudoColorImage (0, 0, myWidth, myHeight, aColorMap);
480 LowX = theImage -> LowerX ();
481 LowY = theImage -> LowerY ();
482 for (y = 0; y < myHeight; y++) {
483 for (x = 0; x < myWidth; x++) {
484 index.SetValue (PIXEL[y*myWidth + x]);
485 theImage -> SetPixel (LowX + x, LowY + y, index);
491 cout << "AlienImage_GIFAlienData::ToImage () finished\n" << endl << flush;
496 //================================================================
497 void AlienImage_GIFAlienData::FromImage (const Handle_Image_Image& anImage)
499 if (anImage -> Type() == Image_TOI_PseudoColorImage) {
500 // Build from PseudoColorImage
501 Handle(Image_PseudoColorImage) aPImage =
502 Handle(Image_PseudoColorImage)::DownCast(anImage);
503 FromPseudoColorImage (aPImage);
504 } else if (anImage -> Type() == Image_TOI_ColorImage) {
505 // Build from ColorImage
506 Handle(Image_ColorImage) aCImage =
507 Handle(Image_ColorImage)::DownCast(anImage);
508 FromColorImage (aCImage);
510 // Unknown type of image
511 Standard_TypeMismatch_Raise_if (Standard_True,
512 "Attempt to convert a unknown Image_Image type to a GIFAlienData");
516 //================================================================
517 void AlienImage_GIFAlienData::FromPseudoColorImage (
518 const Handle(Image_PseudoColorImage)& anImage)
520 int width = anImage -> Width ();
521 int height = anImage -> Height ();
522 unsigned short x, y, i;
523 Standard_Real r, g, b;
524 Aspect_ColorMapEntry entry;
525 Aspect_IndexPixel index;
526 Quantity_Color color;
527 Standard_Integer LowX = anImage -> LowerX();
528 Standard_Integer LowY = anImage -> LowerY();
533 cout << "AlienImage_GIFAlienData::FromPseudoColorImage () starts" << endl << flush;
536 if (width*height > 0) {
537 Handle(Aspect_ColorMap) aColorMap = anImage -> ColorMap ();
538 // Clear old values if any
541 myRedColors = STGMGR_ALLOC (COLORS_SIZE);
542 myGreenColors = STGMGR_ALLOC (COLORS_SIZE);
543 myBlueColors = STGMGR_ALLOC (COLORS_SIZE);
546 // Build colors from colormap
547 for (i = 1; i <= aColorMap -> Size (); i++) {
548 entry = aColorMap -> Entry (i);
550 color = entry.Color ();
551 color.Values (r, g, b, Quantity_TOC_RGB);
552 RED [ei] = (BYTE)(r*255.);
553 GREEN[ei] = (BYTE)(g*255.);
554 BLUE [ei] = (BYTE)(b*255.);
557 // Build imagedata from Image_PseudoColorImage
560 myData = STGMGR_ALLOC (myWidth*myHeight);
561 for (y = 0; y < myHeight; y++) {
562 for (x = 0; x < myWidth; x++) {
563 index = anImage -> Pixel (LowX + x, LowY + y);
564 PIXEL[y*myWidth + x] = (BYTE)index.Value ();
571 cout << "AlienImage_GIFAlienData::FromPseudoColorImage () finished\n" << endl << flush;
575 //================================================================
576 void AlienImage_GIFAlienData::FromColorImage (
577 const Handle(Image_ColorImage)& anImage)
581 cout << "AlienImage_GIFAlienData::FromColorImage () starts" << endl << flush;
585 int width = anImage -> Width ();
586 int height = anImage -> Height ();
587 int i, x, y, LowX = anImage -> LowerX(), LowY = anImage -> LowerY();
588 Quantity_Color color;
589 Standard_Real r, g, b;
591 if (width*height > 0) {
592 Aspect_ColorMapEntry entry;
593 // Clear old values if any
597 LPRGBQUAD pColors = (LPRGBQUAD) STGMGR_ALLOC (256*sizeof(RGBQUAD));
598 PBYTE pBits24 = (PBYTE) STGMGR_ALLOC (width*height*3);
599 memset (pColors, 0, 256*sizeof(RGBQUAD));
601 myData = STGMGR_ALLOC (width*height);
602 myRedColors = STGMGR_ALLOC (COLORS_SIZE);
603 myGreenColors = STGMGR_ALLOC (COLORS_SIZE);
604 myBlueColors = STGMGR_ALLOC (COLORS_SIZE);
606 for (y = 0, i = 0; y < myHeight; y++) {
607 for (x = 0; x < myWidth; x++) {
608 color = anImage -> PixelColor (LowX + x, LowY + y);
609 color.Values (r, g, b, Quantity_TOC_RGB);
610 pBits24 [i + 0] = (BYTE)(b*255.);
611 pBits24 [i + 1] = (BYTE)(g*255.);
612 pBits24 [i + 2] = (BYTE)(r*255.);
617 if (_convert24to8 (pColors, pBits24, (PBYTE)myData, myWidth, myHeight)) {
618 Handle(Aspect_GenericColorMap) aColorMap = new Aspect_GenericColorMap ();
619 for (i = 0; i < 256; i++) {
620 r = ((float)pColors[i].rgbRed / 255.);
621 g = ((float)pColors[i].rgbGreen / 255.);
622 b = ((float)pColors[i].rgbBlue / 255.);
623 color.SetValues (r, g, b, Quantity_TOC_RGB);
624 entry.SetValue (i, color);
625 aColorMap -> AddEntry (entry);
626 RED [i] = pColors[i].rgbRed;
627 GREEN[i] = pColors[i].rgbGreen;
628 BLUE [i] = pColors[i].rgbBlue;
631 Image_Convertor aConvertor;
632 aConvertor.SetDitheringMethod (Image_DM_ErrorDiffusion);
633 Handle(Aspect_ColorMap) aColorMap = anImage -> ChooseColorMap (256);
634 Handle(Image_PseudoColorImage) aPImage =
635 aConvertor.Convert (anImage, aColorMap);
636 FromPseudoColorImage (aPImage);
639 STGMGR_FREE (pColors, 256*sizeof(RGBQUAD));
640 STGMGR_FREE (pBits24, width*height*3);
646 cout << "AlienImage_GIFAlienData::FromColorImage () finished\n" << endl << flush;