Ir para conteúdo
Fórum Script Brasil
  • 0

Modificar Imagem No Imagelist


Thales Pontes Martins

Pergunta

Lá vai eu denovo com os ImageList's da vida.

É o seguinte, eu tenho um ImageList com uma imagem e uma máscara para ela; Agora eu estou precisando de modificar essa imagem dentro do ImageList sem ter que limpar e adicionar outra.

Pois bem, eu lí que na verdade o ImageList armazena todas as imagems um um único Bitmap grandão.

e lí também que o método TImageList.GetImageBitmap retorna o handle desse Bitmap grandão. Então eu estou pegando esse handle e colocando num objeto TBitmap pra ver se eu consigo desenhar alguma coisa lá -> bmp.Handle:=ImageList.GetImageBitmap;. Só que eu não estou conseguindo ler nem escrever nada lá, todas as operações que eu faço depois com esse bitmap resultam em nada. alguém sabe como poderia ser feito isso?

Obrigado.

Link para o comentário
Compartilhar em outros sites

25 respostass a esta questão

Posts Recomendados

  • 0
Então eu estou pegando esse handle e colocando num objeto TBitmap pra ver se eu consigo desenhar alguma coisa lá -> bmp.Handle:=ImageList.GetImageBitmap;. Só que eu não estou conseguindo ler nem escrever nada lá, todas as operações que eu faço depois com esse bitmap resultam em nada. alguém sabe como poderia ser feito isso?
Thales, essa eu não faço idéia mas...
Agora eu estou precisando de modificar essa imagem dentro do ImageList sem ter que limpar e adicionar outra.
Para fazer isso, você não podeira utilizar os métodos GetBitmap e Replace?

var
  bmp :TBitMap;
begin
  bmp := TBitMap.Create;
  try
    ImageList1.GetBitmap(0, bmp);
    bmp.Canvas.TextOut(0, 0, 'Escreve no BMP');
    ImageList1.Replace(0, Bmp, nil);
  finally
    bmp.Free;
  end;
end;

[]s

Link para o comentário
Compartilhar em outros sites

  • 0

É, é, é, é... Se não achar outra alternativa vou ter que fazer assim mesmo, mas você concorda que se eu desenhar diretamente no Bitmap do ImageList o programa ficará mais rápido? E nesse caso estou precisando de uma coisa leve, quanto mais melhor.

O que não aceito é o fato de não conseguir usar o método GetImageBitmap, que deve servir pra alguma coisa, senão não existiria, concorda? E pelo que eu lí na Ajuda do Delphi, esse método serve justamente pra isso que eu quero fazer.

Link para o comentário
Compartilhar em outros sites

  • 0

Opa, descobri que quando eu faço bmp.handle:=ImageList.GetImageBitmap; e depois bmp.savetofile();, ele salva o arquivo com a imagem corretamente, mas se eu tentar desenhar alguma coisa nele ou tentar desenhar ele no form, aí não faz nada.

Link para o comentário
Compartilhar em outros sites

  • 0
Se não achar outra alternativa vou ter que fazer assim mesmo, mas você concorda que se eu desenhar diretamente no Bitmap do ImageList o programa ficará mais rápido?
Acho que será quase imperceptivel.

Utilizar o método proposto, pode ter suas vantagens. você obtém um bitmap único, onde pode usar o canvas livremente sem ter que se preocupar com os off-set dentro do grande bitmap. Li em algum lugar que elas são "agrupadas" em quatro colunas. Fazendo um teste, com quatro imagens adicionadas, observei que realmente o bitmap retornado por GetImageBitmap tem relamente 4x a largura que defini na propriedade Width e 2x a altura. Aparentemente tem área a mais alocada para otimização em novas inserções.

Despois é capaz que o método GetBitmap faça apenas um "CopyRect" do grande bitmap.

Opa, descobri que quando eu faço bmp.handle:=ImageList.GetImageBitmap; e depois bmp.savetofile();, ele salva o arquivo com a imagem corretamente, mas se eu tentar desenhar alguma coisa nele ou tentar desenhar ele no form, aí não faz nada.
É, tinha visto um exemplo deste na net, mas não encontrei nenhum da forma como você queria utilizar.

[]s

Link para o comentário
Compartilhar em outros sites

  • 0
Acho que será quase imperceptivel.

Bem, aí eu não sei, mas eu pretendo desenhar uma imagem nova umas 60 vezes por segundo, e ainda tem que sobrar tempo de processador. Por isso disse que quanto mais leve melhor. Vai ver também eu estou tendo uma noção errada de quanto processador isso vai consumir, vai ver eu uso esse seu método e quando eu for ver o task manager tá 0% de consumo de processador :unsure: .

Vou continuar tentando, se não conseguir vou usar o método proposto por você. Se descobrir qualquer coisa posta aí, por favor.

Link para o comentário
Compartilhar em outros sites

  • 0
eu pretendo desenhar uma imagem nova umas 60 vezes por segundo
É acho que pode ficar mei puxado, mas, vale um teste.
Se descobrir qualquer coisa posta aí, por favor.
estou de olho, quqer novidade posto sim.

Dá para "dar uma palhinha" do que você pretende desenhar nele. Tipo, vai desenhar linhas, outros bitmap's, texto?

[]s

Link para o comentário
Compartilhar em outros sites

  • 0

Ahh, lembrei de mais uma coisa. A imagem tem que ser mudada durante um operação de drag, tipo eu chamo BeginDrag, aí eu chamo dragmove, mudo a imagem, chamo dragmove denovo, mudo a imagem, chamo dragmove denovo................................ Será que com seu método funciona?

Dá para "dar uma palhinha" do que você pretende desenhar nele. Tipo, vai desenhar linhas, outros bitmap's, texto?
Eu estou querendo desenhar uma imagem se mexendo(dessa vez eu quero o blend, por isso usei ImageList, hehe) e enquanto ela se mexe, o angulo dela também muda, então eu tenho que recalcular a posição dos pontos e redesenhar a imagem para o próximo dragmove. Por isso eu queria atualizar ele diretamente na memória onde está alocado, tipo pra ele nem saber que eu a modifiquei. A imagem é formada somente por algums poligonos e linhas(TCanvas.Polygon e TCanvas.LineTo).

Valeu.

Link para o comentário
Compartilhar em outros sites

  • 0
Ahh, lembrei de mais uma coisa. A imagem tem que ser mudada durante um operação de drag, tipo eu chamo BeginDrag, aí eu chamo dragmove, mudo a imagem, chamo dragmove denovo, mudo a imagem, chamo dragmove denovo................................ Será que com seu método funciona?
Thales, não sei não, aquele processo tem uma chamada para DragLock no início da movimentação e DragUnLock no final. Parece sugerir que não dará para mudar a imagem depois que começar a arrastar. Tem que testar, e ser for verdade, acho que você terá que mudar a abordagem para métodos de animação.

e enquanto ela se mexe, o angulo dela também muda, então eu tenho que recalcular a posição dos pontos e redesenhar a imagem para o próximo dragmove. Por isso eu queria atualizar ele diretamente na memória onde está alocado, tipo pra ele nem saber que eu a modifiquei. A imagem é formada somente por algums poligonos e linhas(TCanvas.Polygon e TCanvas.LineTo).
Thales, esse lance envolve rotação, certo. Naquele esquema de desenho das peças através da lista de pontos (polígonos), seria interessante você remapear o desenho delas em relação ao centro, assim você calcula(rotaciona) os pontos a serem desenhados de forma mais fácil e adicionar a um array para utilizar o método Polygon, do canvas, que acredito trabalhará melhor e deixará seu código bastante enchuto. (já utilizei antes, podemos falar mais disto por mail se quizer)

Não mexo muito com desenho de imagens, mas ao que parece o Canvas desse Bitmap fica lockado para leitura e escrita, é como se fosse uma proteção.
s3c, acho que poderia ser isto mesmo porque é um recurso mantido pelo SO. Se olhar o código, o componente TImageList, entre outras facilidades, faz uso das funções da API do Windows. Quando é chamado o método GetImageBitmap, o handle para o bitmap é obtido através da chamada a função da API ImageList_GetImageInfo (link msdn). Entretando, quando é dado um panorama geral sobre o Image List (link msdn), há o seguinte comentário sobre a obtenção de informação da imagem:

_______________________________

Image Information

There are a number of functions that retrieve information from an image list. The ImageList_GetImageInfo function fills an IMAGEINFO structure with information about a single image, including the handles of the image and mask bitmaps, the number of color planes and bits per pixel, and the bounding rectangle of the image within the image bitmap. You can use this information to directly manipulate the bitmaps for the image. The ImageList_GetImageCount function retrieves the number of images in an image list.

_______________________________

A parte em vermelho parece indicar que seria possível mexer no bitmap mantido pelo SO. Acho que entendi direito, não? Neste caso, concordo com o Thales que deverá haver algum meio de fazê-lo.

A título de curiosidade, dando mais umas fuçadas, achei uma função que nem lebrava mais dela, mas que volta e meia vê-se perguntas de como reduzir/apliar uma imagem, e esta é uma das aplicações dela:

CopyImage(

HANDLE hImage, // handle of the image to copy

UINT uType, // type of image to copy

int cxDesired, // desired width of new image

int cyDesired, // desired height of new image

UINT fuFlags // copy flags

);

basta atribuir o resultado ao handle de um TBitmap, como de costume.

Link para o comentário
Compartilhar em outros sites

  • 0
You can use this information to directly manipulate the bitmaps for the image

Eu já vi vários coders por aí na net que deram exemplos sobre esse comando(GetImageBitmap) e todos disseram: "É, tentei várias vezes e não conseguí nem ler nem escrever no bitmap, não consegui transformá-lo em um objeto TBitmap normal que pudesse manipular.".

Então eu acho que agente não está sabendo pegar esse handle e transformá-lo em um obejeto TBitmap normal que se pode manipular. Talvez esteja faltando agente colocar também um handle no Canvas desse Bitmap, ou pegar algum Device Context, se lá.

Thales, esse lance envolve rotação, certo. Naquele esquema de desenho das peças através da lista de pontos (polígonos), seria interessante você remapear o desenho delas em relação ao centro, assim você calcula(rotaciona) os pontos a serem desenhados de forma mais fácil e adicionar a um array para utilizar o método Polygon, do canvas, que acredito trabalhará melhor e deixará seu código bastante enchuto. (já utilizei antes, podemos falar mais disto por mail se quizer)

É mais ou menos isso que estou fazendo, eu tenho um vetor de pontos tridimensionais (X, Y, Z : Extended) que formam os polígonos, aí eu tenho uma função que projeta esses pontos num plano mediante fornecimento de uma camera (H, V : Extended), que na verdade é um angulo de inclinação horizontal, e um vertical. Tá meio errada ainda, tem que dar uma lapidada.

Link para o comentário
Compartilhar em outros sites

  • 0

Pelo que pesquisei, parece que o ImageList mantém o Bitmap num DC próprio e como um Bitmap não pode estar em 2 DCs ao mesmo tempo (essa eu não sabia), você não consegue fazer nada em termos de desenho com o Handle retornado. Uma solução seria criar um novo HBitmap para o seu DC:

  Image1.Picture.Bitmap.Handle := CopyImage(ImageList1.GetImageBitmap,
                                            Image_Bitmap, 0, 0, LR_CopyReturnOrg);

Link para o comentário
Compartilhar em outros sites

  • 0

Opa, s3c, desse jeito eu conseguí ler e escrever no Bitmap, só que quando eu desenhava nele, não era atualizado no Bitmap do ImageList, somente no meu, o que nos leva a crer que nesse caso é feita uma cópia :( .

Link para o comentário
Compartilhar em outros sites

  • 0

Bom, já que se acabaram as idéias, eu vou dizer uma e vocês dizem se funciona: Dei uma olhada no código fonte do TImageList <- TDragImageList <- TCustomImageList. Essa é a hierarquia. E no TCustomImageList tem um campo private FBitmap, que armazena o ponteiro para o próprio objeto Bitmap. O que que vocês acham de eu mudar o código: pegar esse campo e declarar na interface protected, e depois eu ir no TDragImageList e mudar o método create dela: Acrescentar um parametro que vai ser a variável que vai receber esse valor do FBitmap? Assim quando eu criar o objeto eu posso guardar a referencia pra esse bitmap pra ter acesso a ele. Não sei nem se vai funcionar, porque certa vez precisei de mudar o código fonte dessas units do Delphi e não aconteceu nada, foi como se eu não tivesse mudado nada.

Link para o comentário
Compartilhar em outros sites

  • 0

Acho que não vai resolver. Se você observar o código, não é feito grande coisa com este bitmap.

Na inicialização (InitBitmap) ele é criado, "em branco", com o tamanho definido por Width e Height do ImageList. E depois é retornado o seu handle caso Image em GetImageHandle(Image, ImageDDB: TBitmap) seja passado com nil.

Link para o comentário
Compartilhar em outros sites

  • 0

É, não tem jeito, já apaguei .dcu, já apaguei .pas, já botei .pas em todos os lugares e não mudou nada, fica como se eu não tivesse mexido no código.

Desisto.

Obrigado Micheus e s3c pela consideração.

Link para o comentário
Compartilhar em outros sites

  • 0

Opa, sempre existe uma solução, dei uma modificada no meu velho TDragOperation e consegui modificar a imagem durante a operação DragDrop. Mais agora tá faltando eu saber desenhar a imagem SEMI-TRANSPARENTE!!!. alguém aí sabe como fazer, se tem algum método no ImageList que faz isso, pra ficar que nem o ImageList.ShowDragImage;? Ou se não tiver no ImageList, se tem algum outro componente que faça isso??????? Qualquer sugestão é bem vinda. :wacko:

Link para o comentário
Compartilhar em outros sites

  • 0

Opa, eu descobrí que ao desenhar uma imagem, se você apenas substituir um pixel do fundo pelo pixel da imagem que você quer desenhar, ele fica normal, mas se ao invés disso você subtrair do pixel do fundo o inverso do pixel da imagem, ela fica SEMI-TRANSPARENTE!!! :) E não precisa nem ter máscara porque nesse caso a cor branca não influencia. E se fizer um AND lógico também funciona. :) Então se Pegarmos os pixels de um bitmap e fizermos essa operação bit a bit neles, uma imagem vai ser desenhada SEMI-TRANSPARENTE na outra!! :) . Só que eu não sei como fazer isso, teremos que achar o endereço de memória onde estão esses pixels. Me ajudem aí por favor!!!!

Valeu!!!

Link para o comentário
Compartilhar em outros sites

  • 0

Opa descobrí:

BitBlt(
  Dest.Canvas.Handle, // handle to destination DC
  0,  // x-coord of destination upper-left corner
  0,  // y-coord of destination upper-left corner
  80,  // width of destination rectangle
  80, // height of destination rectangle
  Source.Canvas.Handle,  // handle to source DC
  0,   // x-coordinate of source upper-left corner
  0,   // y-coordinate of source upper-left corner
  SRCAND  // raster operation code
);

Voces não me disseram para provar que eu era capaz de descobrir sozinho, né?

Link para o comentário
Compartilhar em outros sites

  • 0

p*********, c**********, só agora que eu fui descobrir que tem a função AlphaBlend da gdi do windows que faz isso, f************, c************, p************** será que ninguém sabia disso não, p*********************.

Link para o comentário
Compartilhar em outros sites

  • 0

p*********, c**********, só agora que eu fui descobrir que tem a função AlphaBlend da gdi do windows que faz isso, f************, c************, p************** será que ninguém sabia disso não, p*********************.

Thales, parece que você não leu um post do dia seguinte (08/Set/2006). Não retornei a questão porque parecia resolvida e porque você sempre dá uma lida nos posts sobre o assunto. Bastava segir o link mensionado neste post.

[]s

Link para o comentário
Compartilhar em outros sites

  • 0
Thales, parece que você não leu um post do dia seguinte (08/Set/2006). Não retornei a questão porque parecia resolvida e porque você sempre dá uma lida nos posts sobre o assunto. Bastava segir o link mensionado neste post.
Nesse post falava-se da propriedade AlphaBlend do Form, e não da função AlphaBlend da GDI.

Tá bom, lá tem um link para uma página da microsoft onde se menciona essa função, mas aí já é querer demais. Era só falar "Thales, dê uma olhada na função AlphaBlend".

E o pior é que para conseguir o efeito que eu queria eu tive que usar form branco. Eu queria que ficasse igual papel celofane, e para isso é preciso subtrair do pixel de destino o inverso do pixel da fonte. Se existisse isso na GDI(não sei se existe) ficaria perfeito. Fazendo um AND lógico o efeito é o mesmo desde que o form seja branco, se for cinza alguns bits do destino estarão desligados o que fará com que os mesmo bits da fonte também fiquem, e isso resulta em perda de tonalidade, ou seja, um grupo de cores com mesma matiz mas com tonalidades próximas mas não iguais se tornam a mesma cor.

Link para o comentário
Compartilhar em outros sites

  • 0
Thales, parece que você não leu um post do dia seguinte (08/Set/2006). Não retornei a questão porque parecia resolvida e porque você sempre dá uma lida nos posts sobre o assunto. Bastava segir o link mensionado neste post.
Nesse post falava-se da propriedade AlphaBlend do Form, e não da função AlphaBlend da GDI.

Tá bom, lá tem um link para uma página da microsoft onde se menciona essa função, mas aí já é querer demais. Era só falar "Thales, dê uma olhada na função AlphaBlend".

Tem que olhar com mais carinho as referências postadas. :D

E o pior é que para conseguir o efeito que eu queria eu tive que usar form branco. Eu queria que ficasse igual papel celofane, e para isso é preciso subtrair do pixel de destino o inverso do pixel da fonte. Se existisse isso na GDI(não sei se existe) ficaria perfeito.
Essa parte do papel celofane eu não captei direito. Dá pra desenhar? :rolleyes:

A parte da inversão do fonte você consegue com o BitBlt (com NOTSRCCOPY), mas a subtração acho qeu não tem como - só na mão. Mas, isso não pode resultar em cores "estranhas" ao invés de transparência?

Link para o comentário
Compartilhar em outros sites

Participe da discussão

Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.

Visitante
Responder esta pergunta...

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.



  • Estatísticas dos Fóruns

    • Tópicos
      152,3k
    • Posts
      652,3k
×
×
  • Criar Novo...