IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
Marek
Člen
Avatar
Marek:1.9.2016 15:53

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.9.2016 15:53
Avatar
Neaktivní uživatel:1.9.2016 16:04

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.9.2016 16:05
Nahoru Odpovědět
1.9.2016 16:04
Neaktivní uživatelský účet
Avatar
David Oczka
Tvůrce
Avatar
Odpovídá na Marek
David Oczka:1.9.2016 16:11

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.9.2016 16:11
Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
 
Nahoru Odpovědět
1.9.2016 16:11
Avatar
Marek
Člen
Avatar
Odpovídá na Neaktivní uživatel
Marek:1.9.2016 16:17

Edit:
díky :)

Editováno 1.9.2016 16:18
 
Nahoru Odpovědět
1.9.2016 16:17
Avatar
David Oczka
Tvůrce
Avatar
Odpovídá na Marek
David Oczka:1.9.2016 16:22

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.9.2016 16:22
Avatar
Odpovídá na Marek
Neaktivní uživatel:1.9.2016 16:23

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.9.2016 16:23
Neaktivní uživatelský účet
Avatar
Marek
Člen
Avatar
Odpovídá na David Oczka
Marek:1.9.2016 16:23

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

 
Nahoru Odpovědět
1.9.2016 16:23
Avatar
Marek
Člen
Avatar
Marek:1.9.2016 17:04

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.9.2016 17:04
Avatar
Odpovídá na Marek
Neaktivní uživatel:1.9.2016 17:15

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.9.2016 17:15
Neaktivní uživatelský účet
Avatar
Odpovídá na Neaktivní uživatel
Neaktivní uživatel:1.9.2016 17:18

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.9.2016 17:18
Neaktivní uživatelský účet
Avatar
Marek
Člen
Avatar
Marek:1.9.2016 17:24

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

 
Nahoru Odpovědět
1.9.2016 17:24
Avatar
Jan Vargovský
Tvůrce
Avatar
Odpovídá na Neaktivní uživatel
Jan Vargovský:1.9.2016 19:05

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.9.2016 19:07
 
Nahoru Odpovědět
1.9.2016 19:05
Avatar
Odpovídá na Jan Vargovský
Neaktivní uživatel:1.9.2016 19:38

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.9.2016 19:38
Neaktivní uživatelský účet
Avatar
Odpovídá na Neaktivní uživatel
Patrik Valkovič:2.9.2016 7:49

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
2.9.2016 7:49
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Marian Benčat:2.9.2016 11:56

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.9.2016 11:56
Totalitní admini..
Avatar
coells
Tvůrce
Avatar
Odpovídá na Neaktivní uživatel
coells:2.9.2016 12:28

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
2.9.2016 12:28
Avatar
Odpovídá na coells
Patrik Valkovič:2.9.2016 13:42

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.9.2016 13:42
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
coells
Tvůrce
Avatar
Odpovídá na Patrik Valkovič
coells:2.9.2016 14:12

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.9.2016 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.