Artigo: 319061 - Última revisão: segunda-feira, 11 de Dezembro de 2006 - Revisão: 4.7

Como guardar um ficheiro .gif com uma nova tabela de cores utilizando o Visual C#

Dica do SistemaEste artigo aplica-se a um sistema operativo diferente do que está a utilizar. Foi desactivado o conteúdo do artigo, que pode não ser relevante para si.

Nesta página

Expandir tudo | Reduzir tudo

Sumário

A CompuServe formato GIF (Graphics Interchange) destina-se com um máximo de 256 cores são dispostas numa tabela de cores. Para efectuar modificações comuns para um ficheiro de imagem .gif, tem de alterar uma tabela de cores personalizado. No entanto, quando System.Drawing edita um objecto de imagem e, em seguida, é solicitado para guardar a imagem com o codificador GIF, o ficheiro .gif resultante contém uma tabela de cores de meio-tom.

Para guardar uma imagem com uma tabela de cores personalizado utilizando o codificador GIF, tem de trabalhar com uma cópia de 256 cores da imagem que não tenha modificado System.Drawing .

Noções sobre ficheiros .gif que são escritos por System.Drawing e GDI +

O ficheiro de imagem .gif pode expressar um máximo de 256 cores. Porque cor é um recurso no ficheiro .gif escassa, optimizar essas cores é uma tarefa pedida frequentemente. Para afectar uma tabela de cores optimizada, tem de ser possível definir qualquer tabela de cores personalizado arbitrário num ficheiro GIF.

O espaço de nomes System.Drawing é principalmente um wrapper em redor de GDI +, refere-, por isso, este artigo se o espaço de nomes como GDI + a menos que é discutido comportamento é específico do espaço de nomes System.Drawing , nesse caso, o termo System.Drawing é utilizado.

Depois de GDI + modifica uma imagem e, em seguida, escreve uma imagem num ficheiro utilizando o codificador GIF, GDI + escreve o ficheiro utilizando uma paleta de meios-tons ao qual bits o objecto de imagem de tem sido reduzido de cores. GDI + é uma conversão de cores de 32 bits por pixel (32 BPP) quando escreve a imagem o ficheiro porque são efectuadas todas as modificações à imagem de GDI + 32-BPP motor de gráficos.

Apesar de GDI + suporta a criação de imagens e os mapas de bits de vários formatos de pixel e, por isso, é possível carregar uma imagem .gif, a utilização do motor de gráficos 32 BPP necessita a conversão para 32 BPP quando estes forem modificados por GDI +. No entanto, uma imagem ou um mapa de bits que é não modificados por GDI + mantém o formato de pixel original e pode ser escrito num ficheiro utilizando o método Guardar com o codificador adequado. Esta propriedade é a base para uma técnica que pode guardar uma imagem de um ficheiro .gif com uma tabela de cores personalizado.

Escrever um ficheiro com uma tabela de cores personalizado .gif

Pode escrever um mapa de bits não tendo sido modificados com o codificador GIF e manter a tabela de cores do mapa de bits intactos; assim, pode utilizar este método para guardar um ficheiro .gif com uma nova tabela de cores.

O método é copiar os dados de imagem de um objecto de imagem original para um objecto temporário do mapa de bits . Este mapa de bits temporário é criado como um BPP 8 indexado mapa de bits , que é o formato pixel é utilizado para guardar um ficheiro .gif. A tabela de cores do mapa de bits é definida pelo utilizando o método SetPalette e, em seguida, a definição de imagem é copiada para o mapa de bits temporário. Depois de criar o mapa de bits temporário com uma definição de duplicados, pode utilizar o método Save() guardá-lo com o codificador GIF, que mantém a tabela de cores 8 BPP.

Para escrever uma imagem .gif para um ficheiro com uma tabela de cores personalizado, siga estes passos:
  1. Crie um objecto mapa de bits duplicado é o mesmo tamanho que a imagem de origem.
  2. Defina tabela do objecto de mapa de bits de cor personalizada para a tabela de cores pretendido.
  3. Utilize o método LockBits para ter acesso de escrita aos bits de imagem da cópia.
  4. Criar uma definição de imagem na cópia escrevendo índices de cor para a memória que é obtida a partir do LockBits duplicar os pixels na imagem original.
  5. Utilize UnLockBits para libertar os bits de imagem.
  6. Utilize a cópia de mapa de bits com a tabela de cores personalizado para guardar a imagem para um ficheiro utilizando o codificador GIF e Guardar .
  7. Liberte a cópia de mapa de bits da imagem .

Utilizar o código de exemplo

O código de exemplo neste artigo demonstra como utilizar Bitmap.Save para escrever um ficheiro .gif com uma tabela de cores personalizado de tamanho arbitrário. O código não está optimizado para desempenho porque é o objectivo de demonstração apenas. As oportunidades melhores para optimização estão a ser o pixel ciclos de processamento. GetPixel é uma abstracção conveniente do formato de pixels, mas é reconhecidamente lenta. O código de exemplo seria muito mais rápido se LockBits que utilizou para aceder directamente o formato de pixel. Para aumentar a velocidade, não utilize o método GetPixel e de abstracção de classe de cor . Para melhorar o desempenho, rescreva a conversão de escala de cinzentos utilizando matemático de número inteiro, em vez de vírgula flutuante.

A função de exemplo assume os quatro parâmetros seguintes:
  • Qualquer objecto de imagem de GDI +.
  • O nome de ficheiro para o ficheiro de destino.
  • O número de cores para o ficheiro .gif.
  • Um sinalizador que indica se é necessária uma cor transparente.
A função cria primeiro um objecto de mapa de bits que tem o formato de pixels do PixelFormat.Format8BPPIndexed porque é que o objecto que é guardado para criar o ficheiro .gif com nColors . Em seguida, é criada uma paleta de cores com as cores personalizadas. O ficheiro .gif obtém o tamanho e entradas específicas para a tabela de cores a partir ColorPalette do objecto de mapa de bits . O código de exemplo cria uma escala de cinzentos para fins de demonstração porque esse algoritmo é fácil de expandir através de vários tamanhos de tabela de cores.

Para criar o ficheiro .gif, terá de inicializar o objecto de mapa de bits BPP 8 com a definição de imagem que está a ser escrito no ficheiro. No código de exemplo, um conjunto central de ciclos é utilizado para cor converter a imagem de entrada essencialmente a preto e branca TV colorimetria.

Para fins de demonstração, os pixels de imagem de origem são acedidos por meio do método GetPixel() de um objecto de mapa de bits que é uma cópia da imagem de origem. É efectuada uma cópia de mapa de bits porque a classe de imagem não implementa o método GetPixel() .

Pode utilizar outras técnicas para acessar os pixels, tal como o acesso directo aos pixels utilizando o método de LockBits() ou interoperabilidade com código não gerido nativo Windows GDI DIB secções . Quando utiliza a função de BitBlt para copiar um mapa de bits de HDC GDI + para uma secção de DIB GDI memória o controlador de domínio, GBitBlt funciona utiliza a cor de correspondência de capacidades de GDI.

Depois de criar a cópia de mapa de bits , utilize o método Guardar com o objecto ImageFormat.gif para escrever o mapa de bits no ficheiro de destino.



Ficheiros GIF com menos de 256 cores

O codec GIF na GDI + versão 1.0 codifica apenas GDI + imagens que são BPP 8. Todos os outros formatos de imagem são convertidos antes de codificação. Este código de utilizar o formato de mapa de bits BPP 8 para escrever ficheiros .gif que tenham menos de 256 cores porque o codec GIF reconhece 8 BPP mapa de bits objectos com menos de 256 cores pela propriedade Palette.Count .

Para obter mais informações sobre o codec GIF, consulte a secção "References" deste artigo.

Infelizmente, a classe ColorPalette do espaço de nomes System.Drawing no .NET Framework não é possível criar instâncias independente de um objecto de mapa de bits . Esta é uma restrição apenas a classe System.Drawing.Bitmap impõe no .NET Framework; no entanto, para utilizar a abordagem neste artigo, o objecto de mapa de bits tem de ter um novo objecto ColorPalette com menos cores que não seja a predefinida 256 ColorPalette .

Para alcançar isso, o código de exemplo define uma função denominada GetColorPalette . Esta função cria um objecto mapa de bits temporário com uma profundidade de cor perto para o número pedido das cores. Em seguida, a função referencia a propriedade paleta e devolve-ao autor da chamada. Isto cria um novo ColorPalette com um dos vários contagens de cores possíveis: 256 cores, 16 cores ou duas cores (monocromático). Embora possa criar tabelas de cores nos ficheiros .gif que são mais pequeno do que 256 cores, cores tabelas estão limitadas a tamanhos de uma potência de dois.

Quando limitar tamanhos de tabela de cores a uma potência de dois, minimize espaço desperdiçado. A tabela de cores resultante neste exemplo é a cores de 8 (2 x 2 x 2). Com o código de exemplo, o ficheiro .gif seria possível criar com uma tabela de cores de 16 cores porque que é o menor PixelFormat para um mapa de bits que acomoda seis cores.

O código do ciclo de processamento que copia definições de pixel a imagem para a 8 BPP mapa de bits tem em consideração o tamanho da paleta quando o código calcula o valor de índice de um pixel. O codec GIF limita o tamanho da paleta e restringe a definição da imagem valores de índice que são compatíveis com o tamanho de paleta (ou seja, a tabela de cores GIF potencial) e, por isso, pode criar ficheiros .gif com menos de 256 cores.

GIF transparência

No código de exemplo, a rotina de criação ColorPalette define a primeira entrada seja a cor transparente GIF para demonstram a utilização da funcionalidade de transparência. O código faz isso configurando o componente Alpha da entrada de cor para ZERO. O código de exemplo neste artigo é para fins de demonstração, por conseguinte, a cor de transparência é uma opção arbitrária e pode ter resultados inesperados que dependem totalmente a imagem de origem.

O codificador GIF identifica a primeira cor ColorPalette que tem um valor Alpha de ZERO como a cor transparente. Isto significa que a cor transparente não terá de ser a primeira entrada ColorPalette . Pode ser qualquer um dos possíveis 256 cores na paleta de cores, o desde que todas as entradas anteriores contêm componentes alfa com valores de zero. Quaisquer entradas posteriores com alfa componente valores de ZERO serão ignoradas. Todas as entradas de zero alfa componentes são consideradas opacas.

GIF/LZW licenciamento problema

Microsoft obteve uma licença de Unisys para utilizar o formato de ficheiro .gif e outras tecnologias LZW abrangidos pela propriedade Unisys dos Estados Unidos e patentes estrangeiras numa variedade de produtos da Microsoft. No entanto, esta licença não expande para os programadores de outros fabricantes que utilizam produtos de desenvolvimento da Microsoft ou conjuntos de ferramentas para desenvolver aplicações. Como programador de outros fabricantes, terá de determinar se tem de obter uma licença a partir do Unisys para utilizar o formato .gif ou tecnologias LZW.

Para obter informações adicionais sobre licenças LZW e GIF, clique no número de artigo existente abaixo para visualizar o artigo na base de dados de conhecimento da Microsoft:
193543  (http://support.microsoft.com/kb/193543/EN-US/ ) INFO: Unisys GIF e informações de licença LZW Technology

Código de exemplo

protected ColorPalette GetColorPalette( uint nColors )
{
    // Assume monochrome image.
    PixelFormat     bitscolordepth = PixelFormat.Format1bppIndexed;
    ColorPalette    palette;    // The Palette we are stealing
    Bitmap          bitmap;     // The source of the stolen palette

    // Determine number of colors.
    if (nColors > 2)
        bitscolordepth = PixelFormat.Format4bppIndexed;
    if (nColors > 16)
        bitscolordepth = PixelFormat.Format8bppIndexed;

    // Make a new Bitmap object to get its Palette.
    bitmap = new Bitmap( 1, 1, bitscolordepth );

    palette = bitmap.Palette;   // Grab the palette
    
    bitmap.Dispose();           // cleanup the source Bitmap

    return palette;             // Send the palette back
}

				
protected void SaveGIFWithNewColorTable(
    Image       image,
    string      filename,
    uint        nColors,
    bool        fTransparent
    )
{

    // GIF codec supports 256 colors maximum, monochrome minimum.
    if (nColors > 256)
        nColors = 256;
    if (nColors < 2)
        nColors = 2;

    // Make a new 8-BPP indexed bitmap that is the same size as the source image.
    int   Width = image.Width;
    int   Height = image.Height;

    // Always use PixelFormat8bppIndexed because that is the color
    // table-based interface to the GIF codec.
    Bitmap  bitmap = new Bitmap(Width, 
                            Height, 
                            PixelFormat.Format8bppIndexed); 

    // Create a color palette big enough to hold the colors you want.
    ColorPalette pal = GetColorPalette(nColors);

    // Initialize a new color table with entries that are determined
    // by some optimal palette-finding algorithm; for demonstration 
    // purposes, use a grayscale.
    for (uint i = 0; i < nColors; i++)
    {
        uint Alpha = 0xFF;                      // Colors are opaque.
        uint Intensity = i*0xFF/(nColors-1);    // Even distribution. 

        // The GIF encoder makes the first entry in the palette
        // that has a ZERO alpha the transparent color in the GIF.
        // Pick the first one arbitrarily, for demonstration purposes.

        if ( i == 0 && fTransparent) // Make this color index...
            Alpha = 0;          // Transparent
    
        // Create a gray scale for demonstration purposes.
        // Otherwise, use your favorite color reduction algorithm
        // and an optimum palette for that algorithm generated here.
        // For example, a color histogram, or a median cut palette.
        pal.Entries[i] = Color.FromArgb( (int)Alpha, 
                                        (int)Intensity, 
                                        (int)Intensity, 
                                        (int)Intensity );
    }

    // Set the palette into the new Bitmap object.
    bitmap.Palette = pal;


    // Use GetPixel below to pull out the color data of Image.
    // Because GetPixel isn't defined on an Image, make a copy 
    // in a Bitmap instead. Make a new Bitmap that is the same size as the
    // image that you want to export. Or, try to
    // interpret the native pixel format of the image by using a LockBits
    // call. Use PixelFormat32BppARGB so you can wrap a Graphics  
    // around it.
    Bitmap BmpCopy = new Bitmap(Width, 
                            Height, 
                            PixelFormat.Format32bppArgb); 
    {
        Graphics g = Graphics.FromImage(BmpCopy);

        g.PageUnit = GraphicsUnit.Pixel;

        // Transfer the Image to the Bitmap
        g.DrawImage(image, 0, 0, Width, Height);

        // g goes out of scope and is marked for garbage collection.
        // Force it, just to keep things clean.
        g.Dispose();
    }

    // Lock a rectangular portion of the bitmap for writing.
    BitmapData  bitmapData;
    Rectangle   rect = new Rectangle(0, 0, Width, Height);

    bitmapData = bitmap.LockBits(
        rect,
        ImageLockMode.WriteOnly,
        PixelFormat.Format8bppIndexed);

    // Write to the temporary buffer that is provided by LockBits.
    // Copy the pixels from the source image in this loop.
    // Because you want an index, convert RGB to the appropriate
    // palette index here.
    IntPtr pixels = bitmapData.Scan0;

    unsafe 
    { 
        // Get the pointer to the image bits.
        // This is the unsafe operation.
        byte *  pBits;
        if (bitmapData.Stride > 0)
            pBits = (byte *)pixels.ToPointer();
        else
            // If the Stide is negative, Scan0 points to the last 
            // scanline in the buffer. To normalize the loop, obtain
            // a pointer to the front of the buffer that is located 
            // (Height-1) scanlines previous.
            pBits = (byte *)pixels.ToPointer() + bitmapData.Stride*(Height-1);
        uint stride = (uint)Math.Abs(bitmapData.Stride);

        for ( uint row = 0; row < Height; ++row )
        {
            for ( uint col = 0; col < Width; ++col )
            {
                // Map palette indexes for a gray scale.
                // If you use some other technique to color convert,
                // put your favorite color reduction algorithm here.
                Color     pixel;    // The source pixel.

                // The destination pixel.
                // The pointer to the color index byte of the
                // destination; this real pointer causes this
                // code to be considered unsafe.
                byte *    p8bppPixel = pBits + row*stride + col;

                pixel = BmpCopy.GetPixel((int)col, (int)row);

                // Use luminance/chrominance conversion to get grayscale.
                // Basically, turn the image into black and white TV.
                // Do not calculate Cr or Cb because you 
                // discard the color anyway.
                // Y = Red * 0.299 + Green * 0.587 + Blue * 0.114

                // This expression is best as integer math for performance,
                // however, because GetPixel listed earlier is the slowest 
                // part of this loop, the expression is left as 
                // floating point for clarity.

                double luminance = (pixel.R *0.299) +
                    (pixel.G *0.587) +
                    (pixel.B *0.114);

                // Gray scale is an intensity map from black to white.
                // Compute the index to the grayscale entry that
                // approximates the luminance, and then round the index.
                // Also, constrain the index choices by the number of
                // colors to do, and then set that pixel's index to the 
                // byte value.
                *p8bppPixel = (byte)(luminance * (nColors-1)/255 +0.5);

            } /* end loop for col */ 
        } /* end loop for row */ 
    } /* end unsafe */ 

    // To commit the changes, unlock the portion of the bitmap.  
    bitmap.UnlockBits(bitmapData);

    bitmap.Save(filename, ImageFormat.Gif);

    // Bitmap goes out of scope here and is also marked for
    // garbage collection.
    // Pal is referenced by bitmap and goes away.
    // BmpCopy goes out of scope here and is marked for garbage
    // collection. Force it, because it is probably quite large.
    // The same applies to bitmap.
    BmpCopy.Dispose();
    bitmap.Dispose();

}

				

Sobre códigos de exemplo

Microsoft fornece exemplos de programação ilustração só, sem garantia expressa ou implícita, incluindo, sem limitação, garantias implícitas de comercialização e/ou adequação a um fim específico. Este artigo pressupõe que está familiarizado com a linguagem de programação apresentada e as ferramentas utilizadas para criar e depurar procedimentos. Profissionais de suporte da Microsoft podem ajudar a explicar a funcionalidade de um determinado procedimento, mas não modificarão estes exemplos para proporcionarem funcionalidades adicionais nem criarão procedimentos adaptados às necessidades específicas.
Se dispõe de limitada experiência de programação, poderá contactar um Microsoft Certified Partner ou a serviços de aviso. Para obter mais informações, visite estes Web sites da Microsoft:

Microsoft certificado Partner - https://partner.microsoft.com/global/30000104 (https://partner.microsoft.com/global/30000104)

Serviços Microsoft aviso - http://support.microsoft.com/gp/advisoryservice (http://support.microsoft.com/gp/advisoryservice)

Para obter mais informações sobre as opções de suporte estão disponíveis e sobre como contactar a Microsoft, visite o seguinte Web site da Microsoft: http://support.microsoft.com/default.aspx?scid=fh;EN-US;CNTACTMS (http://support.microsoft.com/default.aspx?scid=fh;en-us;cntactms)

Resolução de problemas

Quando utiliza este código para substituir um ficheiro existente, poderá ver o que parece ser um problema com o tamanho do ficheiro resultante. Isto ocorre devido a um erro na versão 1.0 não truncar o ficheiro da GDIPlus. Para obter mais informações sobre tamanhos de ficheiro de imagem, consulte a secção "References".

O código de exemplo também utiliza a palavra-chave não seguros . Isto acontece porque o código que move as definições de pixel da origem de mapa de bits para o mapa de bits de destino utiliza um ponteiro para valores de byte . Ponteiros reais só podem ser utilizados no código que está marcado como não seguro e que é compilado com a opção do compilador / inseguro . Qualquer código escrito desta forma tem impliciations de segurança. Em particular, esse código gerido poderá ter de solicitar permissões e poderá não conseguir funcionar se não for fidedigno.

Referências

Para obter informações adicionais sobre formatos de pixel GIF codec, clique no número de artigo existente abaixo para visualizar o artigo na base de dados de conhecimento da Microsoft:
318343  (http://support.microsoft.com/kb/318343/EN-US/ ) INFO: GDI + os ficheiros GIF são guardadas com o formato de 8-BPP
Para obter informações adicionais sobre tamanhos de ficheiro de imagem, clique no número de artigo existente abaixo para visualizar o artigo na base de dados de conhecimento da Microsoft:
312119  (http://support.microsoft.com/kb/312119/EN-US/ ) PROBLEMA: Guardar o método de classe de mapa de bits não truncar tamanho do ficheiro

Para obter informações adicionais sobre esta técnica utilizando o Microsoft Visual C++, clique no número de artigo existente abaixo para visualizar o artigo na base de dados de conhecimento da Microsoft:
315780  (http://support.microsoft.com/kb/315780/EN-US/ ) COMO: Guardar um ficheiro GIF com uma nova tabela de cores utilizando o GDI +

Glossário

BPP
bits por pixel - o número de bits utilizado para representar o valor de cor de cada pixel numa imagem digitalizada; descreve o esquema físico da definição de cor de cada pixel numa imagem. Formatos de pixel comuns e genericamente referenciadas incluem BPP 32, 24 BPP, 16 BPP, BPP 8, BPP 4, 1 BPP.
BPP 8
O formato de pixels de imagem é expressa em oito bits contidos um byte. O valor de byte é utilizado como um índice numa tabela de cores que contém as definições de cor (RGB) de vermelho-verde-azul reais. Uma vez que o índice é um byte de tamanho, a tabela de cores é limitada a 256 cores.
GIF
Graphics Interchange Format - formato de ficheiro streamable imagem que foi criado por CompuServe.
RGB
Vermelho, verde e azul - cada normalmente expresso como um byte e resulta numa triplo de 3 byte cor.


A informação contida neste artigo aplica-se a:
  • Microsoft .NET Framework Software Development Kit 1.0
  • Microsoft Visual C# .NET 2002 Standard Edition
  • Microsoft Visual C# 2005 Express Edition
  • Microsoft Windows XP Professional Edition
  • the operating system: Microsoft Windows XP 64-Bit Edition
Palavras-chave: 
kbmt kbdswgdi2003swept kbhowtomaster KB319061 KbMtpt
Tradução automáticaTradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine translation ou MT), não tendo sido portanto revisto ou traduzido por humanos. A Microsoft tem artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais. O objectivo é simples: oferecer em Português a totalidade dos artigos existentes na base de dados do suporte. Sabemos no entanto que a tradução automática não é sempre perfeita. Esta pode conter erros de vocabulário, sintaxe ou gramática? erros semelhantes aos que um estrangeiro realiza ao falar em Português. A Microsoft não é responsável por incoerências, erros ou estragos realizados na sequência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza actualizações frequentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 319061  (http://support.microsoft.com/kb/319061/en-us/ )