×
Namespaces

Variants
Actions

Utilizando mecanismos de cache em RMS para imagens

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

Artigo
Tradução:
Por thiagobrunoms
Última alteração feita por hamishwillee em 30 Jul 2013

Quando você tem imagens grandes e complexas, que são desenhadas em tempo de execução no seu aplicativo usando a API de baixo nível (por exemplo, montanhas fractal como imagem de fundo ou o sol multicolorido com brilhos e manchas fuzzy), por vezes, leva muito tempo para redesenhar eles (principalmente nos primeiros dispositivos com java embarcado).

Claro, você pode preparar uma imagem nos formatos PNG ou JPG de antemão e utilizá-lo em vez de usar métodos de baixo nível. Mas se a sua aplicação deve funcionar em diferentes dispositivos móveis com diferentes resoluções de tela, então você é obrigado a criar um grande número de tais imagens em diferentes resoluções e, quando o algoritmo é alterado, você precisa voltar e convertê-los todos.


O caminho alternativo é utilizar mecanismos de cache quando as imagens são desenhadas em tempo de execução no dispositivo e depois utilizar a imagem armazenada no cache para redesenhar. Para isso, você deve usar os seguintes métodos:

  • Image.createImage(width, height)
  • image.getGraphics().

Depois de ter um objeto do tipo Image que contém uma imagem complexa, você pode guardá-lo na RMS para não necessitar desenhar novamente depois de executar seu aplicativo novamente.


Atenção:' você deve calcular quais opções serão mais rápidas: lendo do cache RMS de imagens ou executando os algoritmos complexos para desenahr a imagem


Neste artigo, vou apresentar-lhe um padrão para armazenamento de objetos de imagens em cache utilizando Record Management System (RMS) e, em seguida, restaurá-los após a execução da aplicação.

Abaixo segue o código-fonte da classe que irá salvar as imagens em Record Management System (RMS).

public class ImageStorage {
public static final int ID_MOUNTAIN = 0;//índices para as imagens que serão armazenadas em cache
public static final int ID_SUN = 1;
public static final int NUMBER_OF_IMAGES = ID_SUN + 1;
 
private static final Image[] CASHED_IMAGES = new Image[NUMBER_OF_IMAGES];//array de imagens criado
private static final int MAX_AREA_OF_IMAGE = 176 * 220;
 
// Se precisamos de mais, ela vai crescer em run-time
private static final String RMS_IMAGES = "images";
 
 
//nome de armazenamento em RMS
 
/**
* Esta cor será usada para indicar a cor transparente,
* Você pode alterá-la, mas tenha certeza de que
* Sua cor será processada corretamente pelo aplicativo.
* Ela é modificada apenas uma vez (você pode fazer isso final)
*/

protected static int COLOR_TO_BE_TRANSPARENT = 0xFFFFFF;
 
public static boolean isLoaded = false; //sinalizador indica que as imagens foram carregadas em RMS
 
/**
* Classe DrawerImageToBuffer para simplificar o cache de imagens em gráficos de buffer(o padrão é o "método modelo" GOF)
*/

public static abstract class DrawerImageToBuffer {
protected int width;
protected int height;
private Image imgBuffer = null;
 
private DrawerImageToBuffer() {
}
 
/**
* Salva imagem, que é produzida pelo método drawImage,
* no array CASHED_IMAGES
*
* @param w - captura a largura d aimagem
* @param h - captura a altura da imagem
* @param imageIndex - captura o índice da imagem
*/

 
protected void process(int w, int h, int imageIndex) {
width = w;
height = h;
imgBuffer = Image.createImage(width, height);
Graphics g = imgBuffer.getGraphics();
g.setColor(COLOR_TO_BE_TRANSPARENT);
g.fillRect(0, 0, imgBuffer.getWidth(), imgBuffer.getHeight());
drawImage(g);
saveImageToArray(imageIndex);
}
 
abstract protected void drawImage(Graphics g);//Método modelo
 
/**
* @param imageIndex - captura o índice da imagem
*/

private void saveImageToArray(int imageIndex) {
CASHED_IMAGES[imageIndex] = imgBuffer;
}
}
//------------------------------------------------
/**
* O método PaintToBufferAndStoreImages() passa por todas as imagens que devem ser armazenados em cache,
* Invocando seus algoritmos complicados de pintura, armazenando resultados da pintura em ImageStorage.CASHED_IMAGES,
* E, em seguida, salva as imagens em RMS
*/

protected void paintToBufferAndStoreImages() {
DrawerImageToBuffer TM = null;
int size = Font.getDefaultFont().getHeight();
 
TM = new MountainDrawingToCache();
TM.process(size, size, ID_MOUNTAIN);
 
TM = new SunDrawingToCache();
TM.process(4, Font.getDefaultFont().getHeight() * 8, ID_SUN);
 
storeImagesInRMS(CASHED_IMAGES);//salvar imagens em RMS
}
 
/**
* Obtém tabela de cores de curImage imagem em rgbInts array de inteiros
*
* @param rgbInts - matriz resultado com a tabela de cores da imagem
* @param curImage - objeto de imagem a partir do qual temos a tabela de cores
* @param w - largura da imagem obtida (que pode levar toda a região não a imagem)
* @param h - altura da imagem obtida (que pode levar toda a região não a imagem)
* @param s - área da imagem (deve ser w * h)
*/

protected static void getRGB(int[] rgbInts, Image curImage, int w, int h, int s) {
curImage.getRGB(rgbInts, 0, w, 0, 0, w, h);
for (int i = 0; i < s; i++)
if ((rgbInts[i] & 0x00FFFFFF) == COLOR_TO_BE_TRANSPARENT)
rgbInts[i] = (rgbInts[i] & 0x00FFFFFF);
}
 
/**
* Verifica se é preciso atualizar o cache
* Você pode usar dados que são armazenados em RMS se achar que são necessários para atualização
*
* @param recordStore - RMS com dados adicionais
* @return false se dados em RMS é up-to-date
* Caso contrário retorna true
* @throws RecordStoreException
* @throws IOException
*/

protected boolean additioanlCheckingOfNeedingReCashing(RecordStore recordStore) throws RecordStoreException, IOException {
/* verificação adicional por exemplo, dados em RMS estão fora de moda por causa da fonte alterada ou resolução */
return false;
}
 
/**
* Restaura uma série de imagens de RMS para array de imagens creditadas
*
* @param arImages - conjunto de imagens a serem restauradas
*/

protected void restoreImagesFromRMS(Image[] arImages) {
int[] intArrayOfRGBforImage = null;
int w = 0;//largura da imagem
int h = 0;//altura da imagem
int l = 0;//área da imagem
int curPointerToImage = 0;
 
try {
RecordStore recordStore = RecordStore.openRecordStore(RMS_IMAGES, true);
RecordEnumeration re = recordStore.enumerateRecords(null, null, true);
 
 
/* Aqui você pode colocar o código para a tomada de informações adicionais para o re-cashing em RMS (você deve simplesmente ignorá-lo)
* Porque ele já é processado) */

/*...*/
 
try {
while (re.hasNextElement()) {
int id = re.nextRecordId();
ByteArrayInputStream bais = new ByteArrayInputStream(recordStore.getRecord(id));
DataInputStream inputStream = new DataInputStream(bais);
 
try {
l = inputStream.readInt();
w = inputStream.readInt();
h = inputStream.readInt();
intArrayOfRGBforImage = new int[l];
for (int j = 0; j < l; j++)
intArrayOfRGBforImage[j] = inputStream.readInt();
} catch (EOFException ioe) {
ioe.printStackTrace();
}
 
arImages[curPointerToImage++] = Image.createRGBImage(intArrayOfRGBforImage, w, h, true);
System.gc();
}
}
catch (IOException ioe) {
ioe.printStackTrace();
}
recordStore.closeRecordStore();
} catch (Exception rse) {
rse.printStackTrace();
}
}
 
/**
* Arrays de imagens em RMS do conjunto de imagens em chache
*
* @param images - conjunto de imagens a serem armazenadas
*/

public void storeImagesInRMS(Image[] images) {
int w, h, l;
int[] rgbImage = new int[MAX_AREA_OF_IMAGE];
try {
try {// apaga os registros armazenados
RecordStore.deleteRecordStore(RMS_IMAGES);
} catch (RecordStoreException e) {
e.printStackTrace();
}
RecordStore recordStore = RecordStore.openRecordStore(RMS_IMAGES, true);
 
/*Salvar informações adicionais para verificação a necessidade de re-cashing em RMS */
/*...*/
 
for (int i2 = 0; (i2 < images.length) && (images[i2] != null); i2++) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream outputStream = new DataOutputStream(baos);
Image curImage = images[i2];
 
w = curImage.getWidth();
h = curImage.getHeight();
l = w * h;
if (l > MAX_AREA_OF_IMAGE)
rgbImage = new int[l];
 
getRGB(rgbImage, curImage, w, h, l);
try {
outputStream.writeInt(l);
outputStream.writeInt(w);
outputStream.writeInt(h);
for (int j = 0; j < l; j++)
outputStream.writeInt(rgbImage[j]);
System.gc();
} catch (IOException ioe) {
ioe.printStackTrace();
}
 
byte[] b = baos.toByteArray();
int id = recordStore.addRecord(b, 0, b.length);
}
recordStore.closeRecordStore();
} catch (Exception rse) {
rse.printStackTrace();
}
}
 
/**
* Verifica se os dados em RMS (que contém imagens em cache) é up-to-date e se for em seguida
* Carrega do cache as imagens em RMS. Se não for, então a aplicação do cache das imagens usando
* o método DrawImage adequado, guarda em RMS, e em seguida, carrega o cache das imagens em RMS.
*
* @throws Exception
*/

public void loadImages() throws Exception {
RecordStore recordStore = RecordStore.openRecordStore(RMS_IMAGES, true);
if (recordStore.getNumRecords() == 0)
paintToBufferAndStoreImages();
else {
boolean isNeedReCash = additioanlCheckingOfNeedingReCashing(recordStore);
if (isNeedReCash)
paintToBufferAndStoreImages();
}
restoreImagesFromRMS(CASHED_IMAGES);
isLoaded = true;
}
 
/**
* Use este método em vez de Graphics.DrawImage para desenhar imagens complicadas no cache
*
* @param g - Objeto da Classe {@link javax.microedition.lcdui.Graphics}
* @param index - índice de imagem armazenadas em um array de imagens cache
* @param x - x coordenada para desenho x
* @param y - y coordenada para desenho y
* @param anchor - âncora da imagem pintada
*/

public static void drawImage(Graphics g, int index, int x, int y, int anchor) {
if (ImageStorage.isLoaded)
try {
g.drawImage(CASHED_IMAGES[index], x, y, anchor);
} catch (Exception e) {
isLoaded = false;
e.printStackTrace();
}
}
}

Nesta classe Mountain você deve definir os métodos drawSingleMountain que irá conter todo código de pintura da montanha em objetos Graphics. Também deverás fazer na classe Sun no método drawSingleSun.

// Os métodos sobrescritos (você pode colocar esta aula em uma classe adequada (Mountain e Sun))
public static class MountainDrawingToCache extends DrawerImageToBuffer {
public void drawImage(Graphics g) {
Mountain.drawSingleMountain(g/*plus other parametres if needed*/);
}
}
 
public static class SunDrawingToCache extends DrawerImageToBuffer {
public void drawImage(Graphics g) {
Sun.drawSingleSun(g/*plus other parametres if needed*/);
}
}

No método startApp da sua MIDlet, você pode definir o seguinte trecho de código:

protected void startApp() throws MIDletStateChangeException {
ImageStorage ids = new ImageStorage();
try {
ids.loadImages();
} catch (Exception e) {
ids.isLoaded = false;
ids.paintToBufferAndStoreImages();
}
 
/* outro código... */
}

Agora, a fim de desenhar as imagens armazenadas, você deve utilizar o método drawImage(Graphics g, int index, int x, int y, int anchor) da classe ImageStorage.

This page was last modified on 30 July 2013, at 07:36.
111 page views in the last 30 days.