Grafikus C# – Windows Forms tanfolyam › 9.1 lecke

Windows Forms · 9.1 lecke · képek

PictureBox, Image, Bitmap és képbetöltés

A 1.12 leckében a PictureBox alapjait már megismerted. A 9. fejezetben a képekkel és a rajzolással mélyebben foglalkozunk. Ebben a leckében a képek betöltését és megjelenítését tanulod meg: a SizeMode beállításait, az Image és a Bitmap osztály különbségét, a képbetöltés csapdáit (zárolt fájl, OutOfMemoryException, nem támogatott formátum), a vágólapról és a húzással érkező képeket, és az erőforrásból betöltött ábrákat.

  • kb. 100 perc
  • közepes szint
  • képbetöltés
Diáklány C# programot készít laptopon

A lecke végére

  • a PictureBox SizeMode értékeit a feladathoz igazítod;
  • különbséget teszel Image és Bitmap között, és új Bitmapot hozol létre;
  • képet töltesz be a fájl zárolása nélkül (másolat), és kezeled a hibákat;
  • ismered a támogatott formátumokat, és tudod, mit tehetsz egy nem támogatottnál;
  • képet veszel át a vágólapról, húzással és az erőforrásokból (Properties.Resources);
  • kiolvasod a kép adatait (méret, formátum, felbontás).

Mielőtt elkezded

Ehhez a leckéhez az 1.12 lecke (PictureBox, ImageList), a 7.8 lecke (OpenFileDialog) és a 7.4 lecke (MessageBox) szükséges.

8.10 Táblázatos nyilvántartás →

A PictureBox és a SizeMode

SizeModeViselkedésMikor?
NormalEredeti méret, bal felső sarokból; ami nem fér ki, levágódik.Pontos, pixelre eső megjelenítés.
StretchImageA képet a doboz méretére nyújtja (az arány torzulhat).Ritkán: csak ha az arány nem számít.
ZoomArányosan nagyítja vagy kicsinyíti a dobozba (az üres rész marad).Képnézegető, előnézet (a leggyakoribb).
CenterImageEredeti méretben középre teszi, a túlnyúló részt levágja.Ikonok, kis ábrák.
AutoSizeA doboz a kép méretére nő.Ha a doboz igazodik a képhez.
Form1.csC#
pbKep.SizeMode = PictureBoxSizeMode.Zoom;       // arányos beillesztés
pbKep.BackColor = Color.WhiteSmoke; // a Zoom üres sávjainak színe
pbKep.BorderStyle = BorderStyle.FixedSingle;

// az Image tulajdonság: kész kép (Image példány) megjelenítése
pbKep.Image = bitmap;

// az ImageLocation: útvonalból tölt (a PictureBox maga olvassa be); Load és LoadAsync is van
pbKep.ImageLocation = utvonal;
pbKep.LoadCompleted += (s, e) =>
{
if (e.Error != null) { lblInfo.Text = "A kép nem tölthető be."; }
};
Image és ImageLocationAz Image tulajdonságnak kész képet adsz. Az ImageLocation útvonalat (vagy webcímet), amelyet a doboz maga tölt be, akár a háttérben (LoadAsync). A hibát a LoadCompleted esemény adja.
Zoom és háttérszínA Zoom arányosan illeszt, ezért a doboz egyik oldalán üres sáv marad: állíts neki jó háttérszínt (BackColor).
A PictureBox csak megjelenítA PictureBox a képet nem módosítja: a nagyítás és a kicsinyítés csak a megjelenítésre vonatkozik. A kép tényleges átméretezése a 9.2 lecke témája.
Dock és AnchorÁtméretezhető ablakban a PictureBox Dock = Fill vagy Anchor beállítása és a Zoom együtt adja a jó viselkedést (6.2 lecke).

Jósolj!

A PictureBox mérete 400 × 200, a kép 100 × 100 képpontos, a SizeMode értéke Zoom. Mekkora lesz a kép a képernyőn, és hol?

Jóslat ellenőrzése

200 × 200 képpontos (a doboz magassága szab határt, az arány megmarad), a doboz közepén, két oldalán 100–100 képpontos üres sávval. A Zoom a kis képet is nagyítja (életlenebb lehet).

Image és Bitmap: mi a különbség?

Az Image az absztrakt ősosztály (bármilyen kép), a Bitmap a képpontokból álló kép. Rajzoláshoz és szerkesztéshez Bitmap kell. Új, üres Bitmap a méretével jön létre, a fájlból betöltött is átalakítható:

Form1.cs (using System.Drawing; using System.Drawing.Imaging;)C#
// 1. üres vászon: méret megadásával (a képpontok átlátszó feketék)
Bitmap vaszon = new Bitmap(400, 300);

// 2. másolat egy meglévő képről (önálló, a forrástól független)
Bitmap masolat = new Bitmap(forrasKep);

// kép adatai
lblInfo.Text = masolat.Width + " × " + masolat.Height + " képpont, "
+ masolat.PixelFormat + ", "
+ masolat.HorizontalResolution.ToString("0") + " dpi";

// egy képpont színe (lassú, csak kis képen vagy kevés pontra)
Color szin = masolat.GetPixel(10, 10);
masolat.SetPixel(10, 10, Color.Red);

// a formátum felismerése a RawFormat tulajdonsággal
string formatum = "ismeretlen";

if (forrasKep.RawFormat.Equals(ImageFormat.Png)) { formatum = "PNG"; }
else if (forrasKep.RawFormat.Equals(ImageFormat.Jpeg)) { formatum = "JPEG"; }
else if (forrasKep.RawFormat.Equals(ImageFormat.Gif)) { formatum = "GIF"; }
else if (forrasKep.RawFormat.Equals(ImageFormat.Bmp)) { formatum = "BMP"; }
Méret és felbontásA Width és Height képpontban adott. A HorizontalResolution (dpi) a nyomtatáshoz fontos, a képernyőn a pixel számít.
GetPixel és SetPixelEgyszerű, de lassú (minden hívás zárol és old). Néhány pontra jó, egész kép feldolgozásához a LockBits kell (haladó téma).
PixelFormatMegmondja, hogyan tárolja a képpontot (Format32bppArgb: átlátszósággal, Format24bppRgb: nélküle). A JPEG nem tárol átlátszóságot.
Támogatott formátumokA .NET (GDI+) BMP, JPEG, PNG, GIF és TIFF képet olvas. A WebP és sok más formátumot natívan nem; ezekhez külön (NuGet) könyvtár vagy előzetes átalakítás kell.

Jósolj!

Egy JPEG-ből betöltött kép PixelFormat értéke Format24bppRgb. A kódod SetPixel(10, 10, Color.FromArgb(0, 255, 0, 0)) hívással átlátszó pontot próbál beállítani. Mi látszik a képen?

Jóslat ellenőrzése

A pont nem lesz átlátszó: az alfa csatornát nem tároló formátum eldobja az átlátszóságot (piros vagy fekete pont jelenik meg). Ha átlátszóság kell, új Bitmapot hozz létre Format32bppArgb formátummal, és arra rajzolj.

Biztonságos képbetöltés

A legegyszerűbb betöltés (Image.FromFile(utvonal)) két ismert hibát hoz: (1) a kép zárolja a fájlt, amíg az Image él, ezért nem törölhető, nem írható felül (a saját programodból sem); (2) érvénytelen vagy nem támogatott kép esetén OutOfMemoryException kivételt dob (a név félrevezető: nem a memória fogyott el). A megoldás: a kép betöltése, másolat készítése, a forrás azonnali felszabadítása, és try–catch:

Form1.cs (using System.IO;)C#
// zárolás nélküli betöltés: a fájl azonnal szabad, a visszaadott Bitmap önálló
private Bitmap KepBetolt(string utvonal, out string hiba)
{
hiba = "";

try
{
using (Image forras = Image.FromFile(utvonal))
{
return new Bitmap(forras); // a másolat nem hivatkozik a fájlra
}
}
catch (OutOfMemoryException)
{
hiba = "A fájl nem érvényes vagy nem támogatott képformátum.";
}
catch (FileNotFoundException)
{
hiba = "A fájl nem található.";
}
catch (IOException ex)
{
hiba = "A fájl nem olvasható: " + ex.Message;
}
catch (UnauthorizedAccessException)
{
hiba = "Nincs jogosultság a fájl olvasásához.";
}

return null;
}

// a megjelenítés: a régi kép felszabadítása az újra cserélés előtt (9.8 lecke)
private void Mutat(Bitmap uj)
{
Image regi = pbKep.Image;

pbKep.Image = uj;

if (regi != null)
{
regi.Dispose(); // csak az új kép beállítása UTÁN
}
}
A zárolás okaA GDI+ a képet lustán, a fájlból olvassa, ezért a fájl nyitva marad. A másolat (new Bitmap(forras)) a képpontokat a memóriába viszi, így a forrás szabadítható.
OutOfMemoryExceptionEzt a kivételt a GDI+ dobja érvénytelen képfájlnál (sérült, szöveges fájl .jpg névvel, nem támogatott formátum). A hibaüzenetben a „nem érvényes kép” a helyes magyarázat.
using és másolatA using a forrás Image-et felszabadítja, a másolat él tovább. Nagy képnél a másolás memóriát és időt igényel: ezt a 9.8 lecke részletezi.
Régi kép felszabadításaA PictureBox a régi képet nem szabadítja fel: ha nem Dispose-olod, a memória nő, amíg a szemétgyűjtő nem dolgozik. Előbb az újat állítsd be, utána szabadítsd a régit.

Jósolj!

A kódod pbKep.Image = Image.FromFile(utvonal) módon tölt, majd a felhasználó a Törlés gombra kattintva törölné a fájlt (File.Delete(utvonal)), amíg a kép látszik. Mi történik?

Jóslat ellenőrzése

IOException (a fájlt másik folyamat használja): a betöltött kép zárolja a fájlt, a saját programod miatt. A másolattal betöltött képnél a törlés működik.

Vágólap, húzás és erőforrás

Form1.csC#
// 1. kép a vágólapról (Ctrl+V)
private void Beillesztes()
{
if (Clipboard.ContainsImage())
{
Mutat(new Bitmap(Clipboard.GetImage())); // másolat: a vágólap képe nem a miénk
}
}

// 2. húzás az ablakra (AllowDrop = true a Formon)
private void Form1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None;
}

private void Form1_DragDrop(object sender, DragEventArgs e)
{
string[] utak = (string[])e.Data.GetData(DataFormats.FileDrop);
string hiba;
Bitmap kep = KepBetolt(utak[0], out hiba);

if (kep != null) { Mutat(kep); } else { lblInfo.Text = hiba; }
}

// 3. a projekt erőforrásából (Properties → Resources → Add Existing File)
pbLogo.Image = Properties.Resources.logo; // a név az erőforrás neve; futás közben a programba ágyazva van
VágólapA Clipboard.GetImage() a vágólapon lévő képet adja (másik program képét is). A ContainsImage() előbb megmondja, van-e ott kép.
HúzásA FileDrop formátum a fájlok útvonalának tömbjét adja. A húzott fájl bármi lehet: a KepBetolt hibakezelése itt is kell.
ErőforrásAz erőforrásba tett kép a programba épül (nem kell hozzá külön fájl). A Properties.Resources.név minden hívásra új példányt ad: ne hívd ciklusban, tedd változóba.
Webes képA PictureBox.LoadAsync(url) webcímről is tölt (a háttérben). Idegen internetes forrás képét óvatosan kezeld; a hibát a LoadCompleted adja.

Jósolj!

A Paint vagy egy időzítő minden másodpercben a pbKep.Image = Properties.Resources.logo; sort hajtja végre. Mi történik 10 perc alatt a program memóriájával?

Jóslat ellenőrzése

A memória folyamatosan nő: a Resources.logo minden hívása új Bitmapot készít, és a régit senki nem szabadítja fel (Dispose). Egyszer töltsd változóba, és azt használd.

📷 Képernyőkép helye

Mit tegyél ide: a képnézegető ablak egy képpel (Zoom), a kép adataival és a „Kép beillesztve a vágólapról” üzenettel.Javasolt fájlnév: winforms-9-1-kepnezegeto.webp · Alt szöveg: A képnézegető program

Hibakeresés: te vagy a hibadetektív

Mi a baj, és hogyan javítod?

Gondold végig az okot, és csak utána nyisd le a megoldást.

1. OutOfMemoryException, pedig van szabad memória

pbKep.Image = Image.FromFile("jegyzet.txt");   // nem kép
Hiba és javítás

A GDI+ ezt a kivételt dobja érvénytelen képfájlnál. Védd try–catch blokkal, és mondd meg a felhasználónak: a fájl nem támogatott képformátum.

2. A fájl nem törölhető, mert „használatban van”

A kép megjelenítése után a program nem tudja átnevezni vagy törölni a fájlt.

Ok és javítás

Az Image.FromFile zárolja a fájlt. Töltsd be másolattal (new Bitmap(forras)), és szabadítsd a forrást (using).

3. Piros X a PictureBox-ban

using (Bitmap kep = new Bitmap(200, 100))
{
pbKep.Image = kep; // a using vége felszabadítja a megjelenített képet
}
Hiba és javítás

A using a blokk végén megsemmisíti a képet, amelyet a PictureBox még használ: a következő rajzoláskor piros X (vagy kivétel) jelenik meg. A megjelenített képet ne szabadítsd fel; csak a régit, az új beállítása után.

4. A kép torzult

A kép megnyúlt a dobozban.

Ok és javítás

A SizeMode értéke StretchImage. Használd a Zoom módot (arány megtartása).

5. Nő a memóriahasználat új kép betöltésekor

Sok kép megnyitása után a program lassul.

Ok és javítás

A régi képet nem szabadítod fel. Az új kép beállítása után hívd a régi Dispose() metódusát (lásd a Mutat metódust).

6. A WebP képet nem nyitja meg

A felhasználó .webp fájlt nyit meg, és hibát kap.

Ok és javítás

A GDI+ nem támogatja a WebP formátumot. Jelezd érthetően (ez a formátum nem támogatott), vagy használj külső könyvtárat (NuGet), illetve kérd az átalakítást PNG-be.

Mini projekt: képnézegető

Készíts egyszerű képnézegetőt:

  1. Felület: pbKep (Dock = Fill, SizeMode = Zoom, BackColor világosszürke), alul FlowLayoutPanel a gombokkal: Megnyitás..., Előző, Következő, Beillesztés; a cmbMod a SizeMode kiválasztásához (Zoom, Nyújtás, Eredeti méret, Középre); lblInfo az állapotsorban.
  2. Megnyitás: az OpenFileDialog (Multiselect = true, szűrő: Képek (*.png;*.jpg;*.jpeg;*.bmp;*.gif)) a kiválasztott fájlokat egy listába (List<string>) teszi; az első jelenik meg.
  3. Léptetés: Előző és Következő (a lista végén körbe); a ← és → billentyű is (ProcessCmdKey vagy KeyPreview, 5.4 lecke).
  4. Betöltés zárolás nélkül: a KepBetolt metódus másolatot ad; a hibákat (nem támogatott, hiányzó, jogosultság) az állapotsor jelzi, és a program a következő képre léphet.
  5. Adatok: az lblInfo mutatja a fájl nevét, méretét képpontban, a fájlméretet (KB), a formátumot és a sorszámot (3 / 12).
  6. Vágólap és húzás: Ctrl+V beilleszti a vágólap képét (Beillesztett kép felirattal); a képfájl ablakra húzása megnyitja a fájlokat.
  7. Felszabadítás: új kép beállítása után a régi Dispose; a program zárásakor a megjelenített kép is.
  8. Teszteld: több kép, nem képfájl (.txt átnevezve .png-re), nagy kép, fájl törlése megjelenítés közben (a másolat miatt működik), WebP, vágólapról beillesztés, húzás, a SizeMode módok.
Megoldás megnyitása (próbáld ki előbb önállóan!)

A képfájlok listája és az aktuális index kezeli a léptetést; a kép megjelenítése a Mutat metóduson át történik, amely a régit felszabadítja.

Form1.cs (using System.IO; using System.Drawing.Imaging; using System.Collections.Generic;)C#
private List<string> fajlok = new List<string>();
private int index = -1;

private void Form1_Load(object sender, EventArgs e)
{
this.AllowDrop = true;
this.KeyPreview = true;
cmbMod.Items.AddRange(new object[] { "Zoom", "Nyújtás", "Eredeti méret", "Középre" });
cmbMod.SelectedIndex = 0;
ofd.Filter = "Képek (*.png;*.jpg;*.jpeg;*.bmp;*.gif)|*.png;*.jpg;*.jpeg;*.bmp;*.gif|Minden fájl (*.*)|*.*";
ofd.Multiselect = true;
}

private Bitmap KepBetolt(string utvonal, out string hiba)
{
hiba = "";

try
{
using (Image forras = Image.FromFile(utvonal))
{
return new Bitmap(forras);
}
}
catch (OutOfMemoryException) { hiba = "Nem érvényes vagy nem támogatott kép: " + Path.GetFileName(utvonal); }
catch (FileNotFoundException) { hiba = "A fájl nem található: " + Path.GetFileName(utvonal); }
catch (IOException ex) { hiba = "A fájl nem olvasható: " + ex.Message; }
catch (UnauthorizedAccessException) { hiba = "Nincs jogosultság: " + Path.GetFileName(utvonal); }

return null;
}

private void Mutat(Bitmap uj)
{
Image regi = pbKep.Image;

pbKep.Image = uj;

if (regi != null) { regi.Dispose(); }
}

private string Formatum(Image kep)
{
if (kep.RawFormat.Equals(ImageFormat.Png)) { return "PNG"; }
if (kep.RawFormat.Equals(ImageFormat.Jpeg)) { return "JPEG"; }
if (kep.RawFormat.Equals(ImageFormat.Gif)) { return "GIF"; }
if (kep.RawFormat.Equals(ImageFormat.Bmp)) { return "BMP"; }

return "egyéb";
}

private void Megjelenit(int ujIndex)
{
if (fajlok.Count == 0) { return; }

// legfeljebb egyszer körbe: a hibás fájlokat átugorjuk
for (int probalkozas = 0; probalkozas < fajlok.Count; probalkozas++)
{
int i = ((ujIndex + probalkozas) % fajlok.Count + fajlok.Count) % fajlok.Count;
string hiba;
Bitmap kep;
string utvonal = fajlok[i];

kep = KepBetolt(utvonal, out hiba);

if (kep != null)
{
index = i;
Mutat(kep);
long meret = new FileInfo(utvonal).Length;

lblInfo.Text = Path.GetFileName(utvonal) + " – " + kep.Width + " × " + kep.Height + " képpont, " + Formatum(kep) + ", " + (meret / 1024) + " KB (" + (index + 1) + " / " + fajlok.Count + ")";
return;
}

lblInfo.Text = hiba;
}
}

private void btnMegnyit_Click(object sender, EventArgs e)
{
if (ofd.ShowDialog(this) == DialogResult.OK)
{
fajlok = new List<string>(ofd.FileNames);
Megjelenit(0);
}
}

private void btnKovetkezo_Click(object sender, EventArgs e) { Megjelenit(index + 1); }
private void btnElozo_Click(object sender, EventArgs e) { Megjelenit(index - 1); }

private void cmbMod_SelectedIndexChanged(object sender, EventArgs e)
{
PictureBoxSizeMode[] modok = { PictureBoxSizeMode.Zoom, PictureBoxSizeMode.StretchImage, PictureBoxSizeMode.Normal, PictureBoxSizeMode.CenterImage };

pbKep.SizeMode = modok[cmbMod.SelectedIndex];
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Right) { btnKovetkezo.PerformClick(); e.Handled = true; }
else if (e.KeyCode == Keys.Left) { btnElozo.PerformClick(); e.Handled = true; }
else if (e.Control && e.KeyCode == Keys.V) { btnBeillesztes.PerformClick(); e.Handled = true; }
}

private void btnBeillesztes_Click(object sender, EventArgs e)
{
if (Clipboard.ContainsImage())
{
Mutat(new Bitmap(Clipboard.GetImage()));
lblInfo.Text = "Beillesztett kép a vágólapról.";
}
else
{
lblInfo.Text = "A vágólapon nincs kép.";
}
}

private void Form1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None;
}

private void Form1_DragDrop(object sender, DragEventArgs e)
{
fajlok = new List<string>((string[])e.Data.GetData(DataFormats.FileDrop));
Megjelenit(0);
}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (pbKep.Image != null) { pbKep.Image.Dispose(); }
}
📷 Képernyőkép helye

Mit tegyél ide: a kész képnézegető egy fényképpel, a gombokkal és az adatsorral.Javasolt fájlnév: winforms-9-1-kesz.webp · Alt szöveg: A kész képnézegető

Három önálló gyakorlófeladat

Egyszerre csak egyet csinálj: tervezd meg, írd meg, futtasd, ellenőrizd, és csak utána nyisd ki a megoldást.

1. Kép színe egérkattintásra

A felhasználó a képre kattint, és a program kiírja a kattintott képpont színét (RGB). A PictureBox Zoom módban van: hogyan számolod a kép koordinátáját?

Egy lehetséges megoldás

Zoom módban az egér koordinátáját a megjelenítési arányból és az eltolásból kell visszaszámolni (a 9.5 lecke). Egyszerűbb: Normal módban a koordináta közvetlenül a kép koordinátája.

Form1.csC#
private void pbKep_MouseClick(object sender, MouseEventArgs e)
{
Bitmap kep = pbKep.Image as Bitmap;

// Normal módban: e.X és e.Y a kép pontja (ha a kép kisebb a doboznál, ellenőrizzük a határt)
if (kep != null && e.X < kep.Width && e.Y < kep.Height)
{
Color c = kep.GetPixel(e.X, e.Y);
lblSzin.Text = "RGB(" + c.R + ", " + c.G + ", " + c.B + ")";
pnlSzin.BackColor = c;
}
}

2. Üres vászon létrehozása

Az Új kép gomb 400 × 300 képpontos fehér Bitmapot hoz létre. Hogyan töltöd fehérre (a Bitmap alapból átlátszó fekete)?

Egy lehetséges megoldás

A Graphics.FromImage segítségével a Clear(Color.White) metódussal (9.3 lecke), using blokkban.

Form1.csC#
Bitmap vaszon = new Bitmap(400, 300);

using (Graphics g = Graphics.FromImage(vaszon))
{
g.Clear(Color.White);
}

Mutat(vaszon);

3. Kép adatai egy ablakban

A Tulajdonságok gomb egy modális ablakban mutatja a kép adatait (méret, formátum, felbontás, fájlméret). Hogyan adod át az adatot (7.7 lecke)?

Egy lehetséges megoldás

Az adatokat szövegként (vagy kis adatosztályban) a konstruktor kapja, az ablak csak megjeleníti. A Bitmapot ne add át az ablaknak (így nem keveredik a felszabadításuk).

Gyakorlótár: 6 további feladat

Három szinten gyakorolhatsz: alap, közepes és kihívás. Csak a próbálkozás után nyisd le a megoldást.

Alap szint

1. SizeMode választás

Melyik SizeMode: (a) fényképek előnézete; (b) 16 × 16-os ikon középen; (c) a doboz igazodjon a képhez?

Megoldás megnyitása

(a) Zoom; (b) CenterImage; (c) AutoSize.

2. Mi a különbség?

Mi a különbség az Image.FromFile és a new Bitmap(Image.FromFile(...)) között a fájlzárolás szempontjából?

Megoldás megnyitása

Az Image.FromFile által adott kép zárolja a fájlt, amíg él. A másolat (new Bitmap(...)) önálló: a forrás Dispose hívása után a fájl szabad. (A másolat készítésénél a forrást using blokkal kell szabadítani.)

Közepes szint

3. Fájlméret olvasható alakban

A fájlméretet B, KB, MB egységben írd ki. Hol van ilyen metódus korábbról?

Megoldás megnyitása

A 7.8 lecke Meret(long) metódusa: a 1024-gyel osztás ciklusa.

4. Kép mentése másként

A megjelenített képet PNG-ként mentenéd. Melyik metódust használod, és mire kell vigyáznod?

Megoldás megnyitása

Az Image.Save(útvonal, ImageFormat.Png) metódust (részletek a 9.2 leckében). Ne ugyanarra a fájlra mentsd, amelyből a kép betöltődött, ha a kép zárolja (a másolatos betöltés ezt megszünteti).

Kihívás szint

5. Mappa képeinek bélyegképei

Egy mappa képeit kis (96 pixel) bélyegképként mutasd FlowLayoutPanelben. Mire kell figyelned a memória miatt?

Megoldás megnyitása

Mindegyik bélyegkép külön Bitmap, ezért a mappa váltásakor az összes régit fel kell szabadítani (Dispose), a nagy eredeti képeket pedig csak a bélyegkép elkészítéséig tartani (9.2 és 9.8 lecke).

6. Lassú kép betöltése a háttérben

Egy hálózati meghajtón lévő nagy képet a felület lefagyása nélkül töltenél be. Mi a megoldás elve?

Megoldás megnyitása

A betöltés háttérszálon (Task.Run), az eredmény megjelenítése a felület szálán (await, 11. fejezet). Addig a PictureBox.LoadAsync is használható útvonalra.

Gyors önellenőrzés

Válaszolj fejben, és csak utána nyisd le a választ.

1. Melyik SizeMode tartja meg az arányt?

A Zoom (és az eredeti méretű Normal, CenterImage); a StretchImage torzít.

2. Mi az Image és a Bitmap viszonya?

Az Image az ősosztály, a Bitmap képpontokból álló, szerkeszthető kép.

3. Miért zárolja a fájlt az Image.FromFile?

A GDI+ lustán olvassa a fájlt, ezért nyitva tartja; másolattal oldható meg.

4. Mit jelent a OutOfMemoryException képbetöltéskor?

Általában: a fájl nem érvényes vagy nem támogatott képformátum.

5. Melyik képformátumokat támogatja a GDI+?

BMP, JPEG, PNG, GIF, TIFF (a WebP-t nem).

6. Mikor szabadítod fel a régi képet?

Az új kép beállítása után (Dispose), különben a megjelenített kép megsemmisülne.

7. Miért veszélyes a Properties.Resources.kép ciklusban?

Minden hívás új Bitmapot készít: változóba kell tenni.

Mit tudsz már?

  • A PictureBox módjait feladathoz igazítod.
  • Különbséget teszel Image és Bitmap között, és új vásznat hozol létre.
  • Képet töltesz be zárolás nélkül, hibatűrően.
  • Képet veszel át a vágólapról, húzással és az erőforrásból.
  • A régi képeket felszabadítod, és elkerülöd a gyakori hibákat.

Következő lecke: Képek igazítása, méretezése és mentése

A kép tényleges átméretezése jó minőségben, forgatás, tükrözés, vágás és mentés különböző formátumokban.