我现在做一个小软件,用TBitmap 自动生成图片。纯黑白: PixelFormat = pf1bit当图片改变大小的时候 Palette 会发生改变,虽然看上去颜色是对的,但 ScanLine 里的内容全反了。我知道可以重设 Palette,但这个方法会浪费时间。有没有别的办法,可以在改变图片大小的时候让其自动获得想要的 Palette,比如让黑色在内存里始终为 0。

解决方案 »

  1.   

    看了一个TBitmap的源码,好像似乎用PixelFormat = pf4bit 可以做到Palette不变procedure TBitmap.SetHeight(Value: Integer);
    var
      DIB: TDIBSection;
    begin
      with FImage do
        if FDIB.dsbm.bmHeight <> Value then
        begin
          HandleNeeded;
          DIB := FDIB;
          DIB.dsbm.bmHeight := Value;
          DIB.dsbmih.biHeight := Value;
          CopyImage(FHandle, FPalette, DIB);
          Changed(Self);
        end;
    end;
    procedure TBitmap.CopyImage(AHandle: HBITMAP; APalette: HPALETTE; DIB: TDIBSection);
    var
      NewHandle, NewPalette: THandle;
    begin
      FreeContext;
      NewHandle := 0;
      NewPalette := 0;
      try
        if APalette = SystemPalette16 then
          NewPalette := APalette
        else
          NewPalette := CopyPalette(APalette);
        NewHandle := CopyBitmap(AHandle, APalette, NewPalette, DIB, FCanvas);   // 这里改变了NewPalette,CopyBitmap代码好长
        NewImage(NewHandle, NewPalette, DIB, FImage.FOS2Format);
      except
        InternalDeletePalette(NewPalette);
        if NewHandle <> 0 then DeleteObject(NewHandle);
        raise;
      end;
    end;procedure TBitmap.SetPixelFormat(Value: TPixelFormat);
    const
      BitCounts: array [pf1Bit..pf32Bit] of Byte = (1,4,8,16,16,24,32);
    var
      DIB: TDIBSection;
      Pal: HPalette;
      DC: HDC;
      KillPal: Boolean;
    begin
      if Value = GetPixelFormat then Exit;
      case Value of
        pfDevice:
          begin
            HandleType := bmDDB;
            Exit;
          end;
        pfCustom: InvalidGraphic(@SInvalidPixelFormat);
      else
        FillChar(DIB, sizeof(DIB), 0);
        DIB.dsbm := FImage.FDIB.dsbm;
        KillPal := False;
        with DIB, dsbm, dsbmih do
        begin
          bmBits := nil;
          biSize := sizeof(DIB.dsbmih);
          biWidth := bmWidth;
          biHeight := bmHeight;
          biPlanes := 1;
          biBitCount := BitCounts[Value];
          Pal := FImage.FPalette;
          case Value of
            pf4Bit: Pal := SystemPalette16;     // 看来用pf4Bit是好主意
            pf8Bit:
              begin
                DC := GDICheck(GetDC(0));
                Pal := CreateHalftonePalette(DC);
                KillPal := True;
                ReleaseDC(0, DC);
              end;
            pf16Bit:
              begin
                biCompression := BI_BITFIELDS;
                dsBitFields[0] := $F800;
                dsBitFields[1] := $07E0;
                dsBitFields[2] := $001F;
              end;
          end;
          try
            CopyImage(Handle, Pal, DIB);
            PaletteModified := Pal <> 0;
          finally
            if KillPal then DeleteObject(Pal);
          end;
          Changed(Self);
        end;
      end;
    end;