Domanda

Ho cercato sul web per ore, ma non riesco a trovare nulla su come ottenere la tavolozza da un tpicture.graphic. Devo anche ottenere i valori di colore in modo da poter passare questi valori a una lista Tstring per riempire le celle in un colorpicker.

Ecco il codice che ho attualmente:

procedure TFormMain.OpenImage1Click( Sender: TObject );
var
  i: integer;
  S: TStringList;
  AColor: TColor;
  AColorCount: integer;
  N: string;
  Pal: PLogPalette;
  HPal: hPalette;
begin
  if OpenPictureDialog1.Execute then
  begin
    Screen.Cursor := crHourGlass;
    try
      Pal := nil;
      try
        S := TStringList.Create;
        ABitmap.Free; // Release any existing bitmap
        ABitmap := TBitmap.Create;
        Image1.Picture.LoadFromFile( OpenPictureDialog1.Filename );
        ABitmap.Canvas.Draw( 0, 0, Image1.Picture.Graphic );
        GetMem( Pal, Sizeof( TLogPalette ) + Sizeof( TPaletteEntry ) * 255 );
        Pal.palversion := $300;
        Pal.palnumentries := 256;
        for i := 0 to 255 do
        begin
          AColor := Pal.PalPalEntry[ i ].PeRed shl 16 + Pal.PalPalEntry[ i ].PeGreen shl 8 + Pal.PalPalEntry[ i ].PeBlue;
          N := ColorToString( AColor );
          S.Add( N );
        end;
        HPal := CreatePalette( Pal^ );
        ABitmap.Palette := HPal;
        Memo1.Lines := S;
      finally; FreeMem( Pal ); end;
      S.Free;
    finally; Screen.Cursor := crDefault; end;
  end;
end;

Sto attingendo alla tela di AbitMap con l'immagine contenuta in Image1.Picture.Graphic Perché voglio supportare tutti i tipi di immagini TPicture come Bitmap, JPEG, PNGIMAGE e GIFIMG.

Qualsiasi assistenza sarebbe apprezzata. Sono sul percorso corretto o è necessario qualcosa di diverso?

È stato utile?

Soluzione

Il codice che hai pubblicato non fa davvero nulla. Devi leggere la palette dalla bitmap prima di poter accedervi, oppure devi creare una tavolozza e assegnarla a una bitmap - il tuo codice non fa nessuno dei due.

Il seguente codice è più o meno tuo, con campi fBitmap e fBitmapPalEntries Per i risultati dell'operazione. Ho commentato tutte le righe che ho cambiato:

  if OpenPictureDialog1.Execute then
  begin
    Screen.Cursor := crHourGlass;
    try
      Pal := nil;
      try
        S := TStringList.Create;
        fBitmap.Free; // Release any existing bitmap
        fBitmap := TBitmap.Create;
// if you want a 256 colour bitmap with a palette you need to say so
        fBitmap.PixelFormat := pf8bit;
        Image1.Picture.LoadFromFile( OpenPictureDialog1.Filename );
        fBitmap.Canvas.Draw( 0, 0, Image1.Picture.Graphic );
// access the palette only if bitmap has indeed one
        if fBitmap.Palette <> 0 then begin
          GetMem( Pal, Sizeof( TLogPalette ) + Sizeof( TPaletteEntry ) * 255 );
          Pal.palversion := $300;
          Pal.palnumentries := 256;
// read palette data from bitmap
          fBitmapPalEntries := GetPaletteEntries(fBitmap.Palette, 0, 256,
            Pal.palPalEntry[0]);
          for i := 0 to fBitmapPalEntries - 1 do
          begin
            AColor := Pal.PalPalEntry[ i ].PeRed shl 16
                    + Pal.PalPalEntry[ i ].PeGreen shl 8
                    + Pal.PalPalEntry[ i ].PeBlue;
            N := ColorToString( AColor );
            S.Add( N );
          end;
// doesn't make sense, the palette is already there
//        HPal := CreatePalette( Pal^ );
//        fBitmap.Palette := HPal;
          Memo1.Lines := S;
        end;
      finally; FreeMem( Pal ); end;
      S.Free;
    finally; Screen.Cursor := crDefault; end;
  end;

Il supporto per le palette con meno voci è facile, devi solo riallocare la memoria dopo aver saputo quante voci ci sono, qualcosa di simile

ReallocMem(Pal, SizeOf(TLogPalette) + SizeOf(TPaletteEntry) * (fBitmapPalEntries - 1));

La creazione di una tavolozza sarebbe necessaria solo se si desidera scrivere una bitmap pf4Bit o pf8Bit formato. Dovresti determinare i 16 o 256 colori che sono voci della tavolozza, possibilmente riducendo il numero di colori (dithering). Quindi riempiresti gli slot di colore della palette con i valori di colore e infine useresti le due righe che ho commentato dal tuo codice. Devi assicurarti che il formato pixel della bitmap e il numero di voci della tavolozza corrisponda.

Altri suggerimenti

Una meravigliosa risorsa di grafica alogitmi è disponibile su La libreria di riferimento di EFG che include una sezione specifica che si occupa solo di colore. Specificamente questo L'articolo (con la fonte) discute il conteggio dei colori disponibili e potrebbe essere del miglior utilizzo.

Non mi conosco, ma potresti dare un'occhiata XN Editor alle risorse, che visualizza le informazioni sulla tavolozza, è scritto in Delphi e ha una fonte disponibile.

Grazie a tutti .... specialmente Mghie. Siamo riusciti a far funzionare molto bene il codice per i file BMP, PNG e GIF e immagini PF1bit, PF4bit, PF8bit, PF16bit e PF24bit. Stiamo ancora tenendo il codice ma finora sembra funzionare molto bene. Spero che questo codice aiuti anche altri sviluppatori.

var
  i: integer;
  fStringList: TStringList;
  fColor: TColor;
  fColorString: string;
  fPal: PLogPalette;
  fBitmapPalEntries: Cardinal;
begin
  if OpenPictureDialog1.Execute then
  begin
    Screen.Cursor := crHourGlass;
    try
      fPal := nil;
      try
        fStringList := TStringList.Create;
        Image1.Picture.LoadFromFile( OpenPictureDialog1.Filename );
        if Image1.Picture.Graphic.Palette <> 0 then
        begin
          GetMem( fPal, Sizeof( TLogPalette ) + Sizeof( TPaletteEntry ) * 255 );
          fPal.palversion := $300;
          fPal.palnumentries := 256;
          fBitmapPalEntries := GetPaletteEntries( Image1.Picture.Graphic.Palette, 0, 256, fPal.palPalEntry[ 0 ] );
          for i := 0 to fBitmapPalEntries - 1 do
          begin
            fColor := fPal.PalPalEntry[ i ].PeBlue shl 16
              + fPal.PalPalEntry[ i ].PeGreen shl 8
              + fPal.PalPalEntry[ i ].PeRed;
            fColorString := ColorToString( fColor );
            fStringList.Add( fColorString );
          end;
        end;
      finally; FreeMem( fPal ); end;
      if fStringList.Count = 0 then
        ShowMessage('No palette entries!')
      else
      // add the colors to the colorpicker here
      fStringList.Free;
    finally; Screen.Cursor := crDefault; end;
  end;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top