Melhor abordagem para armazenar pixels de imagem em ordem de baixo para cima em java
-
20-09-2019 - |
Pergunta
Eu tenho uma variedade de bytes representando uma imagem no formato BMP do Windows e gostaria que minha biblioteca a apresentasse ao aplicativo Java como um BufferedImage
, sem copiando os dados do pixel.
O principal problema é que todas as implementações de Raster
Nos pixels da imagem da loja JDK em ordem de cima para baixo, da esquerda para a direita, enquanto os dados do Pixel BMP são armazenados de baixo para cima, da esquerda para a direita. Se isso não for compensado, a imagem resultante será invertida verticalmente.
A "solução" mais óbvia é definir o SampleModel
's scanlineStride
propriedade para um valor negativo e alterar as compensações da banda (ou o DataBuffer
Offset da matriz) para apontar para o pixel superior esquerdo, ou seja, o primeiro pixel da última linha da matriz. Infelizmente isso não funciona porque todo o SampleModel
Os construtores lançam uma exceção se receber um negativo scanlineStride
argumento.
Atualmente estou trabalhando em torno disso, forçando o scanlineStride
Campo para um valor negativo usando reflexão, mas eu gostaria de fazê -lo de maneira mais limpa e portátil, se possível. por exemplo, há outra maneira de enganar o Raster
ou SampleModel
Arranjar os pixels em ordem de baixo para cima, mas sem quebrar o encapsulamento? Ou existe uma biblioteca em algum lugar que envolverá o Raster
e SampleModel
, apresentando as linhas de pixel em ordem inversa?
Eu preferiria evitar as seguintes abordagens:
- Copiando toda a imagem (por razões de desempenho. O código deve processar centenas de imagens grandes (> = 1mpixels) por segundo e, embora toda a imagem deva estar disponível para o aplicativo, ela normalmente acessará apenas um pequeno (mas difícil de predeus ) parte da imagem.)
- Modificando o
DataBuffer
Para realizar a transformação de coordenadas (isso realmente funciona, mas é outra solução "suja", porque o buffer não precisa saber sobre o layout de scanline/pixel.) - Reimplementar o
Raster
e/ouSampleModel
Interfaces do zero (devido à maneira como a verificação de compatibilidade é implementada (pelo menos no Sun JDK), exigindo subclasses específicas deSampleModel
Então, um genéricoBottomUpSampleModel
A classe Wrapper não funcionaria.)
Solução
Eu descobri que posso implementar isso usando apenas uma nova classe, que eu nomeei BottomUpComponentSampleModel
. Ele se estende ComponentSampleModel
e nega o valor do scanlineStride
campo (que, felizmente, é protected
ao invés de private
) depois de chamar o construtor de superclasse. Todos os cálculos de endereço do pixel funcionam bem, embora a validação em Raster.createWritableRaster
Não (isso pode deixar de detectar se você fornece uma matriz muito pequena), mas isso não é um problema sério.
Isso não é necessário com MultiPixelPackedSampleModel
ou SinglePixelPackedSampleModel
, como eles aceitam um negativo scanlineStride
. Eles não têm compensações de banda, mas isso pode ser contornado definindo um compensado no DataBuffer
.
Outras dicas
Que tal ter o aplicativo (ou camada de acesso) a tradução e o fliping funcionam em sua cópia ao acessar a parte minúscula (mas difícil de predito) da imagem?
Melhor ainda, parece que o aplicativo não precisa exibir a imagem? Por que se preocupar em querer virá -lo em primeiro lugar para que pareça correto na tela? Basta escrever a lógica para trabalhar na versão que você tem? Também não há necessidade de ter um bufferImage, trabalhe diretamente na matriz.