PREMESSO CHE:
Una bitmap MxN esiste come una matrice di pixel ad N righe, ed ogni riga è costituita da 3*M byte colore + un certo numero di byte riservati di valore ininfluente tanti quanti occorrono per portare la riga ad avere un numero di byte che sia multiplo di 4. Es. una bitmap 5x4 avrà 4 righe ognuna di 3*5 + 1 byte perchè 3*5 fa 15 e 15 non è multiplo di 4, serve un altro byte per arrivare a 16.
PREMESSO CHE:
La mappatura dei byte su filestream e quella in memoria sono uguali, cambia solo una cosa: nello stream si comincia dalla riga in basso e si procede da sx a dx salendo verso l'alto, nella memoria si segue invece ilo normale flusso dei pixel (dall'alto verso il basso e da sx a dx).
Detto questo
OGGETTO: ho la necessità di copiare in memoria una sotto-bitmap b2 (regione rettangolare) da una bitmap base b1 fuori memoria (su stream).
In precedenza ho presentato un codice che fa esattamente l'operazione inversa cioè copia una bitmap b2 in memoria in una bitmap base b1 fuori memoria e funziona, ma non c'è verso di fare funzionare il codice che ho scritto per l'operazione inversa come da oggetto.
Mi dite cosa ho sbagliato?
codice:
//Preleva una porzione da una bitmap su disco in base ai dati di origine x0,y0
//e le dimensioni dimx,dimy e restituisce una bitmap in memoria.
//La copia avviene per porzioni di riga e usa il Marshalling
public static Bitmap MarshalGetBmp(string path, int x0, int y0, int dimx, int dimy)
{
//Legge i dati di intestazione della base b1
Vector4 Data = GetData(path);
int Dim1 = (int)Data.X;
int Dim2 = (int)Data.Y;
int Bits = (int)Data.Z;
int Ofs = (int)Data.W;
Bitmap b2 = new Bitmap(dimx, dimy);
//bmdata contiene tutti i byte della clip
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, dimx, dimy);
System.Drawing.Imaging.BitmapData bmdata = b2.LockBits(rect,
System.Drawing.Imaging.ImageLockMode.ReadWrite,
b2.PixelFormat);
// Puntatore ad inizio bitmap clip b2
IntPtr Ptr = bmdata.Scan0;
//Lunghezza fisica di row della base
int truewidth1 = (int)((Bits * Dim1 + 31) / 32) * 4;
//Lunghezza fisica di row della b2
int truewidth2 = (int)((Bits * dimx + 31) / 32) * 4;
//n. byte da copiare (= byte x row)
int bytes = 3 * dimx;
//array dei byte colore pixel di b2
byte[] a = new byte[bytes];
// Stream della base
FileStream f = File.Open(path, FileMode.OpenOrCreate);
int sp; //puntatore stream base
//ciclo dei pixel nella regione di sovrascrittura
for (int y = y0; y < y0 + dimy; y++)
{
//puntatore stream ad inizio row (x0,y) su base
sp = Ofs + (Bits / 8) * x0 + truewidth1 * (Dim2 - y - 1);
//aggiorna puntatore stream
f.Seek(sp, SeekOrigin.Begin);
//legge i byte-pixel nello stream
f.Read(a, 0, bytes);
//copia byte array nella memoria b2
System.Runtime.InteropServices.Marshal.Copy(a, 0, Ptr, bytes);
//aggiorna il puntatore bmdata alla prossima riga di b2
Ptr = new IntPtr((int)IntPtr.Add(Ptr, truewidth2));
}
// Chiusura
b2.UnlockBits(bmdata);
f.Close();
return b2;
}
codice:
//Legge in un file bitmap e restituisce Dim1, Dim2, bits e offset
public static Vector4 GetData(string path)
{
long len;
byte[] b = new byte[30];
using (FileStream x = File.Open(path, FileMode.OpenOrCreate))
{
x.Seek(0, SeekOrigin.Begin); //Ptr a Width (4 byte)
x.Read(b, 0, b.Length);
len = x.Length;
x.Close();
}
int Ofs = Convert.ToInt32(b[10]);
int Dim1 = Convert.ToInt32(b[18]) + Convert.ToInt32(b[19]) * 256;
int Dim2 = Convert.ToInt32(b[22]) + Convert.ToInt32(b[23]) * 256;
int Bits = Convert.ToInt32(b[28]);
long bmpbytes = len - Ofs;
if (bmpbytes < Dim1 * Dim2)
{
Dim1 = Convert.ToInt32(b[18]) * 256 + Convert.ToInt32(b[19]);
Dim2 = Convert.ToInt32(b[22]) * 256 + Convert.ToInt32(b[23]);
}
if (Ofs == 0)
Ofs = 54;
if (Bits == 0)
Bits = 24;
return new Vector4(Dim1, Dim2, Bits, Ofs);
}