Avatar
Marek
Člen
Avatar
Marek:

Zdar,
chci se zeptat, je možno udělat screen obrazovky z konzolové aplikaci? V okenní aplikaci nemám problém si an to vytvořit vlastní funkci.

void Screen (string cesta)
{
        Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
        Graphics graphics = Graphics.FromImage(bitmap as Image);
        graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
        bitmap.Save(cesta, ImageFormat.Jpeg);
}

Jak to ale udělat v konzolové aplikaci? using System.Drawing; nepomáhá.

 
Odpovědět 1. září 15:53
Avatar
Lukas C#
Redaktor
Avatar
Lukas C#:

Pro příště: musíš taky napsat, jestli ti to píše chybu nebo jestli se to spustí, ale nic to nedělá. Pravděpodobně sis nepřidal referenci na System.Drawing.dll.

Editováno 1. září 16:05
 
Nahoru Odpovědět 1. září 16:04
Avatar
David Oczka
Redaktor
Avatar
Odpovídá na Marek
David Oczka:

Také je třeba přidat referenci pro System.Window­s.Forms, protože používáš třídu Screen. Také není úplně dobré dávat metodám nebo proměnným stejný název jako je třída, které už používáš (Mám na mysli metodu Screen a třídu Screen)...

Tvůj kód pak funguje bez problémů...

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ScreenTest
{
    class Program
    {
        static void Main(string[] args)
        {
            GetScreen("test.jpg");
        }

        static void GetScreen(string cesta)
        {
            Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            Graphics graphics = Graphics.FromImage(bitmap as Image);
            graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
            bitmap.Save(cesta, ImageFormat.Jpeg);
        }
    }
}
Editováno 1. září 16:11
Akceptované řešení
+20 Zkušeností
+1 bodů
Řešení problému
 
Nahoru Odpovědět 1. září 16:11
Avatar
Marek
Člen
Avatar
Odpovídá na Lukas C#
Marek:

Edit:
díky :)

Editováno 1. září 16:18
 
Nahoru Odpovědět 1. září 16:17
Avatar
David Oczka
Redaktor
Avatar
Odpovídá na Marek
David Oczka:

Obrázky asi vypoví více než tisíc slov. V příloze je máš. Ale ve zkratce prostě klikneš pravým na Reference v Solution exploreru a vybereš vlevo Assemblies a tam najdeš seznam s výše zmíněnými namespacy.

 
Nahoru Odpovědět 1. září 16:22
Avatar
Lukas C#
Redaktor
Avatar
Odpovídá na Marek
Lukas C#:

Kromě "using namespace", které ti pouze zjednodušší psaní názvů tříd (např. namísto System.Drawin­g.Bitmap můžeš psát jenom Bitmap) musíš přidat ještě referenci na soubor .dll, kde je toto namespace a jeho třídy definované. Namespace System.Drawing se nachází v System.Drawing.dll, System.Window­s.Forms v System.Window­s.Forms.dll (ne vždy to takhle pěkně koresponduje). Ve Visual studiu klikneš pravým na projekt v solution exploreru, zvolíš Add -> Reference. V seznamu pak najdeš všechny dll, co potřebuješ a dáš OK. V projektu Windows Forms se tyto reference přidají automaticky, v Console application ne (protože se nepředpokládá, že by to někdo chtěl použít).

 
Nahoru Odpovědět 1. září 16:23
Avatar
Marek
Člen
Avatar
Odpovídá na David Oczka
Marek:

Díky, to už jsem si dohledal a pochopil, díky moc oběma :)

 
Nahoru Odpovědět 1. září 16:23
Avatar
Marek
Člen
Avatar
Marek:

Měl bycj ještě prosbu hoši. Učím se trošku pokus omyl, tak vám předem děkuji za vaši trpělivost. Když to zacyklím se čítením vstupu a napřiklad při vstupu čísla 9 mi to udělá screen. S každým screenem mi program vezme 9MB z paměti, nevíte, jak tuto pamět znovu uvolnit?

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ScreenTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string znak = "";
            while(1==1)
            {
                znak = Console.ReadLine();
                if (znak == "9")
                {
                    GetScreen(@"C:\Users\okay\AppData\Roaming\KlavModul\screen");
                }
            }
        }

        static void GetScreen(string cesta)
        {
            Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            Graphics graphics = Graphics.FromImage(bitmap as Image);
            graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
            bitmap.Save(cesta + DateTime.Now.ToString("MMddyyHmmss") + ".jpeg", ImageFormat.Jpeg);
        }
    }
}
 
Nahoru Odpovědět 1. září 17:04
Avatar
Lukas C#
Redaktor
Avatar
Odpovídá na Marek
Lukas C#:

Paměť za tebe uvolní (v tomto případě) GarbageCollector. Ten Bitmap bitmap je lokální proměnná funkce, takže po jejím skončení na ten objekt nevede žádná reference, tudíž je označen jako připravený k odstranění. Jakmile by tvojí aplikaci docházela paměť, tak se GC zapne a uvolní všechny takto označené objekty. Jestli to chceš dělat explicitně, tak použij bitmap.Dispose().
Dále: while(true) je hezčí než while(1==1) :-)

 
Nahoru Odpovědět 1. září 17:15
Avatar
Lukas C#
Redaktor
Avatar
Odpovídá na Lukas C#
Lukas C#:

Alternativně můžeš použít direktivu "using":

using(Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
{
        Graphics graphics = Graphics.FromImage(bitmap as Image);
            graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
            bitmap.Save(cesta + DateTime.Now.ToString("MMddyyHmmss") + ".jpeg", ImageFormat.Jpeg);
}

Jediné, co "using" způsobí je, že po skončení kódu ve složených závorkách se automaticky zavolá metoda Dispose() na objektu, který jsi deklaroval v "using" závorkách.

 
Nahoru Odpovědět  +1 1. září 17:18
Avatar
Marek
Člen
Avatar
Marek:

Díky, bylo to ještě třeba provést in na objektu graphics.

 
Nahoru Odpovědět 1. září 17:24
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na Lukas C#
Jan Vargovský:

Paměť za tebe uvolní (v tomto případě) GarbageCollector

Všechno co implementuje IDisposable bys měl mít v using bloku (pokud to používáš v jednom scopu), jinak si koleduješ o memory leaky. Jestliže to máš uvnitř nějaké třídy jako propertu/field, tak bys měl pak implementovat taky IDisposable a prochainovat ty věci a uvolnit je (zavolat na nich Dispose()).

Btw, Dispose neznamená smazání objektu, ale uvolnění unmanaged věcí, které nejsou v řežii GC. To jen tak na okraj... Otázka na zamyšlení, to bys potom při každém " ... new " měl uzavírat do usingu? Pogoogli si rozdíl mezi managed a unmanaged resourcy :)

Editováno 1. září 19:07
 
Nahoru Odpovědět 1. září 19:05
Avatar
Lukas C#
Redaktor
Avatar
Odpovídá na Jan Vargovský
Lukas C#:

Rozdíl znám z WinAPI programování, jen jsem asi blbě popsal to Dispose :-) Že mám všechno, co implementuje IDisposable dávat do using nebo na tom volat Dispose(), jsem už slyšel mockrát, ale opravdu je to třeba tady nutné? Reference bitmap se po skončení metody dostane mimo scope => je ready na destrukci. Pokud náhodou dojde paměť, GC se spustí a zavolá na těchto objektech destruktor. A destruktor ve třídě Image volá Dispose() => zdroje se uvolní. To samé s Graphics.

 
Nahoru Odpovědět 1. září 19:38
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Lukas C#
patrik.valkovic:

Nejde jenom u ovolňování zdrojů. Pokud máš třída destrujtor, tak je to naprosto mimo rámec GC. Pro prvním průchodu se přesune do Finalizovane fronty a tam straší jeste pěkně dlouho, než se destruktor zavola. Pomocí using se tomu vyhneš, destruktor obejdeš a vrátíš správu zpět GC.

Nahoru Odpovědět  +1 2. září 7:49
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Marian Benčat
Redaktor
Avatar
Marian Benčat:

Je s podivem, kolik programátorů netuší, jak funguje GC, Disposable i finalizer. Chápu, že každý nemusí vědět o generacích a rozdílech například u velkých objektů. Ale alespoň by už mohli vědět, kdy GC co může uvolnit a jak to udělat dříve.

 
Nahoru Odpovědět 2. září 11:56
Avatar
coells
Redaktor
Avatar
Odpovídá na Lukas C#
coells:

GC a destruktory si moc nerozumí.

Protože GC běží na vlastním vlákně, nedá se nikdy říct, kdy a co provede.
Pokud třída pracuje s unmanaged resources nebo potřebuje při své destrukci vyvolat explicitní akci, nelze se na destruktor spoléhat, to mají společné všechny platformy s GC.

Další platformy, které se tomu snaží vyhnout (.NET tam nepatří), a které kombinují reference counting s GC mají zase problém s garancí zavolání destruktoru.

Při vyšším tlaku na heap nebo zaplnění paměti se GC nezavolá, to je daleko komplikovanější.
Spuštění GC v takové situaci znamená zamrznutí programu, což bylo dlouhá léta chování, kterým trpěla Java.
Odtud také pochází původní varování, že Java nesměla být nasazována v real-time systémech jako letadla nebo elektrárny.
Dříve by program spadl na out of memory a GC by proti tomu nic neudělal.
Dnes zafunguje virtualizace paměti na úrovni OS a začnou se dít nehezké věci, často horší, než ukončení programu.

A na závěr perlička.
Protože je GC chování nedeterministické a záleží na plánování zdrojů OS, bude se program chovat jinak ve vývojovém režimu a jinak v produkčním, jinak na i5 a jinak na i7 nebo i7 se zakázanou virtulizací.
Objekt, který ve vývojovém režimu spadne do vyšší generace, může v produkčním režimu zůstat v nulté generaci a získat prioritu pro uvolnění před jiným objektem, pořadí destrukce objektů je tedy také nepredikovatelné.
Jinak řečeno, na různých počítačích se začnou projevovat různé chyby, které nepůjdou verifikovat.

Takže ano, pokud si nejsi naprosto jistý, že objekt implementuje Dispose jen proto, že musí, měl bys vždy používat using.

 
Nahoru Odpovědět  +3 2. září 12:28
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na coells
patrik.valkovic:

Reference counting nemá problém se zavoláním destruktoru, problém je samotné počítání referencí, které o hodně zpomaluje program. Koneckonců, je to jedna z věcí, která je doporučena pro C++. Tam si ale dokážeme spoustu paměti hlídat sami, takže se reference nepočítá u naproto každého objektu a nároky nejsou tak vysoké.

Nahoru Odpovědět 2. září 13:42
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
coells
Redaktor
Avatar
Odpovídá na patrik.valkovic
coells:

Jak jsem psal, kombinace refcountingu s GC má velký problém s voláním destruktorů.
Počínaje určením vlákna, na kterém destruktor poběží a konče synchronizací GC/RC, když dochází k uvolnění.

Narozdíl od GC je RC velice rychlé (teď už nemluvím o jejich kombinaci), protože odpadá synchronizace vláken a neběží tam explicitní vlákno pro GC. RC se dá implementovat velice efektivně, implementace retain/release cyklu může být levná i při synchronizaci.

 
Nahoru Odpovědět 2. září 14:12
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 18 zpráv z 18.