JavascriptProva

Visualizzazione post con etichetta immagini. Mostra tutti i post
Visualizzazione post con etichetta immagini. Mostra tutti i post

giovedì 2 giugno 2016

Studio per modifica immagini nell'App.

Bene.
Ora devo mettere l'immagine regolabile e scalabile anche alle funzioni che permettono di modificare l'immagine.
Vediamo un po' come fare...

Innanzitutto, da dove parte il codice?
Eccolo:
//LISTENER PER IL BOTTONE IMGBUTTON CHE MODIFICA LE IMMAGINI:
  imgButton.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    Intent intent=new Intent();
    intent.setAction(Intent.ACTION_PICK);
    intent.setData(Uri.parse("content://media/external/images/media"));
    startActivityForResult(intent, 0);
   }
  });
Ecco, questo permette di andare direttamente alla memoria a prendere un'immagine per sostituirla a quella che c'era precedentemente.
Questo non va bene.
Dovrei riaprire invece il form ImagePick.
Vediamo il codice che lo apre...

  //LISTENER PER CREARE UNA NUOVA IMMAGINE
 
  
  mainLayout.setOnLongClickListener(new View.OnLongClickListener() {
   
   @Override
   public boolean onLongClick(View v) {
    if(settingMode){
     Intent intent=new Intent(MainActivity.this,ImagePick.class);
     intent.putExtra("Categoria", currentCat);
     intent.putExtra("CoordX", mlX);
     intent.putExtra("CoordY", mlY);
     startActivity(intent);
    }
    return true;
   }
  });
Ecco: è un Intent esplicito che semplicemente apre ImagePick
E vi immette la categoria corrente, la coordinata X e la coordinata Y di dove è stato esercitato il tocco.
Ma dove prende le variabili mlX e mlY?
Da qui:
  mainLayout.setOnTouchListener(new View.OnTouchListener() {
   
   @Override
   public boolean onTouch(View v, MotionEvent event) {
    mlX=(int)event.getX();
    mlY=(int)event.getY();
    scrollView.requestDisallowInterceptTouchEvent(false);
    ActiveOne=null;
    for(int i=0;i<mainLayout.getChildCount();i++){
     ((ViewGroup)mainLayout.getChildAt(i)).getChildAt(numEtichetta).setBackgroundColor(Color.WHITE);
    }
    button.setVisibility(View.INVISIBLE);
    imgButton.setVisibility(View.INVISIBLE);
    return false;
   }
  });
che è il listener del tocco di mainLayout.

Ristudiamoci il codice:
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  Bundle extras=getIntent().getExtras();
  categoria =extras.getString("Categoria");
  coordX=extras.getInt("CoordX");
  coordY=extras.getInt("CoordY");
  setContentView(R.layout.activity_image_pick);
  mainLayout=(RelativeLayout)findViewById(R.id.mainLayout);
  
  //inizializzazione della jImage
  jImage=new JImage();
  
  //creo una nuova istanza di Immagine, chiamata img.
  img=new Immagine(this);
  mainLayout.addView(img);
  img.getLayoutParams().width=300;
  img.getLayoutParams().height=300;
  img.setX(50);
  img.setY(70);
  
  //inizializzazioni delle variabili oggetto dei controlli presenti nell'activity
  
  editText=(EditText)findViewById(R.id.editText1);
  editText.setVisibility(View.INVISIBLE);
  radioGroup=(RadioGroup)findViewById(R.id.radioGroup1);
  radioGroup.setVisibility(View.INVISIBLE);
  bttInvia=(Button)findViewById(R.id.button1);
  bttInvia.setVisibility(View.INVISIBLE);
  bttAnnulla=(Button)findViewById(R.id.button2);
  bttPick=(Button)findViewById(R.id.bttPick);
  
  
  
  
//AL TOCCO DEL PULSANTE, PER CARICARE LE IMMAGINI DALLO STORAGE
  bttPick.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    Intent intent=new Intent();
    intent.setAction(Intent.ACTION_PICK);
    intent.setData(Uri.parse("content://media/external/images/media"));
    startActivityForResult(intent,0);
    
   }
  });
Ecco: dovendo caricare ImagePick per scegliere un'immagine ex novo, abbiamo questa inizializzazione dei vari controlli:
  //inizializzazioni delle variabili oggetto dei controlli presenti nell'activity
  
  editText=(EditText)findViewById(R.id.editText1);
  editText.setVisibility(View.INVISIBLE);
  radioGroup=(RadioGroup)findViewById(R.id.radioGroup1);
  radioGroup.setVisibility(View.INVISIBLE);
  bttInvia=(Button)findViewById(R.id.button1);
  bttInvia.setVisibility(View.INVISIBLE);
  bttAnnulla=(Button)findViewById(R.id.button2);
  bttPick=(Button)findViewById(R.id.bttPick);
La casella di testo dove digitare il nome dell'immagine è invisibile;
i radiobuttons per selezionare se si tratti di un'immagine normale o di una categoria sono invisibili;
Il pulsante Invia è invisibile.
Solo il pulsante Annulla è visibile, come lo è quello che ho aggiunto per andare ad aprire la memoria in modo da selezionare l'immagine.

Qui, invece, devo fare in modo che il nome e il tipo siano già determinate. Dunque su editText deve già figurare il nome dell'immagine e su RadioButtons deve già figurare il tipo. E quindi questi controlli devono essere già visibili.
Forse conviene aprire un altro form per evitare confusioni terribili?

Forse è meglio, sì. Semmai una volta entrato nel meccanismo potrò utilizzare lo stesso form con maggior possibilità di non commettere errori.
Correggo solo l'allineamento del button che carica l'immagine e del controllo Immagine, e ne rendo uguali le ampiezze, giusto per un fatto estetico.
  editText=(EditText)findViewById(R.id.editText1);
  editText.setVisibility(View.INVISIBLE);
  radioGroup=(RadioGroup)findViewById(R.id.radioGroup1);
  radioGroup.setVisibility(View.INVISIBLE);
  bttInvia=(Button)findViewById(R.id.button1);
  bttInvia.setVisibility(View.INVISIBLE);
  bttAnnulla=(Button)findViewById(R.id.button2);
  bttPick=(Button)findViewById(R.id.bttPick);
  bttPick.setX(img.getX());
  bttPick.getLayoutParams().width=img.getLayoutParams().width;
  
E vediamo se funziona...

Okay, funziona!
Passiamo a realizzare l'activity per il cambio di immagine.

lunedì 2 maggio 2016

Codice per scrolling e zoom di un'immagine.

Ecco il codice che realizza un'immagine scrollabile e zoomabile:
public class MainActivity extends Activity {
 float scale=1f;
 ScaleGestureDetector SGD;
 
 RelativeLayout mainLayout;
 ImageView imageView;
 
 Bitmap bitmap;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  SGD = new ScaleGestureDetector(this, new ScaleListener());
  mainLayout=(RelativeLayout)findViewById(R.id.mainLayout);
  
  bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.angurie2);
  final int larghezza=300;
  final int altezza=300;
  ImageView i=newImage(mainLayout,larghezza, altezza, 10, 10, bitmap, Color.BLACK, ScaleType.MATRIX);
    
  View.OnTouchListener onTouchListener=new View.OnTouchListener() {
   Matrix matrix=new Matrix();
   Matrix inversa=new Matrix();
   float X,Y,currentX, currentY;
   float deltaX, deltaY;
   @Override
   public boolean onTouch(View v, MotionEvent event) {
    switch(event.getAction()){
    case MotionEvent.ACTION_DOWN:
     X=event.getX();
     Y=event.getY();
     
     break;
    case MotionEvent.ACTION_MOVE:
     
     currentX=event.getX();
     currentY=event.getY();
     float[] pts={0,0};
     ((ImageView)v).getImageMatrix().invert(inversa);
     inversa.mapPoints(pts);
     
     
     if(currentX<X){
      if((pts[0]-currentX+X)<(bitmap.getWidth()-larghezza/scale)){
       deltaX=-pts[0]+currentX-X;
      }
      else{
       if((pts[0]-currentX+X)>(bitmap.getWidth()-larghezza/scale))
       deltaX=-(bitmap.getWidth()-larghezza/scale);
       
      }
     }
     if(currentX>X){
      if((pts[0]-currentX+X)>0){
       deltaX=-pts[0]+currentX-X;
      }
      else{
       if((pts[0]-currentX+X)<0) deltaX=0;
      }
     }
     
     if(currentY<Y){
      if((pts[1]-currentY+Y)<(bitmap.getHeight()-altezza/scale)){
       deltaY=-pts[1]+currentY-Y;
      }
      else{
       if((pts[1]-currentY+Y)>(bitmap.getHeight()-altezza/scale))
        deltaY=-(bitmap.getHeight()-altezza/scale);
       
      }
     }
     if(currentY>Y){
      if((pts[1]-currentY+Y)>0){
       deltaY=-pts[1]+currentY-Y;
      }
      else{
       if((pts[1]-currentY+Y)<0) deltaY=0;
      }
     }
     
     
     matrix.setTranslate(deltaX,deltaY);
     matrix.postScale(scale, scale);
     ((ImageView)v).setImageMatrix(matrix);
     X=currentX;
     Y=currentY;
     SGD.onTouchEvent(event);
     break;
    }
    return true;
   }
  };
  i.setOnTouchListener(onTouchListener);
 
  
  
  
 }

 class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener{
  @Override
  public boolean onScale(ScaleGestureDetector SGD){
   scale *= SGD.getScaleFactor();
   return true;
  }
 }
 public ImageView newImage(ViewGroup layout, int larghezza, int altezza, 
   float X, float Y, Bitmap bitmap, int colore, 
   ScaleType scaletype){
  ImageView imageView=new ImageView(this);
  layout.addView(imageView);
  imageView.getLayoutParams().width=larghezza;
  imageView.getLayoutParams().height=altezza;
  imageView.setX(X);
  imageView.setY(Y);

  imageView.setImageBitmap(bitmap);
  imageView.setBackgroundColor(colore);
  imageView.setScaleType(scaletype);
  return imageView;
 }

} 
Ora devo provvedere a metterlo nell'applicazione...
Dopo averla opportunamente SALVATA!!!

Il codice per prendere l'immagine devo andare a ripescarmelo...

Eccolo:
  button.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    
    imageView.destroyDrawingCache();
    imageView.buildDrawingCache();
    Bitmap bmp=imageView.getDrawingCache();
    imgControllo.setImageBitmap(bmp);
    
   }
  });

sabato 23 aprile 2016

Codice che replica in tempo reale su una imageView il contenuto di un'altra ImageView compreso lo sfondo

Codice che crea su una ImageView imgControllo una bitmap presa dal contenuto di una ImageView imageView spostabile, in tempo reale con gli spostamenti:
  OnTouchListener onTouchListener=new View.OnTouchListener() {
   Matrix matrice=new Matrix();
   Matrix inversa=new Matrix();
   
   @Override
   public boolean onTouch(View v, MotionEvent event) {
    
    switch (event.getAction()){
    case MotionEvent.ACTION_DOWN:
     X=event.getX();
     Y=event.getY();
     break;
    case MotionEvent.ACTION_MOVE:
     currentX=event.getX();
     currentY=event.getY();
     pts=new float[]{0,0};
     imageView.getImageMatrix().invert(inversa);
     inversa.mapPoints(pts);
     matrice.setTranslate(-pts[0]+currentX-X, -pts[1]+currentY-Y);
     imageView.setImageMatrix(matrice);
     X=currentX;
     Y=currentY;
     imageView.destroyDrawingCache();
     imageView.buildDrawingCache();
     Bitmap bmp=imageView.getDrawingCache();
     imgControllo.setImageBitmap(bmp);
     
     break;
    }
    return true;
   }
   
  };
  imageView.setOnTouchListener(onTouchListener);

mercoledì 20 aprile 2016

Studio per ritagliare immagini (codice grezzo)

Ho realizzato in questo modo una "finestra" sulla bitmap, ossia una ImageView che si "affaccia" su una Bitmap più grande di essa e tramite la quale si può "uncinare" la bitmap spostandola a piacimento.
  imageView =new ImageView(this);
  bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.facciadaculo);
  int larghezza=bitmap.getWidth();
  int altezza=bitmap.getHeight();  

  
  LayoutParams params=new LayoutParams(200,100);
  imageView.setLayoutParams(params);
  imageView.setScaleType(ScaleType.CENTER);
  imageView.setImageBitmap(bitmap);
  imageView.setBackgroundColor(Color.BLACK);
  
  mainLayout.addView(imageView);
  
  OnTouchListener onTouchListener=new View.OnTouchListener() {
   
   @Override
   public boolean onTouch(View v, MotionEvent event) {
    
    switch(event.getAction()){
     case MotionEvent.ACTION_DOWN:
      X=event.getX();
      Y=event.getY();
      break;
     case MotionEvent.ACTION_MOVE:
      currentX=event.getX();
      currentY=event.getY();
      
      int scrollByX=(int)(X-currentX);
      int scrollByY=(int)(Y-currentY);
      v.scrollBy(scrollByX, scrollByY);
      X=currentX;
      Y=currentY;
      break;
    }
    return true;
   }
  };
  imageView.setOnTouchListener(onTouchListener);
 }
Bene.
Annotata questa, procedo a sperimentare un po' oltre...

Provo a usare il metodo scrollTo(int,int).
  OnTouchListener onTouchListener=new View.OnTouchListener() {
   
   @Override
   public boolean onTouch(View v, MotionEvent event) {
    
    switch(event.getAction()){
     case MotionEvent.ACTION_DOWN:
      imageView.scrollTo(0, 0);
      break;
     
      
    }
    return true;
   }
  };
  imageView.setOnTouchListener(onTouchListener);
Giocando con ScaleType e con ScrollTo posso modificare sia la posizione iniziale della bitmap nei confronti della ImageView sia l'entità dello scorrimento della bitmap.
Adesso quello che mi interessa è prendere le coordinate della bitmap.
Se uso ScaleType.MATRIX, ottengo il posizionamento iniziale nell'angolo superiore sinistro della Bitmap, quindi zero.
Ora sposto di 50 e 50:
    switch(event.getAction()){
     case MotionEvent.ACTION_DOWN:
      imageView.scrollTo(50,50);
      break;
     
      
    }


Sposto mediante il Touch di 50,50:



E adesso quindi so di avere una finestra che esplora la bitmap secondo queste coordinate:
Angolo superiore sinistro: 50,50;
Angolo inferiore destro: 150,150 (dato che le dimensioni della finestra sono rispettivamente 100 e 100).

Provo quindi a ritagliare un'immagine di queste coordinate e dimensioni.
Per vederla, però, devo creare una nuova ImageView.

Ecco il codice:
  imageView =new ImageView(this);
  bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.facciadaculo);
  int larghezza=bitmap.getWidth();
  int altezza=bitmap.getHeight();
  
  
  LayoutParams params=new LayoutParams(100,100);
  imageView.setLayoutParams(params);
  imageView.setScaleType(ScaleType.MATRIX);
  imageView.setImageBitmap(bitmap);
  imageView.setBackgroundColor(Color.BLACK);
  
  mainLayout.addView(imageView);
  
  imgControllo=new ImageView(this);
  LayoutParams p=new LayoutParams(100,100);
  p.leftMargin=10;
  p.topMargin=200;
  imgControllo.setLayoutParams(p);
  mainLayout.addView(imgControllo);
  
  OnTouchListener onTouchListener=new View.OnTouchListener() {
   
   @Override
   public boolean onTouch(View v, MotionEvent event) {
    
    switch(event.getAction()){
     case MotionEvent.ACTION_DOWN:
      imageView.scrollTo(50,50);
      Bitmap newBmp=Bitmap.createBitmap(bitmap,50,50,100,100);
      imgControllo.setImageBitmap(newBmp);
      break;
     
      
    }
    return true;
   }
  };
  imageView.setOnTouchListener(onTouchListener);
Questo codice prende la bitmap e, dopo lo spostamento calcolato a partire dall'angolo superiore sinistro della bitmap, calcola il ritaglio da praticare nella bitmap in relazione allo spostamento, ne crea una nuova bitmap e la pone nell'ImageView di controllo.
Ecco: prima dello spostamento:



E dopo lo spostamento con ritaglio e copia nella seconda ImageView.



Bene.


Ecco, ho creato un codice che permette di individuare le coordinate della bitmap sottostante.
Me lo copio qui, grezzo grezzo e con residui di un codice precedente che resta inutilizzato, in modo da poter attingere ad esso in caso di eventuali vuoti di memoria nella riscrittura di un codice fatto meglio
public class MainActivity extends Activity {
 float X;
 float Y;
 float currentX, currentY;

 ImageView imageView;
 ImageView imageView2;
 RelativeLayout mainLayout;
 RelativeLayout layout;
 Bitmap bitmap;
 Matrix matrix;
 ImageView imgControllo;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  
  
  mainLayout=(RelativeLayout)findViewById(R.id.mainLayout);
  
  int LayLeft, LayTop, LayWidth, LayHeight;
  int ImgLeft, ImgTop, ImgWidth, ImgHeight;
  LayLeft=0;
  LayTop=0;
  LayWidth=100;
  LayHeight=100;
  
  ImgLeft=0;
  ImgTop=0;
  

  
  //CREAZIONE DEL LAYOUT
  layout=new RelativeLayout(this);
  BitmapDrawable sfondo=(BitmapDrawable)this.getResources().getDrawable(R.drawable.cartellanuova);
  layout.setBackground(sfondo);
  
  //settaggio dei parametri
  LayoutParams lParams=new LayoutParams(LayWidth,LayHeight);
  lParams.leftMargin=LayLeft;
  lParams.topMargin=LayTop;
  layout.setLayoutParams(lParams);
  
  
  //CREAZIONE DELL'IMMAGINE
  imageView =new ImageView(this);
  bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.facciadaculo);
  int larghezza=bitmap.getWidth();
  int altezza=bitmap.getHeight();
  
 
  
  
  
  LayoutParams params=new LayoutParams(100,100);
  imageView.setLayoutParams(params);
  imageView.setScaleType(ScaleType.CENTER);
  
  
  
  bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), 
    bitmap.getHeight(),matrix, false);
  imageView.setImageBitmap(bitmap);
  
  imageView.setBackgroundColor(Color.BLACK);
  
  mainLayout.addView(imageView);
  
  imgControllo=new ImageView(this);
  LayoutParams p=new LayoutParams(100,100);
  p.leftMargin=10;
  p.topMargin=200;
  imgControllo.setLayoutParams(p);
  imgControllo.setBackgroundColor(Color.BLACK);
  mainLayout.addView(imgControllo);
  
  OnTouchListener onTouchListener=new View.OnTouchListener() {
   Matrix matrix=imageView.getImageMatrix();
   @Override
   public boolean onTouch(View v, MotionEvent event) {
    ((ImageView)v).getImageMatrix().invert(matrix);
    switch(event.getAction()){
     case MotionEvent.ACTION_DOWN:
      X=event.getX();
      Y=event.getY();
      float[] pts={0f,0f};
        
      
      matrix.mapPoints(pts);
      Log.v(""+pts[0],""+pts[1]);
      break;
    }
      
     
    
    return true;
   }
  };
  imageView.setOnTouchListener(onTouchListener);
  
 }
 

 
 @Override
 public void onWindowFocusChanged(boolean hasFocus){
  super.onWindowFocusChanged(hasFocus);
  Log.v("LARGHEZZA DI IMAGEVIEW",""+imageView.getWidth());
  Log.v("ALTEZZA DI IMAGEVIEW",""+imageView.getHeight());
 }
 
}

lunedì 18 aprile 2016

Studi di ridimensionamento di immagini con Matrix

Adesso ridimensiono la bitmap e poi vedo se la ImageView che la contiene si riduce di conseguenza.

  imageView =new ImageView(this);

  Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.anguria);
  bitmap=Bitmap.createScaledBitmap(bitmap, 100, 100, false);
  Log.v("LARGHEZZA DELLA BITMAP",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP",""+bitmap.getHeight());
  
  imageView.setImageBitmap(bitmap);
  mainLayout.addView(imageView);
 }
 
 @Override
 public void onWindowFocusChanged(boolean hasFocus){
  super.onWindowFocusChanged(hasFocus);
  Log.v("LARGHEZZA DI IMAGEVIEW",""+imageView.getWidth());
  Log.v("ALTEZZA DI IMAGEVIEW",""+imageView.getHeight());
 }
04-18 15:59:10.215: V/LARGHEZZA DELLA BITMAP(6108): 100
04-18 15:59:10.216: V/ALTEZZA DELLA BITMAP(6108): 100

.....

04-18 15:59:10.434: V/LARGHEZZA DI IMAGEVIEW(6108): 100
04-18 15:59:10.434: V/ALTEZZA DI IMAGEVIEW(6108): 100

Ho ridotto l'immagine senza rispetto per le proporzioni.
Ma ricordo adesso che si può usare Matrix per scalare le immagini.
Ciò può essere molto utile, anziché calcolare il rapporto larghezza/altezza e agire di conseguenza...

Vediamo...

  imageView =new ImageView(this);

  Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.anguria);
  Log.v("LARGHEZZA DELLA BITMAP",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP",""+bitmap.getHeight());
  Matrix matrix=new Matrix();
  matrix.postScale(.5f,.5f);
  bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
  Log.v("LARGHEZZA DELLA BITMAP DOPO MATRIX",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP DOPO MATRIX",""+bitmap.getHeight());
  
  imageView.setImageBitmap(bitmap);
  mainLayout.addView(imageView);
 }
 
 @Override
 public void onWindowFocusChanged(boolean hasFocus){
  super.onWindowFocusChanged(hasFocus);
  Log.v("LARGHEZZA DI IMAGEVIEW",""+imageView.getWidth());
  Log.v("ALTEZZA DI IMAGEVIEW",""+imageView.getHeight());
 }
04-18 19:01:38.411: V/LARGHEZZA DELLA BITMAP(6466): 408
04-18 19:01:38.411: V/ALTEZZA DELLA BITMAP(6466): 313
04-18 19:01:38.412: V/ALTEZZA DELLA BITMAP DOPO MATRIX(6466): 157

.....

04-18 19:01:39.289: V/LARGHEZZA DI IMAGEVIEW(6466): 204
04-18 19:01:39.290: V/ALTEZZA DI IMAGEVIEW(6466): 157

Perfetto! La bitmap si è ridimensionata e la ImageView con lei.


Ora voglio portare la bitmap a una larghezza di 100.
Calcolo il rapporto fra 100 e la larghezza della bitmap...


  imageView =new ImageView(this);

  Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.anguria);
  Log.v("LARGHEZZA DELLA BITMAP",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP",""+bitmap.getHeight());
  float Ratio=100f/(float)bitmap.getWidth();
  
  Matrix matrix=new Matrix();
  matrix.postScale(Ratio,Ratio);
  bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
  Log.v("LARGHEZZA DELLA BITMAP DOPO MATRIX",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP DOPO MATRIX",""+bitmap.getHeight());
  
  imageView.setImageBitmap(bitmap);
  mainLayout.addView(imageView);
 }
 
 @Override
 public void onWindowFocusChanged(boolean hasFocus){
  super.onWindowFocusChanged(hasFocus);
  Log.v("LARGHEZZA DI IMAGEVIEW",""+imageView.getWidth());
  Log.v("ALTEZZA DI IMAGEVIEW",""+imageView.getHeight());
 }
E vediamo le misure:
04-18 19:08:39.152: V/LARGHEZZA DELLA BITMAP(6512): 408
04-18 19:08:39.152: V/ALTEZZA DELLA BITMAP(6512): 313
04-18 19:08:39.153: V/LARGHEZZA DELLA BITMAP DOPO MATRIX(6512): 100
04-18 19:08:39.153: V/ALTEZZA DELLA BITMAP DOPO MATRIX(6512): 77

.....

04-18 19:08:39.562: V/LARGHEZZA DI IMAGEVIEW(6512): 100
04-18 19:08:39.562: V/ALTEZZA DI IMAGEVIEW(6512): 77

Perfetto! La larghezza è stata portata a 100!

Ora voglio che l'altezza sia pari a 100:
  imageView =new ImageView(this);

  Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.anguria);
  Log.v("LARGHEZZA DELLA BITMAP",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP",""+bitmap.getHeight());
  float Ratio=100f/(float)bitmap.getHeight();
  
  Matrix matrix=new Matrix();
  matrix.postScale(Ratio,Ratio);
  bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
  Log.v("LARGHEZZA DELLA BITMAP DOPO MATRIX",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP DOPO MATRIX",""+bitmap.getHeight());
  
  imageView.setImageBitmap(bitmap);
  mainLayout.addView(imageView);
 }
 
 @Override
 public void onWindowFocusChanged(boolean hasFocus){
  super.onWindowFocusChanged(hasFocus);
  Log.v("LARGHEZZA DI IMAGEVIEW",""+imageView.getWidth());
  Log.v("ALTEZZA DI IMAGEVIEW",""+imageView.getHeight());
 }
04-18 19:10:26.931: V/LARGHEZZA DELLA BITMAP(6601): 408
04-18 19:10:26.931: V/ALTEZZA DELLA BITMAP(6601): 313
04-18 19:10:26.937: V/LARGHEZZA DELLA BITMAP DOPO MATRIX(6601): 130
04-18 19:10:26.938: V/ALTEZZA DELLA BITMAP DOPO MATRIX(6601): 100

.....

04-18 19:10:27.114: V/LARGHEZZA DI IMAGEVIEW(6601): 130
04-18 19:10:27.114: V/ALTEZZA DI IMAGEVIEW(6601): 100

Perfetto!
Dunque, se un'immagine è orizzontale, la misura da riportare a 100 sarà la larghezza, mentre se è verticale la misura sarà l'altezza.
Potremo così costringere un'immagine a stare nei limiti che vogliamo.
Ma se ho un'immagine orizzontale, che riduco a 100 di larghezza ma voglio che non occupi più di una certa dimensione in altezza, ossia ho due limiti, come mi metto?
Se porto direttamente l'altezza a valori inferiori al limite verticale, potrei avere ancora una larghezza superiore a 100.
Se porto la larghezza a valori inferiori a 100 potrei avere ancora un'altezza superiore al secondo limite.
Così, per le immagini orizzontali bisogna prima rapportarle a 100 e poi al secondo limite.


Iniziamo a ridimensionare le immagini secondo la larghezza o l'altezza a seconda che siano rispettivamente orizzontali o verticali.
Facciamo conto che il limite orizzontale sia 100 e quello verticale di 50.
Innanzitutto distinguiamo se l'immagine è orizzontale o verticale. Se è perfettamente quadrata può rientrare nel campo di quelle verticali.

  imageView =new ImageView(this);

  Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.anguria);
  Log.v("LARGHEZZA DELLA BITMAP",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP",""+bitmap.getHeight());
  
  int larghezza=bitmap.getWidth();
  int altezza=bitmap.getHeight();
  
  
  float Ratio;
  if(altezza>=larghezza) Ratio=50f/(float)bitmap.getHeight();
  else Ratio=100f/(float)bitmap.getWidth();
 
  
  Matrix matrix=new Matrix();
  matrix.postScale(Ratio,Ratio);
  bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
  Log.v("LARGHEZZA DELLA BITMAP DOPO MATRIX",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP DOPO MATRIX",""+bitmap.getHeight());
  
  imageView.setImageBitmap(bitmap);
  mainLayout.addView(imageView);
 }
 
 @Override
 public void onWindowFocusChanged(boolean hasFocus){
  super.onWindowFocusChanged(hasFocus);
  Log.v("LARGHEZZA DI IMAGEVIEW",""+imageView.getWidth());
  Log.v("ALTEZZA DI IMAGEVIEW",""+imageView.getHeight());
 }
Ecco: questo codice stabilisce un limite di larghezza 100 per le immagini orizzontali, mentre stabilisce un limite di altezza 50 per le immagini verticali e quadrate.
Lo provo dapprima con l'immagine orizzontale "anguria", quindi con l'immagine verticale "torre": Con "anguria", immagine orizzontale:
04-18 19:26:51.062: V/LARGHEZZA DELLA BITMAP(6785): 408
04-18 19:26:51.062: V/ALTEZZA DELLA BITMAP(6785): 313

04-18 19:26:51.062: V/LARGHEZZA DELLA BITMAP DOPO MATRIX(6785): 100
04-18 19:26:51.062: V/ALTEZZA DELLA BITMAP DOPO MATRIX(6785): 77

04-18 19:26:51.255: V/LARGHEZZA DI IMAGEVIEW(6785): 100
04-18 19:26:51.255: V/ALTEZZA DI IMAGEVIEW(6785): 77
Mi ha ridotto l'immagine orizzontale a una larghezza di 100 (con un'altezza di 77).

Con "torre", immagine verticale:
04-18 19:29:13.569: V/LARGHEZZA DELLA BITMAP(6832): 591
04-18 19:29:13.570: V/ALTEZZA DELLA BITMAP(6832): 888

04-18 19:29:13.570: V/LARGHEZZA DELLA BITMAP DOPO MATRIX(6832): 33
04-18 19:29:13.570: V/ALTEZZA DELLA BITMAP DOPO MATRIX(6832): 50

04-18 19:29:13.769: V/LARGHEZZA DI IMAGEVIEW(6832): 33
04-18 19:29:13.770: V/ALTEZZA DI IMAGEVIEW(6832): 50
Mi ha ridotto l'immagine verticale a un'altezza di 50 (con larghezza pari a 33).
Ora, però, io voglio che per l'immagine orizzontale anche l'altezza abbia dei limiti, ossia che sia al massimo di 50.
Come fare?
Proviamo...
  layout=new RelativeLayout(this);
  BitmapDrawable sfondo=(BitmapDrawable)this.getResources().getDrawable(R.drawable.cartellanuova);
  layout.setBackground(sfondo);
  
  //settaggio dei parametri
  LayoutParams lParams=new LayoutParams(LayWidth,LayHeight);
  lParams.leftMargin=LayLeft;
  lParams.topMargin=LayTop;
  layout.setLayoutParams(lParams);
  
  
  //CREAZIONE DELL'IMMAGINE
  imageView =new ImageView(this);

  Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.anguria);
  Log.v("LARGHEZZA DELLA BITMAP",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP",""+bitmap.getHeight());
  
  int larghezza=bitmap.getWidth();
  int altezza=bitmap.getHeight();
  
  
  float Ratio;
  if(altezza>=larghezza) Ratio=50f/(float)bitmap.getHeight();
  else Ratio=100f/(float)bitmap.getWidth();
 
  
  Matrix matrix=new Matrix();
  matrix.postScale(Ratio,Ratio);
  bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
  Log.v("LARGHEZZA DELLA BITMAP DOPO MATRIX",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP DOPO MATRIX",""+bitmap.getHeight());
  
  if(bitmap.getHeight()>50){
   Ratio=50f/(float)bitmap.getHeight();
   Log.v("RATIO",""+Ratio);
   matrix=new Matrix();
   matrix.postScale(Ratio, Ratio);
   bitmap=Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(), bitmap.getHeight(),matrix,false);
   Log.v("LARGHEZZA DELLA BITMAP DOPO SECONDA MATRIX",""+bitmap.getWidth());
   Log.v("ALTEZZA DELLA BITMAP DOPO SECONDA MATRIX",""+bitmap.getHeight());
  }
  imageView.setImageBitmap(bitmap);
  mainLayout.addView(imageView);
 }
 
 @Override
 public void onWindowFocusChanged(boolean hasFocus){
  super.onWindowFocusChanged(hasFocus);
  Log.v("LARGHEZZA DI IMAGEVIEW",""+imageView.getWidth());
  Log.v("ALTEZZA DI IMAGEVIEW",""+imageView.getHeight());
 }
Ecco.
La provo con l'immagine anguria che è orizzontale con poca differenza fra altezza e larghezza:
04-18 20:05:06.598: V/LARGHEZZA DELLA BITMAP(7254): 408
04-18 20:05:06.598: V/ALTEZZA DELLA BITMAP(7254): 313

04-18 20:05:06.598: V/LARGHEZZA DELLA BITMAP DOPO MATRIX(7254): 100
04-18 20:05:06.598: V/ALTEZZA DELLA BITMAP DOPO MATRIX(7254): 77

04-18 20:05:06.600: V/RATIO(7254): 0.64935064

04-18 20:05:06.603: V/LARGHEZZA DELLA BITMAP DOPO SECONDA MATRIX(7254): 65
04-18 20:05:06.604: V/ALTEZZA DELLA BITMAP DOPO SECONDA MATRIX(7254): 50
Dopo aver ridotto l'immagine orizzontale a 100, questa ha un'altezza di 77, che è eccessiva rispetto al limite verticale di 50. Calcola nuovamente il rapporto e la riduce ulteriormente fino a un'altezza di 50.

La provo adesso con l'immagine torre che è verticale:
04-18 20:07:41.595: V/LARGHEZZA DELLA BITMAP(7302): 591
04-18 20:07:41.595: V/ALTEZZA DELLA BITMAP(7302): 888

04-18 20:07:41.596: V/LARGHEZZA DELLA BITMAP DOPO MATRIX(7302): 33
04-18 20:07:41.596: V/ALTEZZA DELLA BITMAP DOPO MATRIX(7302): 50

04-18 20:07:41.726: V/LARGHEZZA DI IMAGEVIEW(7302): 33
04-18 20:07:41.726: V/ALTEZZA DI IMAGEVIEW(7302): 50
Non va oltre la prima riduzione all'altezza di 50.

La provo adesso con l'immagine chiave che è orizzontale più stretta della precedente orizzontale:
04-18 20:09:23.188: V/LARGHEZZA DELLA BITMAP(7348): 406
04-18 20:09:23.188: V/ALTEZZA DELLA BITMAP(7348): 175

04-18 20:09:23.188: V/LARGHEZZA DELLA BITMAP DOPO MATRIX(7348): 100
04-18 20:09:23.193: V/ALTEZZA DELLA BITMAP DOPO MATRIX(7348): 43

04-18 20:09:23.401: V/LARGHEZZA DI IMAGEVIEW(7348): 100
04-18 20:09:23.402: V/ALTEZZA DI IMAGEVIEW(7348): 43
In questo caso, con la riduzione a 100 l'altezza è già sotto il limite verticale di 50 e quindi l'immagine non necessita di ulteriori riduzioni.
Tutto ciò è quanto era nelle mie intenzioni!

Adesso bisogna studiare il posizionamento delle immagini in una View, in relazione al rapporto con una TextView.

Dimensioni di una bitmap e della ImageView che la contiene

Prendo l'immagine e ne rilevo le dimensioni:
  Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.anguria);
  Log.v(""+bitmap.getWidth(),""+bitmap.getHeight());
Ottengo
04-18 14:40:04.976: V/408(4740): 313
408 e 313.

Metto la bitmap in una ImageView.
  ImageView imageView =new ImageView(this);

  Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.anguria);
  Log.v(""+bitmap.getWidth(),""+bitmap.getHeight());
  
  imageView.setImageBitmap(bitmap);
  mainLayout.addView(imageView);
La ImageView mi viene abbastanza grande:



Siamo sicuri che ImageView abbia le stesse dimensioni della Bitmap?
Vediamole...
  ImageView imageView =new ImageView(this);

  Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.anguria);
  Log.v(""+bitmap.getWidth(),""+bitmap.getHeight());
  
  imageView.setImageBitmap(bitmap);
  Log.v(""+imageView.getWidth(),""+imageView.getHeight());
  mainLayout.addView(imageView);
04-18 15:47:26.523: V/408(5881): 313
04-18 15:47:26.524: V/0(5881): 0

Così facendo, ottengo come risultato 0 e 0.
Il motivo è che fino a onResume non è stata ancora dispiegata "materialmente" la ImageView, e quindi bisogna overridare l'evento onWindowFocusChanged, a quanto leggo...

Proviamo:
  Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.anguria);
  Log.v(""+bitmap.getWidth(),""+bitmap.getHeight());
  
  imageView.setImageBitmap(bitmap);
  mainLayout.addView(imageView);
 }
 
 @Override
 public void onWindowFocusChanged(boolean hasFocus){
  super.onWindowFocusChanged(hasFocus);
  Log.v(""+imageView.getWidth(),""+imageView.getHeight());
 }
04-18 15:50:18.327: V/408(5974): 313

.....

04-18 15:50:18.537: V/408(5974): 313

Per avere la prova, faccio di meglio:
  imageView =new ImageView(this);

  Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.anguria);
  Log.v("LARGHEZZA DELLA BITMAP",""+bitmap.getWidth());
  Log.v("ALTEZZA DELLA BITMAP",""+bitmap.getHeight());
  
  imageView.setImageBitmap(bitmap);
  mainLayout.addView(imageView);
 }
 
 @Override
 public void onWindowFocusChanged(boolean hasFocus){
  super.onWindowFocusChanged(hasFocus);
  Log.v("LARGHEZZA DI IMAGEVIEW",""+imageView.getWidth());
  Log.v("ALTEZZA DI IMAGEVIEW",""+imageView.getHeight());
 }
04-18 15:55:33.902: V/LARGHEZZA DELLA BITMAP(6021): 408
04-18 15:55:33.910: V/ALTEZZA DELLA BITMAP(6021): 313

.....

04-18 15:55:34.016: V/LARGHEZZA DI IMAGEVIEW(6021): 408
04-18 15:55:34.016: V/ALTEZZA DI IMAGEVIEW(6021): 313

Ed è così confermato che le dimensioni della ImageView sono le stesse della bitmap in essa contenuta.

Studio per l'adattamento e la centratura delle immagini in un contenitore.

Se un'immagine è contenuta in un contenitore, ne assume la larghezza.
Provo:
  //CREAZIONE DEL LAYOUT
  layout=new RelativeLayout(this);
  BitmapDrawable sfondo=(BitmapDrawable)this.getResources().getDrawable(R.drawable.cartella);
  layout.setBackground(sfondo);
  
  //settaggio dei parametri
  LayoutParams lParams=new LayoutParams(LayWidth,LayHeight);
  lParams.leftMargin=LayLeft;
  lParams.topMargin=LayTop;
  layout.setLayoutParams(lParams);
  
  
  //CREAZIONE DELL'IMMAGINE
  ImageView imageView =new ImageView(this);
  BitmapDrawable immagine=(BitmapDrawable)this.getResources().getDrawable(R.drawable.chiave);
  imageView.setImageDrawable(immagine);
  
  //definizione delle dimensioni
  ImgWidth=immagine.getBitmap().getWidth();
  ImgHeight=immagine.getBitmap().getHeight();
  
  //scaletype
  imageView.setScaleType(ImageView.ScaleType.FIT_START);
  Log.v(""+ImgWidth,""+ImgHeight);
  
  //settaggio dei parametri
  LayoutParams imgParams=new LayoutParams(ImgWidth,ImgHeight);
  imgParams.leftMargin=ImgLeft;
  imgParams.topMargin=ImgTop;
  imageView.setLayoutParams(imgParams);
Ecco: qui ottengo questi valori di larghezza e altezza dell'immagine:
04-17 21:52:23.285: V/406(2224): 175

ossia 406 e 175.

Ma le dimensioni del Layout contenitore sono 100 e 100:
  int LayLeft, LayTop, LayWidth, LayHeight;
  int ImgLeft, ImgTop, ImgWidth, ImgHeight;
  LayLeft=0;
  LayTop=0;
  LayWidth=100;
  LayHeight=100;
  
  ImgLeft=0;
  ImgTop=0;
Bisogna rapportare quindi le dimensioni dell'immagine a quelle del contenitore.



Ecco infine la funzione che ho creato, in cui bisogna fornire una scalatura, una ImageView, la bitmap e le dimensioni del contenitore:
 public void centerImage(float Scalatura, ImageView imgView, 
   BitmapDrawable bitmapDrawable,int ContWidth, int ContHeight){
  int ImgWidth=bitmapDrawable.getBitmap().getWidth();
  int ImgHeight=bitmapDrawable.getBitmap().getHeight();
  float Scala=Scalatura;
  if(ImgWidth>ImgHeight) {
   float Ratio=(float)ImgHeight/(float)ImgWidth;
   ImgWidth=(int) (ContWidth*Scala);
   ImgHeight=(int)(ImgWidth*Ratio);
  }else{
   float Ratio=(float)ImgWidth/(float)ImgHeight;
   ImgHeight=(int)(ContHeight*Scala);
   ImgWidth=(int)(ImgHeight*Ratio);
  }
  
  int ImgTop=ContHeight/2-ImgHeight/2;
  int ImgLeft=ContWidth/2-ImgWidth/2;
  
  imgView.setScaleType(ImageView.ScaleType.FIT_START);
  LayoutParams imgParams=new LayoutParams(ImgWidth,ImgHeight);
  imgParams.leftMargin=ImgLeft;
  imgParams.topMargin=ImgTop;
  imgView.setLayoutParams(imgParams);
 }


sabato 20 febbraio 2016

Alcuni errori e perplessità

Mettiamo a confronto.

Viene presa l'immagine, e sottoposta a questa procedura:
//DA RISORSE A BITMAP
 public static Bitmap ResourcesToBitmap(Context context,int id, int dimensioni){
   BitmapFactory.Options opzioni=new BitmapFactory.Options();
   opzioni.inJustDecodeBounds=true;
   BitmapFactory.decodeResource(context.getResources(),id,opzioni);
   int fattore=1;
   while(opzioni.outWidth/fattore>dimensioni && opzioni.outHeight/fattore>dimensioni){
    fattore*=2;
   }
   opzioni.inSampleSize=fattore;
   opzioni.inJustDecodeBounds=false;
   Bitmap bmp=BitmapFactory.decodeResource(context.getResources(),id,opzioni);
   return bmp;
 }
Da file, invece:
//DA PATH A BITMAP
 public static Bitmap PathToBitmap(String path, int dimensioni){
  BitmapFactory.Options opzioni=new BitmapFactory.Options();
  opzioni.inJustDecodeBounds=true;
  BitmapFactory.decodeFile(path,opzioni);
  int fattore=1;
  while(opzioni.outWidth/fattore>dimensioni && opzioni.outHeight/dimensioni>dimensioni){
   fattore*=2;
  }
  opzioni.inSampleSize=fattore;
  opzioni.inJustDecodeBounds=false;
  Bitmap bmp=BitmapFactory.decodeFile(path, opzioni);
  return bmp;
 }
Ho trovato il banale ma tremendo errore!


Ora le immagini caricate da path risultano appena più grandi di quelle caricate da risorse.
Perché?

Vediamo con quali parametri vengono chiamate le funzioni di cui sopra.
Il salvataggio di immagini da risorse avviene tramite la seguente funzione:
 private void salvaInDatabase(String etichetta, String categoria, int idImmagine, String tipo, int coordX, int coordY){
  JImage jImage=new JImage();
  jImage.etichetta=etichetta;
  jImage.categoria=categoria;
  jImage.immagine=Funzioni.ResourcesToByteArray(this, idImmagine, 100, 80);
  jImage.tipo=tipo;
  jImage.coordX=coordX;
  jImage.coordY=coordY;
  helper.save(jImage);
 }
La funzione che fa uso della funzione ResourcesToBitmap(Context context,int id, int dimensioni) viene chiamata dalla funzione ResourcesToByteArray(Context context, int id, int dimensioni,int quality)
 public static byte[] ResourcesToByteArray(Context context, int id, int dimensioni,int quality){
  return BitmapToByteArray(ResourcesToBitmap(context,id,dimensioni), quality);
 }
La funzione ResourcesToBitmap(Context context,int id, int dimensioni)viene chiamata con i parametri Context context, int id, int dimensioni che sono this,idImmagine,100, mentre la funzione BitmapToByteArray(Bitmap bmp,int quality) ha il parametro Int quality che è 80.

Invece la funzione PathToBitmap(String path, int dimensioni) viene chiamata con i parametri path e dimensioni, che viene usato allo stesso modo che nella funzione ResourcesToBitap.
, e prima di salvarla in un database viene trasformata in byte[] mediante la stessa funzione BitmapToByteArray(Bitmap bmp,int quality), sempre con un parametro quality di 80.

Mah... Le immagini vengono trattate allo stesso modo, e non riesco a spiegarmi perché vengano di dimensione diversa.
Fa nulla, la differenza è di poco...

mercoledì 27 gennaio 2016

Creazione di un form per il caricamento di immagini in database e creazione di un bordo in un LinearLayout programmaticamente.

Prendere un'immagine dalla memoria e metterla in un database, insieme a etichetta e categoria.
Mi predispongo una tabella di database in cui vi siano i tre campi.
 class Helper extends SQLiteOpenHelper{

  public Helper(Context context) {
   super(context, "database", null, 1);
  }

  @Override
  public void onCreate(SQLiteDatabase db) {
   db.execSQL("CREATE TABLE TABELLA(_ID INTEGER PRIMARY KEY,ETICHETTA TEXT,CATEGORIA TEXT,IMMAGINE BLOB)");
   
   
  }
  
  

  @Override
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
   // TODO Auto-generated method stub
   
  }
  
 }
Ora creo il metodo save e il metodo query.
Ma prima forse mi conviene definire una classe che abbia tutte le proprietà
E qui la cosa si fa interessante per la gestione dell'immagine.
Credo che mi convenga memorizzare un array di bytes.

 class JImage{
  public String Etichetta;
  public String Categoria;
  public byte[] ImageByteArray;
 }
Questo presuppone che nell'immissione di dati venga creata prima la ByteArrayOutputStream e quindi dalla bitmap venga fatta la compressione con successiva conversione della ByteArrayOutputStream in byte di array.

Adesso provo a creare il metodo save().
  public void save(JImage jImage){
   SQLiteDatabase db=this.getWritableDatabase();
   ContentValues values=new ContentValues();
   values.put("ETICHETTA", jImage.Etichetta);
   values.put("CATEGORIA", jImage.Categoria);
   values.put("IMMAGINE", jImage.ImageByteArray);
   db.insert("TABELLA", null, values);
  }
Ecco.

Adesso devo costruire il meccanismo per l'immissione dell'immagine e delle sue caratteristiche.

Fatto.
Il codice che ho inserito è questo (completo):
public class Scelta extends Activity {

 //DICHIARAZIONI
 Bitmap bmp;
 JImage jImage;
 Helper helper;
 Button button;
 Adapter adapter;

 ImageView imageView;
 EditText editText;
 AutoCompleteTextView autoComplete;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_scelta);
  
  //DEFINIZIONI
  helper=new Helper(this);
  imageView=(ImageView) findViewById(R.id.imageView1);
  editText=(EditText) findViewById(R.id.editText1);
  autoComplete=(AutoCompleteTextView) findViewById(R.id.autoCompleteTextView1);
  button=(Button) findViewById(R.id.button1);
  button.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    Intent intent=new Intent();
    intent.setData(Uri.parse("content://media/external/images/media"));
    intent.setAction(Intent.ACTION_PICK);
    startActivityForResult(intent,0);
    
   }
  });
  
  adapter=new Adapter(this,helper.catQuery(" "));
  autoComplete.setAdapter(adapter);
  autoComplete.setOnEditorActionListener(new TextView.OnEditorActionListener() {
   
   @Override
   public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    ByteArrayOutputStream stream=new ByteArrayOutputStream();
    bmp.compress(CompressFormat.JPEG, 50, stream);
    byte[] blob=stream.toByteArray();
    jImage=new JImage();
    jImage.Etichetta=editText.getText().toString();
    jImage.Categoria=autoComplete.getText().toString();
    jImage.ImageByteArray=blob;
    helper.save(jImage);
    jImage=null;
    bmp=null;
    return false;
   }
  });
  

  
 }
 public void onActivityResult(int requestCode, int resultCode, Intent data){
  if(resultCode==RESULT_OK){
   BitmapFactory.Options opzioni=new BitmapFactory.Options();
   opzioni.inJustDecodeBounds=true;
   BitmapFactory.decodeFile(getPathFromUri(data.getData()),opzioni);
   int fattore=1;
   while(opzioni.outWidth/fattore>200 && opzioni.outHeight/fattore>200){
    fattore*=2;
   }
   opzioni.inSampleSize=fattore;
   opzioni.inJustDecodeBounds=false;
   bmp=BitmapFactory.decodeFile(getPathFromUri(data.getData()),opzioni);
   imageView.setImageBitmap(bmp);
   
   
   
   
  }
 }
 
 private String getPathFromUri(Uri uri){
  Cursor crs=getContentResolver().query(uri, null, null, null, null);
  crs.moveToFirst();
  int index=crs.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
  String s=crs.getString(index);
  return s;
 }
 class Helper extends SQLiteOpenHelper{

  public Helper(Context context) {
   super(context, "database", null, 1);
  }

  @Override
  public void onCreate(SQLiteDatabase db) {
   db.execSQL("CREATE TABLE TABELLA(_id INTEGER PRIMARY KEY,ETICHETTA TEXT,CATEGORIA TEXT,IMMAGINE BLOB)");
   db.execSQL("CREATE TABLE TBLCATEGORIE(_id INTEGER PRIMARY KEY,CATEGORIA TEXT)");
  }
  
  public void save(JImage jImage){
   SQLiteDatabase db=this.getWritableDatabase();
   ContentValues values=new ContentValues();
   values.put("ETICHETTA", jImage.Etichetta);
   values.put("CATEGORIA", jImage.Categoria);
   values.put("IMMAGINE", jImage.ImageByteArray);
   db.insert("TABELLA", null, values);
   values.clear();
   values.put("CATEGORIA", jImage.Categoria);
   db.insert("TBLCATEGORIE", null, values);
   imageView.setImageBitmap(null);
   editText.setText(null);
   autoComplete.setText(null);
  }
  
  public Cursor query(){
   SQLiteDatabase db=this.getWritableDatabase();
   Cursor c = db.rawQuery("SELECT * FROM TABELLA", null);
   c.moveToFirst();
   return c;
  }
  
  public Cursor catQuery(String str){
   SQLiteDatabase db=this.getWritableDatabase();
   Cursor c=db.rawQuery("SELECT * FROM TBLCATEGORIE WHERE CATEGORIA LIKE '"+str+"%'", null);
   c.moveToFirst();
   return c;
  }
  

  @Override
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
   
   
  }
  
 }
 
 class JImage{
  public String Etichetta;
  public String Categoria;
  public byte[] ImageByteArray;
 }
 
 class Adapter extends CursorAdapter{

  public Adapter(Context context, Cursor c) {
   super(context, c);
   
  }

  @Override
  public View newView(Context context, Cursor cursor, ViewGroup parent) {
   LayoutInflater inflater=(LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
   TextView v=(TextView) inflater.inflate(android.R.layout.simple_dropdown_item_1line, null);
   return v;
  }

  @Override
  public void bindView(View view, Context context, Cursor cursor) {
   ((TextView)view).setText(cursor.getString(1));
   
  }
  
  @Override
  public Cursor runQueryOnBackgroundThread(CharSequence constraint){
   if(constraint!=null) return helper.catQuery(constraint+"");
   return null;
  }
  
  @Override
  public String convertToString(Cursor cursor){
   return cursor.getString(1);
   
  }
  
 }
Questo codice è stato trasferito su un'altra activity, chiamata "Scelta".
Ora vorrei visualizzare le immagini su dei LinearLayout.
Per prima cosa, trasferisco il codice su un'altra activity.

E l'ho fatto, ripassando l'Intent esplicito (per passare da un'activity all'altra.
  button=(Button) findViewById(R.id.button1);
  button.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    
    Intent intent=new Intent(MainActivity.this,Scelta.class);
    startActivity(intent);
    
   }
  });
Bene.
Ora, all'avvio di questa Activity, voglio che le immagini salvate nel database vengano riportate su dei LinearLayout.
Devo ripassare le procedure per creare programmaticamente un linearlayout.
LinearLayout ll = new LinearLayout(this);
E poi?
Ecco il codice per aggiungere un Layout all'Activity:
  LinearLayout ll = new LinearLayout(this);
  ll.setBackgroundColor(Color.BLUE);
  ll.setOrientation(LinearLayout.VERTICAL);
  AbsoluteLayout.LayoutParams params=new AbsoluteLayout.LayoutParams(200,200,100,0);
  ll.setLayoutParams(params);
  AbsoluteLayout abs=(AbsoluteLayout)findViewById(R.id.lay);
  abs.addView(ll);
Ora potrebbe essere utile disegnare un bordo al layout.
Questa è una novità.
E ho trovato subito la soluzione
  LinearLayout ll = new LinearLayout(this);
  
  ll.setOrientation(LinearLayout.VERTICAL);
  AbsoluteLayout.LayoutParams params=new AbsoluteLayout.LayoutParams(200,200,100,0);
  ll.setLayoutParams(params);
  GradientDrawable gd=new GradientDrawable();
  gd.setColor(Color.WHITE);
  gd.setStroke(5, Color.BLACK);
  ll.setBackground(gd);
  AbsoluteLayout abs=(AbsoluteLayout)findViewById(R.id.lay);
  abs.addView(ll);
...che mi dà un Layout bianco con un bordo nero di spessore 5 (il numero che appare come parametro nel metodo setStroke).