Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

Utilizando mecanismos de cache em RMS para imagens

From 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 04:36.
157 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×