Ho deciso di provare qualcosa da solo. Ho trovato un semplice codice GDI +, che usa le tessere che ho già ricevuto. Ho solo filtrato le parti che sono rilevanti per la regione di ritaglio corrente. Funziona come per magia! Si prega di trovare il mio codice qui sotto. (Impostazioni modulo doppio buffering per i migliori risultati)
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics dc = e.Graphics;
dc.ScaleTransform(1.0F, 1.0F);
Size scrollOffset = new Size(AutoScrollPosition);
int start_x = Math.Min(matrix_x_size,
(e.ClipRectangle.Left - scrollOffset.Width)/256);
int start_y = Math.Min(matrix_y_size,
(e.ClipRectangle.Top - scrollOffset.Height)/256);
int end_x = Math.Min(matrix_x_size,
(e.ClipRectangle.Right - scrollOffset.Width + 255)/256);
int end_y = Math.Min(matrix_y_size,
(e.ClipRectangle.Bottom - scrollOffset.Height + 255)/256);
// start * contain the first and last tile x/y which are on screen
// and which need to be redrawn.
// now iterate trough all tiles which need an update
for (int y = start_y; y < end_y; y++)
for (int x = start_x; x < end_x; x++)
{ // draw bitmap with gdi+ at calculated position.
dc.DrawImage(BmpMatrix[y, x],
new Point(x * 256 + scrollOffset.Width,
y * 256 + scrollOffset.Height));
}
}
Per provarlo, ho creato una matrice di 80x80 di 256 piastrelle (420 MPixel). Ovviamente dovrò aggiungere del caricamento posticipato nella vita reale. Posso lasciare le tessere (vuote) se non sono ancora state caricate. In effetti, ho chiesto al mio cliente di attaccare 8 GByte nella sua macchina, quindi non devo preoccuparmi troppo delle prestazioni. Una volta caricate le tessere può rimanere in memoria.
public partial class Form1 : Form
{
bool dragging = false;
float Zoom = 1.0F;
Point lastMouse;
PointF viewPortCenter;
private readonly Brush solidYellowBrush = new SolidBrush(Color.Yellow);
private readonly Brush solidBlueBrush = new SolidBrush(Color.LightBlue);
const int matrix_x_size = 80;
const int matrix_y_size = 80;
private Bitmap[,] BmpMatrix = new Bitmap[matrix_x_size, matrix_y_size];
public Form1()
{
InitializeComponent();
Font font = new Font("Times New Roman", 10, FontStyle.Regular);
StringFormat strFormat = new StringFormat();
strFormat.Alignment = StringAlignment.Center;
strFormat.LineAlignment = StringAlignment.Center;
for (int y = 0; y < matrix_y_size; y++)
for (int x = 0; x < matrix_x_size; x++)
{
BmpMatrix[y, x] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
// BmpMatrix[y, x].Palette.Entries[0] = (x+y)%1==0?Color.Blue:Color.White;
using (Graphics g = Graphics.FromImage(BmpMatrix[y, x]))
{
g.FillRectangle(((x + y) % 2 == 0) ? solidBlueBrush : solidYellowBrush, new Rectangle(new Point(0, 0), new Size(256, 256)));
g.DrawString("hello world\n[" + x.ToString() + "," + y.ToString() + "]", new Font("Tahoma", 8), Brushes.Black,
new RectangleF(0, 0, 256, 256), strFormat);
g.DrawImage(BmpMatrix[y, x], Point.Empty);
}
}
BackColor = Color.White;
Size = new Size(300, 300);
Text = "Scroll Shapes Correct";
AutoScrollMinSize = new Size(256 * matrix_x_size, 256 * matrix_y_size);
}
Questa è stata la parte facile.Ottenere l'i/o multithread asincrono fatto in background era molto più difficile da ottenere. Eppure, ho funzionato nel modo descritto qui. I problemi da risolvere erano più legati al multithreading .NET/Form rispetto a questo argomento.
In pseudo-codice funziona in questo modo:
after onPaint (and on Tick)
check if tiles on display need to be retrieved from disc
if so: post them to an async io queue
if not: check if tiles close to display area are already loaded
if not: post them to an async io/queue
check if bitmaps have arrived from io thread
if so: updat them on screen, and force repaint if visible
Risultato: Ora ho il mio controllo personalizzato che utilizza circa 50 MByte per un accesso molto veloce alla dimensione arbitraria (piastrelle) file TIFF.
DeepZoom sembra l'approccio. Dovrai creare versioni a bassa risoluzione delle immagini con qualcosa come http://www.imagemagick.org/script/index.php. Dalla mia ricerca, sembra che questo sia un campo minato brevettato, quindi .... – kenny