Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- {$IF NOT DEFINED(CLR)}
- procedure TBitmap.ReadDIB(Stream: TStream; ImageSize: LongWord; bmf: PBitmapFileHeader);
- const
- DIBPalSizes: array [Boolean] of Byte = (SizeOf(TRGBQuad), SizeOf(TRGBTriple));
- var
- DC, MemDC: HDC;
- BitsMem: Pointer;
- OS2Header: TBitmapCoreHeader;
- BitmapInfo: PBitmapInfo;
- ColorTable: Pointer;
- HeaderSize: Integer;
- OS2Format: Boolean;
- BMHandle, OldBMP: HBITMAP;
- DIB: TDIBSection;
- Pal, OldPal: HPalette;
- RLEStream: TStream;
- vbmf: TBitmapFileHeader;
- {$IFDEF LINUX}
- I: Integer;
- {$ENDIF}
- begin
- Pal := 0;
- BMHandle := 0;
- RLEStream := nil;
- Stream.Read(HeaderSize, SizeOf(HeaderSize));
- OS2Format := HeaderSize = SizeOf(OS2Header);
- if OS2Format then
- HeaderSize := SizeOf(TBitmapInfoHeader);
- GetMem(BitmapInfo, HeaderSize + 12 + 256 * SizeOf(TRGBQuad));
- with BitmapInfo^ do
- try
- try
- if OS2Format then // convert OS2 DIB to Win DIB
- begin
- Stream.Read(Pointer(PByte(@OS2Header) + SizeOf(HeaderSize))^,
- SizeOf(OS2Header) - SizeOf(HeaderSize));
- FillChar(bmiHeader, SizeOf(bmiHeader), 0);
- with bmiHeader, OS2Header do
- begin
- biWidth := bcWidth;
- biHeight := bcHeight;
- biPlanes := bcPlanes;
- biBitCount := bcBitCount;
- end;
- Dec(ImageSize, SizeOf(OS2Header));
- end
- else
- begin // support bitmap headers larger than TBitmapInfoHeader
- Stream.Read(Pointer(PByte(BitmapInfo) + SizeOf(HeaderSize))^,
- HeaderSize - SizeOf(HeaderSize));
- Dec(ImageSize, HeaderSize);
- if (bmiHeader.biCompression <> BI_BITFIELDS) and
- (bmiHeader.biCompression <> BI_RGB) then
- begin // Preserve funky non-DIB data (like RLE) until modified
- RLEStream := TMemoryStream.Create;
- // source stream could be unidirectional. don't reverse seek
- if bmf = nil then
- begin
- FillChar(vbmf, SizeOf(vbmf), 0);
- vbmf.bfType := $4D42;
- vbmf.bfSize := ImageSize + Cardinal(HeaderSize);
- bmf := @vbmf;
- end;
- RLEStream.Write(bmf^, SizeOf(bmf^));
- RLEStream.Write(HeaderSize, SizeOf(HeaderSize));
- RLEStream.Write(Pointer(PByte(BitmapInfo) + SizeOf(HeaderSize))^,
- HeaderSize - SizeOf(HeaderSize));
- RLEStream.CopyFrom(Stream, ImageSize);
- { Cast ImageSize (long word) to integer to avoid integer overflow when negating. }
- RLEStream.Seek(-Integer(ImageSize), soFromEnd);
- Stream := RLEStream; // the rest of the proc reads from RLEStream
- end;
- end;
- with bmiHeader do
- begin
- biSize := HeaderSize;
- ColorTable := Pointer(PByte(BitmapInfo) + HeaderSize);
- { check number of planes. DIBs must be 1 color plane (packed pixels) }
- if biPlanes <> 1 then InvalidBitmap;
- // 3 DWORD color element bit masks (ie 888 or 565) can precede colors
- // TBitmapInfoHeader sucessors include these masks in the headersize
- if (HeaderSize = SizeOf(TBitmapInfoHeader)) and
- ((biBitCount = 16) or (biBitCount = 32)) and
- (biCompression = BI_BITFIELDS) then
- begin
- Stream.ReadBuffer(ColorTable^, 3 * SizeOf(DWORD));
- Inc(PByte(ColorTable), 3 * SizeOf(DWORD));
- Dec(ImageSize, 3 * SizeOf(DWORD));
- end;
- // Read the color palette
- if biClrUsed = 0 then
- biClrUsed := GetDInColors(biBitCount);
- if (biClrUsed * DIBPalSizes[OS2Format]) > (256 * SizeOf(TRGBQuad)) then
- InvalidGraphic({$IFNDEF CLR}@{$ENDIF}SInvalidBitmap);
- Stream.ReadBuffer(ColorTable^, biClrUsed * DIBPalSizes[OS2Format]);
- Dec(ImageSize, biClrUsed * DIBPalSizes[OS2Format]);
- // biSizeImage can be zero. If zero or RGB, compute the size.
- if (biSizeImage = 0) or (biCompression = BI_RGB) then // top-down DIBs have negative height
- biSizeImage := BytesPerScanLine(biWidth, biBitCount, 32) * Abs(biHeight);
- if biSizeImage < ImageSize then
- ImageSize := biSizeImage;
- end;
- { convert OS2 color table to DIB color table }
- if OS2Format then RGBTripleToQuad(ColorTable^);
- DC := GDICheck(GetDC(0));
- try
- if ((bmiHeader.biCompression <> BI_RGB) and
- (bmiHeader.biCompression <> BI_BITFIELDS)) or DDBsOnly then
- begin
- MemDC := 0;
- GetMem(BitsMem, ImageSize);
- try
- Stream.ReadBuffer(BitsMem^, ImageSize);
- MemDC := GDICheck(CreateCompatibleDC(DC));
- OldBMP := SelectObject(MemDC, CreateCompatibleBitmap(DC, 1, 1));
- OldPal := 0;
- if bmiHeader.biClrUsed > 0 then
- begin
- Pal := PaletteFromDIBColorTable(0, ColorTable, bmiHeader.biClrUsed);
- OldPal := SelectPalette(MemDC, Pal, False);
- RealizePalette(MemDC);
- end;
- try
- BMHandle := CreateDIBitmap(MemDC, BitmapInfo^.bmiHeader, CBM_INIT, BitsMem,
- BitmapInfo^, DIB_RGB_COLORS);
- if (BMHandle = 0) then
- if GetLastError = 0 then
- InvalidBitmap else RaiseLastOSError;
- finally
- if OldPal <> 0 then
- SelectPalette(MemDC, OldPal, True);
- DeleteObject(SelectObject(MemDC, OldBMP));
- end;
- finally
- if MemDC <> 0 then DeleteDC(MemDC);
- FreeMem(BitsMem);
- end;
- end
- else
- begin
- BMHandle := CreateDIBSection(DC, BitmapInfo^, DIB_RGB_COLORS, BitsMem, 0, 0);
- if (BMHandle = 0) or (BitsMem = nil) then
- if GetLastError = 0 then
- InvalidBitmap else RaiseLastOSError;
- try
- {$IFDEF LINUX}
- // I need to pre-touch the memory in 4096 byte increments to ensure
- // the read will succeed. WINE marks this memory as not present to
- // catch when we make changes to it. If we read directly into it
- // Linux will (correctly) terminate the read with a failure since an
- // exception occured during the read. We need to make sure these
- // exceptions are triggered in user space instead of kernel.
- for I := 1 to (ImageSize + 4095) div 4096 do
- PByteArray(BitsMem)^[(I - 1) * 4096] := 0;
- {$ENDIF}
- Stream.ReadBuffer(BitsMem^, ImageSize);
- except
- DeleteObject(BMHandle);
- raise;
- end;
- end;
- finally
- ReleaseDC(0, DC);
- end;
- // Hi-color DIBs don't preserve color table, so create palette now
- // 16 bit or more do not have a color palette.
- if (bmiHeader.biBitCount > 8) and (bmiHeader.biBitCount <= 16) and
- (bmiHeader.biClrUsed > 0) and (Pal = 0)then
- Pal := PaletteFromDIBColorTable(0, ColorTable, bmiHeader.biClrUsed);
- FillChar(DIB, SizeOf(DIB), 0);
- GetObject(BMHandle, Sizeof(DIB), @DIB);
- // GetObject / CreateDIBSection don't preserve these info values
- DIB.dsBmih.biXPelsPerMeter := bmiHeader.biXPelsPerMeter;
- DIB.dsBmih.biYPelsPerMeter := bmiHeader.biYPelsPerMeter;
- DIB.dsBmih.biClrUsed := bmiHeader.biClrUsed;
- DIB.dsBmih.biClrImportant := bmiHeader.biClrImportant;
- except
- RLEStream.Free;
- raise;
- end;
- finally
- FreeMem(BitmapInfo);
- end;
- NewImage(BMHandle, Pal, DIB, OS2Format, RLEStream);
- if (FImage.FDIB.dsBMIh.biBitCount = 32) and (FAlphaFormat = afDefined) then
- PreMultiplyAlpha;
- PaletteModified := Palette <> 0;
- Changed(Self);
- end;
- {$ENDIF}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement