00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "camtypes.h"
00010 #include "ensure.h"
00011 #include "fixmem.h"
00012 #include "errors.h"
00013 #include "progress.h"
00014
00015
00016 #include "gifutil.h"
00017
00018
00019
00020
00021 #include "camfiltr.h"
00022
00023 #define new CAM_DEBUG_NEW
00024
00025
00026 CC_IMPLEMENT_MEMDUMP(Palette, CC_CLASS_MEMDUMP)
00027 Palette::~Palette()
00028 {
00029 if (m_pColours)
00030 delete [] m_pColours;
00031 m_pColours = NULL;
00032 m_nSize = 0;
00033 }
00034
00035
00036
00037 Palette::Palette(const Palette& otherPalette)
00038 {
00039 if (&otherPalette == this) return;
00040
00041 if (otherPalette.m_nSize > m_nSize)
00042 delete [] m_pColours;
00043 m_pColours = new RGBQUAD[otherPalette.m_nSize];
00044 if (m_pColours == NULL)
00045 {
00046 m_bInitOK = FALSE;
00047 return;
00048 }
00049 m_nSize = otherPalette.m_nSize;
00050 memcpy(m_pColours, otherPalette.m_pColours, m_nSize);
00051 m_bInitOK = TRUE;
00052 }
00053
00054 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
00055
00056
00057 BOOL GIFUtil::Interlace = FALSE;
00058 int GIFUtil::Transparent = -1;
00059 UINT32 GIFUtil::m_Delay = 0;
00060 BOOL GIFUtil::ZeroDataBlock = FALSE;
00061 int GIFUtil::m_nCurrentBitmap = 0;
00062 GIFDisposalMethod GIFUtil::m_Restore = GDM_LEAVE;
00063
00064 LPRGBQUAD GIFUtil::lpGlobalPalette = NULL;
00065 int GIFUtil::GlobalPaletteSize = 0;
00066 FilePos GIFUtil::m_NextImageStartPosition = 0;
00067 BOOL GIFUtil::m_bImageRead = FALSE;
00068
00069 WORD GIFUtil::m_GlobalWidth = 0;
00070 WORD GIFUtil::m_GlobalHeight = 0;
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 BOOL GIFUtil::ReadFromFile( CCLexFile *File, LPBITMAPINFO *Info, LPBYTE *Bits,
00140 int *TransColour, String_64 *ProgressString,
00141 BaseCamelotFilter *pFilter )
00142 {
00143 int nBitmap = 1;
00144
00145 return (ReadFromFile( File, Info, Bits, TransColour, nBitmap, ProgressString, pFilter));
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 BOOL GIFUtil::ReadFromFile( CCLexFile *File, LPBITMAPINFO *Info, LPBYTE *Bits,
00163 int *TransColour, int& nBitmapToRead, String_64 *ProgressString,
00164 BaseCamelotFilter *pFilter, UINT32* Delay, GIFDisposalMethod *Restore,
00165 UINT32 * pLeftOffset, UINT32 * pTopOffset,
00166 BOOL * pLocalPalette)
00167 {
00168 if ((nBitmapToRead > 1 && nBitmapToRead == m_nCurrentBitmap) || nBitmapToRead < 1)
00169 {
00170 ERROR3("GIFUtil::ReadFromFile() - can't read that bitmap");
00171 return FALSE;
00172 }
00173
00174 *Info = NULL;
00175 *Bits = NULL;
00176 Transparent = -1;
00177 *TransColour = -1;
00178 int Background = 0;
00179 Interlace = FALSE;
00180
00181
00182
00183
00184
00185 BOOL OldThrowingState = File->SetThrowExceptions( TRUE );
00186 BOOL OldReportingState = File->SetReportErrors( FALSE );
00187
00188
00189
00190 if (ProgressString != NULL)
00191 BeginSlowJob(100, FALSE, ProgressString);
00192
00193 try
00194 {
00195
00196 if (nBitmapToRead == 1)
00197 {
00198
00199 lpGlobalPalette = NULL;
00200 GlobalPaletteSize = 0;
00201
00202 GIFINFOHEADER Header;
00203
00204
00205 const size_t HeaderSize = sizeof(char)* 6 + sizeof(WORD) * 2 + sizeof(BYTE) * 3;
00206
00207 File->read( &Header, HeaderSize );
00208 if (File->bad())
00209 File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
00210
00211
00212 if (
00213 (strncmp(Header.giName, "GIF89a", 6) != 0) &&
00214 (strncmp(Header.giName, "GIF87a", 6) != 0)
00215 )
00216 File->GotError( _R(IDE_BADFORMAT) );
00217
00218
00219 m_GlobalWidth = Header.giWidth;
00220 m_GlobalHeight = Header.giHeight;
00221
00222
00223
00224
00225
00226 int ColorResolution = (((Header.giFlags >> 4) & 0x07) + 1);
00227 GlobalPaletteSize = 2 << (Header.giFlags & 0x07);
00228 Background = Header.giBackground;
00229
00230
00231 TRACEUSER("Neville",_T("Gif Global Width = %d Height = %d\n"), m_GlobalWidth, m_GlobalHeight);
00232 TRACEUSER("Neville",_T("Gif ColorResolution = %d\n"), ColorResolution);
00233
00234
00235 if (BitSet(Header.giFlags, GLOBALCOLOURMAP))
00236 {
00237 TRACEUSER("Neville",_T("Gif read global colour table size = %d\n"), GlobalPaletteSize);
00238
00239 const size_t TotalPal = sizeof(RGBQUAD) * GlobalPaletteSize;
00240 lpGlobalPalette = (LPRGBQUAD)CCMalloc( TotalPal );
00241 if (lpGlobalPalette==NULL)
00242 return FALSE;
00243
00244 ReadColourMap(File, GlobalPaletteSize, lpGlobalPalette);
00245 }
00246 m_nCurrentBitmap = 0;
00247 m_NextImageStartPosition = 0;
00248 }
00249
00250
00251
00252
00253 BOOL FileProcessed = FALSE;
00254
00255 m_bImageRead = FALSE;
00256 unsigned char c;
00257
00258
00259
00260
00261
00262
00263 if (m_NextImageStartPosition != 0)
00264 {
00265 File->seekIn(m_NextImageStartPosition, ios::beg);
00266 m_NextImageStartPosition = 0;
00267 }
00268
00269 while (!File->eof() && !File->bad() && !FileProcessed)
00270 {
00271
00272
00273
00274
00275
00276 File->get( (char&)c );
00277
00278 switch (c)
00279 {
00280 case ';':
00281 {
00282
00283
00284
00285 FileProcessed = TRUE;
00286 nBitmapToRead = -1;
00287 break;
00288 }
00289
00290 case '!':
00291 {
00292
00293 ProcessExtension(File);
00294 break;
00295 }
00296
00297 case ',':
00298 {
00299
00300 if (m_bImageRead)
00301 {
00302 if (m_NextImageStartPosition == 0)
00303 {
00304
00305 m_NextImageStartPosition = File->tellIn() - 1;
00306 }
00307 ++nBitmapToRead;
00308 FileProcessed = TRUE;
00309 break;
00310 }
00311
00312 UINT32 LeftOffset = 0;
00313 UINT32 TopOffset = 0;
00314 BOOL LocalPalette = FALSE;
00315
00316
00317 ProcessImageBlock(File, Info, Bits, &LeftOffset, &TopOffset, &LocalPalette);
00318 ++m_nCurrentBitmap;
00319
00320 if (nBitmapToRead == m_nCurrentBitmap)
00321 {
00322 m_bImageRead = TRUE;
00323 }
00324
00325
00326 if (pLeftOffset)
00327 *pLeftOffset = LeftOffset;
00328 if (pTopOffset)
00329 *pTopOffset = TopOffset;
00330 if (pLocalPalette)
00331 *pLocalPalette = LocalPalette;
00332 break;
00333 }
00334
00335 default:
00336
00337
00338
00339
00340
00341
00342 if (m_bImageRead)
00343 {
00344
00345
00346 FileProcessed = TRUE;
00347 nBitmapToRead = -1;
00348 }
00349 TRACE( _T("Unrecognized Character %x at %d\n"), (int)c, File->tellIn());
00350
00351 break;
00352 }
00353 }
00354
00355
00356
00357
00358 if (*Info == NULL || *Bits == NULL)
00359 File->GotError( _R(IDE_BADFORMAT) );
00360
00361
00362
00363 if (m_bImageRead && File->eof())
00364 {
00365 TRACE( _T("GIF: Premature end of file") );
00366 nBitmapToRead = -1;
00367 }
00368
00369
00370 *TransColour = Transparent;
00371 if (Delay)
00372 {
00373 *Delay = m_Delay;
00374 }
00375 if (Restore)
00376 {
00377 *Restore = m_Restore;
00378 }
00379
00380
00381 if (lpGlobalPalette && nBitmapToRead == -1)
00382 {
00383 CCFree(lpGlobalPalette);
00384 lpGlobalPalette = NULL;
00385 }
00386
00387
00388 if (ProgressString != NULL)
00389 EndSlowJob();
00390
00391
00392 File->SetThrowExceptions( OldThrowingState );
00393 File->SetReportErrors( OldReportingState );
00394
00395
00396 return TRUE;
00397 }
00398 catch( CFileException e )
00399 {
00400
00401 TRACE( _T("GIFUtil::ReadFromFile CC catch handler\n") );
00402
00403 FreeDIB( *Info, *Bits );
00404 *Info = NULL;
00405 *Bits = NULL;
00406
00407
00408 if (lpGlobalPalette)
00409 {
00410 CCFree(lpGlobalPalette);
00411 lpGlobalPalette = NULL;
00412 }
00413
00414
00415 if (ProgressString != NULL)
00416 EndSlowJob();
00417
00418
00419 File->SetThrowExceptions( OldThrowingState );
00420 File->SetReportErrors( OldReportingState );
00421
00422 return FALSE;
00423 }
00424
00425 ERROR2( FALSE, "Escaped exception clause somehow" );
00426 }
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 BOOL GIFUtil::ProcessExtension(CCLexFile *fd)
00444 {
00445 static char buf[256];
00446
00447
00448 unsigned char ExtensionType;
00449 fd->read( &ExtensionType, 1 );
00450
00451 switch (ExtensionType)
00452 {
00453 case TRANSPARENTBLOCK:
00454 {
00455
00456
00457 m_NextImageStartPosition = fd->tellIn() - 2;
00458
00459
00460
00461
00462 GIFTRANSBLOCK TransBlock;
00463
00464
00465
00466 const size_t TransBlockSize = sizeof(WORD) * 1 + sizeof(BYTE) * 6;
00467 fd->read( &(TransBlock.gtbBlockSize), TransBlockSize - 2);
00468
00469
00470
00471
00472
00473 if (!m_bImageRead)
00474 {
00475 BOOL fTrans = TransBlock.gtbFlags & 0x1;
00476 if (fTrans != 0)
00477 Transparent = TransBlock.gtbTransparency;
00478 else
00479 {
00480 Transparent = -1;
00481 }
00482
00483 TRACEUSER("Neville", _T("ProcessExtension - transparent fTrans = %d Transparent = %d\n"), fTrans, Transparent );
00484
00485
00486 m_Delay = TransBlock.gtbDelay;
00487 m_Restore = GIFDisposalMethod((TransBlock.gtbFlags >> 2) & 0x03);
00488 }
00489
00490 return TRUE;
00491 }
00492
00493 case PLAINTEXTBLOCK:
00494 {
00495
00496
00497
00498
00499 if (m_bImageRead)
00500 {
00501
00502
00503 m_NextImageStartPosition = 0;
00504 }
00505 else
00506 {
00507
00508 Transparent = -1;
00509 }
00510
00511 }
00512
00513 default:
00514 break;
00515 }
00516
00517
00518
00519
00520 ZeroDataBlock = FALSE;
00521
00522
00523 while (GetDataBlock(fd, (unsigned char*) buf) != 0)
00524 ;
00525
00526 return FALSE;
00527 }
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543 BOOL GIFUtil::ReadColourMap(CCLexFile *fd, int number, LPRGBQUAD lpPalette)
00544 {
00545 GIFRGBTRIPLE rgb;
00546 for (int i = 0; i < number; ++i)
00547 {
00548 fd->read( &rgb, sizeof(GIFRGBTRIPLE) );
00549 lpPalette->rgbBlue = rgb.grgbtBlue;
00550 lpPalette->rgbGreen = rgb.grgbtGreen;
00551 lpPalette->rgbRed = rgb.grgbtRed;
00552 lpPalette->rgbReserved = 0;
00553 lpPalette++;
00554 }
00555
00556 return TRUE;
00557 }
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 int GIFUtil::GetDataBlock(CCLexFile *fd, unsigned char *buf)
00579 {
00580 unsigned char count;
00581
00582
00583
00584 if (ZeroDataBlock)
00585 return 0;
00586
00587 fd->read( &count, 1 );
00588
00589
00590
00591 if (count == 0)
00592 {
00593 ZeroDataBlock = TRUE;
00594
00595 }
00596 else
00597 {
00598 ZeroDataBlock = FALSE;
00599 fd->read( buf, count );
00600
00601 }
00602
00603 return count;
00604 }
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622 int GIFUtil::GetCode(CCLexFile *fd, int code_size, int flag)
00623 {
00624 static unsigned char buf[280];
00625 static int curbit;
00626 static int lastbit;
00627 static int done;
00628 static int last_byte;
00629 int i;
00630 int j;
00631 int ret;
00632 unsigned char count;
00633
00634 if (flag)
00635 {
00636 curbit = 0;
00637 lastbit = 0;
00638 done = FALSE;
00639 return 0;
00640 }
00641
00642 if ( (curbit+code_size) >= lastbit)
00643 {
00644 if (done)
00645 {
00646 if (curbit >= lastbit)
00647 {
00648
00649 }
00650 return -1;
00651 }
00652 buf[0] = buf[last_byte-2];
00653 buf[1] = buf[last_byte-1];
00654
00655 if ((count = GetDataBlock(fd, &buf[2])) == 0)
00656 done = TRUE;
00657
00658 last_byte = 2 + count;
00659 curbit = (curbit - lastbit) + 16;
00660 lastbit = (2+count)*8 ;
00661 }
00662
00663 ret = 0;
00664 for (i = curbit, j = 0; j < code_size; ++i, ++j)
00665 ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
00666
00667 curbit += code_size;
00668
00669 return ret;
00670 }
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689 int GIFUtil::LWZReadByte(CCLexFile *fd, int flag, int input_code_size)
00690 {
00691 static int fresh = FALSE;
00692 int code;
00693 int incode;
00694 static int code_size;
00695 static int set_code_size;
00696 static int max_code;
00697 static int max_code_size;
00698 static int firstcode;
00699 static int oldcode;
00700 static int clear_code;
00701 static int end_code;
00702 static int table[2][(1<< MAX_LWZ_BITS)];
00703 static int stack[(1<<(MAX_LWZ_BITS))*2];
00704 static int *sp;
00705 int i;
00706
00707 if (flag)
00708 {
00709 set_code_size = input_code_size;
00710 code_size = set_code_size+1;
00711 clear_code = 1 << set_code_size ;
00712 end_code = clear_code + 1;
00713 max_code_size = 2*clear_code;
00714 max_code = clear_code+2;
00715
00716 GetCode(fd, 0, TRUE);
00717
00718 fresh = TRUE;
00719
00720 for (i = 0; i < clear_code; ++i)
00721 {
00722 table[0][i] = 0;
00723 table[1][i] = i;
00724 }
00725 for (; i < (1<<MAX_LWZ_BITS); ++i)
00726 table[0][i] = table[1][0] = 0;
00727
00728 sp = stack;
00729
00730 return 0;
00731 }
00732 else if (fresh)
00733 {
00734 fresh = FALSE;
00735 do
00736 {
00737 firstcode = oldcode = GetCode(fd, code_size, FALSE);
00738 } while (firstcode == clear_code);
00739
00740 return firstcode;
00741 }
00742
00743 if (sp > stack)
00744 return *--sp;
00745
00746 while ((code = GetCode(fd, code_size, FALSE)) >= 0)
00747 {
00748 if (code == clear_code)
00749 {
00750 for (i = 0; i < clear_code; ++i)
00751 {
00752 table[0][i] = 0;
00753 table[1][i] = i;
00754 }
00755
00756 for (; i < (1<<MAX_LWZ_BITS); ++i)
00757 table[0][i] = table[1][i] = 0;
00758
00759 code_size = set_code_size+1;
00760 max_code_size = 2*clear_code;
00761 max_code = clear_code+2;
00762 sp = stack;
00763 firstcode = oldcode = GetCode(fd, code_size, FALSE);
00764
00765 return firstcode;
00766 }
00767 else if (code == end_code)
00768 {
00769 int count;
00770 unsigned char buf[260];
00771
00772 if (ZeroDataBlock)
00773 return -2;
00774
00775 while ((count = GetDataBlock(fd, buf)) > 0)
00776 ;
00777
00778 if (count != 0)
00779 return -2;
00780 }
00781
00782 incode = code;
00783
00784 if (code >= max_code)
00785 {
00786 *sp++ = firstcode;
00787 code = oldcode;
00788 }
00789
00790 while (code >= clear_code)
00791 {
00792 *sp++ = table[1][code];
00793 if (code == table[0][code])
00794 {
00795
00796 }
00797 code = table[0][code];
00798 }
00799
00800 *sp++ = firstcode = table[1][code];
00801
00802 if ((code = max_code) <(1<<MAX_LWZ_BITS))
00803 {
00804 table[0][code] = oldcode;
00805 table[1][code] = firstcode;
00806 ++max_code;
00807 if ((max_code >= max_code_size) && (max_code_size < (1<<MAX_LWZ_BITS)))
00808 {
00809 max_code_size *= 2;
00810 ++code_size;
00811 }
00812 }
00813
00814 oldcode = incode;
00815
00816 if (sp > stack)
00817 return *--sp;
00818 }
00819 return code;
00820 }
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848 BOOL GIFUtil::ReadImage(CCLexFile *fd, LPBYTE pBitsData, int width, int height, int bpp,
00849 BOOL interlace, BaseCamelotFilter *pFilter)
00850 {
00851 ERROR2IF(pBitsData == NULL, FALSE, "GIFUtil::ReadImage given null pointer to bits data");
00852 ERROR2IF(bpp != 8 && bpp != 4 && bpp != 1, FALSE, "GIFUtil::ReadImage - bpp invalid");
00853
00854 unsigned char c;
00855 int v = 0;
00856 int xpos = 0;
00857 int ypos = 0;
00858 int pass = 0;
00859 int yposcount = 0;
00860
00861 ZeroDataBlock = FALSE;
00862
00863
00864 int UpdateEvery = 1;
00865 INT32 UpdateValue = 1;
00866 if (pFilter == NULL)
00867 UpdateEvery = height/100 + 1;
00868 else
00869 {
00870
00871
00872
00873
00874
00875
00876 INT32 RecordSize = pFilter->GetCurrentRecordSize();
00877 if (RecordSize == 0)
00878 RecordSize = 1;
00879 UpdateValue = RecordSize/height;
00880 UpdateEvery = 0;
00881 }
00882
00883 int LastProgressUpdate = 0;
00884
00885
00886 INT32 WidthOfLine = DIBUtil::ScanlineSize( width, bpp );
00887
00888
00889 fd->read( &c, 1 );
00890 ERROR3IF(c > GIFBITS,"Bad code size in GIFUtil ReadImage");
00891
00892 if (LWZReadByte(fd, TRUE, c) < 0)
00893 {
00894 return FALSE;
00895 }
00896
00897 while ((v = LWZReadByte(fd, FALSE, c)) >= 0 )
00898 {
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909 if (bpp == 8)
00910 {
00911
00912 LPBYTE pData = pBitsData + xpos + ((height - 1 - ypos) * WidthOfLine);
00913 *(pData) = v;
00914 }
00915 else if (bpp == 4)
00916 {
00917
00918
00919
00920
00921 LPBYTE pData = pBitsData + xpos/2 + ((height - 1 - ypos) * WidthOfLine);
00922
00923 if (xpos & 1)
00924 *(pData) = ((*(pData)) & 0xF0) | (v & 0x0F);
00925 else
00926 *(pData) = ((*(pData)) & 0x0F) | ((v << 4) & 0xF0);
00927 }
00928 else if (bpp == 1)
00929 {
00930
00931
00932
00933
00934 LPBYTE pOutputBitmap = pBitsData + (xpos / 8) + ((height - 1 - ypos) * WidthOfLine);
00935
00936 UINT32 BitPosition = 7 - (xpos % 8);
00937 BYTE SetBit = v << BitPosition;
00938 BYTE Mask = ~(1 << BitPosition);
00939
00940 *pOutputBitmap = ((*pOutputBitmap) & Mask) | SetBit;
00941 }
00942 else
00943 {
00944 ERROR3IF(TRUE, "GIFUtil::ReadImage() - Invalid bpp");
00945
00946 }
00947
00948
00949
00950 ++xpos;
00951
00952 BOOL JobState = TRUE;
00953
00954
00955 if (xpos >= width)
00956 {
00957 xpos = 0;
00958
00959
00960 if (interlace)
00961 {
00962
00963 switch (pass)
00964 {
00965 case 0:
00966 case 1:
00967 ypos += 8; break;
00968 case 2:
00969 ypos += 4; break;
00970 case 3:
00971 ypos += 2; break;
00972 }
00973
00974 while (ypos >= height && pass <= 3)
00975 {
00976 ++pass;
00977 switch (pass)
00978 {
00979 case 1:
00980 ypos = 4;
00981 break;
00982 case 2:
00983 ypos = 2;
00984 break;
00985 case 3:
00986 ypos = 1;
00987 break;
00988 default:
00989 goto finish;
00990 }
00991 }
00992 }
00993 else
00994 {
00995
00996 ++ypos;
00997 }
00998
00999 yposcount++;
01000
01001 if (yposcount > (LastProgressUpdate + UpdateEvery))
01002 {
01003
01004 LastProgressUpdate = yposcount;
01005
01006
01007 if (pFilter == NULL)
01008 JobState = ContinueSlowJob( (long)(100 * yposcount/height) );
01009 else
01010 JobState = pFilter->IncProgressBarCount(UpdateValue);
01011
01012
01013
01014 if (!JobState)
01015 {
01016 fd->GotError( _R(IDW_CANCELLEDBMPIMPORT) );
01017 return FALSE;
01018 }
01019 }
01020 }
01021
01022 if (ypos >= height)
01023 break;
01024 }
01025
01026 finish:
01027 if (LWZReadByte(fd, FALSE, c) >= 0)
01028 {
01029
01030 }
01031
01032
01033 return TRUE;
01034 }
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079 BOOL Palette::SetSize(const UINT32 nNewSize)
01080 {
01081 if (nNewSize == m_nSize) return TRUE;
01082 if (m_pColours != NULL)
01083 {
01084 delete [] m_pColours;
01085 }
01086 if (nNewSize == 0)
01087 {
01088 m_pColours = NULL;
01089 return TRUE;
01090 }
01091 m_pColours = new RGBQUAD[nNewSize];
01092
01093
01094 return (m_pColours == NULL) ? FALSE : TRUE;
01095 }
01096
01097
01098 static BOOL ReadColourMap(CCLexFile *fd, Palette& NewPalette)
01099 {
01100 GIFRGBTRIPLE rgb;
01101 PaletteIterator PalColour;
01102 for (PalColour = NewPalette.Start(); PalColour < NewPalette.End(); ++PalColour)
01103 {
01104 fd->read(&rgb, sizeof(GIFRGBTRIPLE));
01105
01106 PalColour.SetBlue(rgb.grgbtBlue);
01107 PalColour.SetGreen(rgb.grgbtGreen);
01108 PalColour.SetRed(rgb.grgbtRed);
01109 PalColour.SetTransparent(0);
01110 }
01111
01112 return TRUE;
01113 }
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128 BOOL GIFUtil::ProcessHeader()
01129 {
01130 ERROR3("GIFUtil::ProcessHeader : not implemented");
01131 if (TRUE) return FALSE;
01132
01133 CCLexFile* File;
01134 GIFINFOHEADER Header;
01135
01136
01137 const size_t HeaderSize = sizeof(char)* 6 + sizeof(WORD) * 2 + sizeof(BYTE) * 3;
01138
01139
01140 File->read( &Header, HeaderSize );
01141 if (File->bad())
01142 File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01143
01144
01145 if (
01146 ( strncmp( Header.giName, "GIF89a", 6 ) != 0 ) &&
01147 ( strncmp( Header.giName, "GIF87a", 6 ) != 0 )
01148 )
01149 File->GotError( _R(IDE_BADFORMAT) );
01150
01151
01152 m_GlobalWidth = Header.giWidth;
01153 m_GlobalHeight = Header.giHeight;
01154
01155
01156
01157 UINT32 nGlobalPaletteSize = 2 << (Header.giFlags & 0x07);
01158
01159
01160
01161 if (BitSet(Header.giFlags, GLOBALCOLOURMAP))
01162 {
01163
01164 if (m_GlobalPalette.SetSize(nGlobalPaletteSize) == FALSE)
01165 {
01166 ERROR3("GIFUtil::ProcessHeader() - can't renew palette");
01167 return FALSE;
01168 }
01169 ::ReadColourMap(File, m_GlobalPalette);
01170 }
01171 m_nCurrentBitmap = 0;
01172 }
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190 BOOL GIFUtil::ProcessImageBlock(CCLexFile* File, LPBITMAPINFO *Info, LPBYTE *Bits,
01191 UINT32 * pLeftOffset, UINT32 * pTopOffset, BOOL * pLocalPalette)
01192 {
01193 GIFIMAGEBLOCK ImageBlock;
01194
01195 const size_t ImageHeaderSize = sizeof(WORD) * 4 + sizeof(BYTE) * 1;
01196 File->read( &ImageBlock, ImageHeaderSize );
01197
01198
01199
01200 BOOL UseLocalColourMap = BitSet(ImageBlock.gibFlags, LOCALCOLOURMAP);
01201 int LocalColourMapSize = 1 << ((ImageBlock.gibFlags & 0x07) + 1);
01202
01203 int Width = ImageBlock.gibWidth;
01204 int Height = ImageBlock.gibDepth;
01205
01206
01207
01208 if (pLeftOffset && ImageBlock.gibLeft < m_GlobalWidth)
01209 *pLeftOffset = ImageBlock.gibLeft;
01210 if (pTopOffset && ImageBlock.gibTop < m_GlobalHeight)
01211 *pTopOffset = ImageBlock.gibTop;
01212 if (pLocalPalette)
01213 *pLocalPalette = UseLocalColourMap;
01214
01215 Interlace = BitSet(ImageBlock.gibFlags, INTERLACE);
01216
01217 int ColoursInPalette = UseLocalColourMap ? LocalColourMapSize : GlobalPaletteSize;
01218 int BitsPerPixel;
01219 if (ColoursInPalette > 16)
01220 BitsPerPixel = 8;
01221 else if (ColoursInPalette > 2)
01222 BitsPerPixel = 4;
01223 else
01224 BitsPerPixel = 1;
01225
01226 TRACEUSER("Neville", _T("Colours in palette = %d bpp = %d\n"), ColoursInPalette, BitsPerPixel );
01227
01228
01229
01230 if ((BitsPerPixel != 8) && (BitsPerPixel != 4) && (BitsPerPixel != 1) && (Width != 0) && (Height != 0))
01231 File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01232
01233
01234 *Info = AllocDIB( Width, Height, BitsPerPixel, Bits, NULL );
01235
01236 if (*Info == NULL || *Bits == NULL)
01237 File->GotError( _R(IDS_OUT_OF_MEMORY) );
01238
01239
01240
01241 BOOL ok = FALSE;
01242 if (UseLocalColourMap)
01243 {
01244
01245
01246 if (LocalColourMapSize > (1 << BitsPerPixel))
01247 File->GotError( _R(IDE_BADFORMAT) );
01248
01249 ReadColourMap(File, LocalColourMapSize, (*Info)->bmiColors);
01250 }
01251 else
01252 {
01253
01254 if (lpGlobalPalette && ((*Info)->bmiColors))
01255 {
01256 const size_t TotalPal = sizeof(RGBQUAD) * GlobalPaletteSize;
01257 memcpy((*Info)->bmiColors, lpGlobalPalette, TotalPal);
01258 }
01259 }
01260
01261
01262 (*Info)->bmiHeader.biClrUsed = ColoursInPalette;
01263
01264 ok = ReadImage(File, *Bits, Width, Height, BitsPerPixel, Interlace);
01265
01266 if (!ok)
01267 File->GotError( _R(IDE_BADFORMAT) );
01268
01269 return TRUE;
01270 }
01271
01272