DELPHI4ProgrammingManual
¦ Jan2022 — UNIVERSUMS
HISTORIA | 2011V4 ¦ 2022I18 | aproduction
| Senast uppdaterade version: 2022-09-10 YMD ¦ HumanRight
is a knowledge domain
content · webbSÖK äMNESORD på
denna sida Ctrl+F • SubjectINDEX • all files • helpStart
Elementär FlytbildsTeknik
— flytbildsläget — 16;64-felet i DELPHI4 | EditColors | TabellHIMRV | Se även BILDHANTERING [PictureHANDLING/picture
manipulation] allmänt
GENERAL
IMAGE HANDLING IN Delphi4Test2022 ¦ ImportExport
Foto:
15Sep2014 E32 Bild112
· NikonD90 ¦ NaturenRef
Hur flytbildsläget fungerar med ovanstående illustrations
begrepp beskrivs också utförligt i
Exempel, 4Sep2014
I tur och ordning — detta
htm-dokument:
DelphiBegin ¦ DelphiKOD ¦ ProgramFÖNSTRET ¦ KOMPONENTER ¦ ProjektKatalogen ¦ ExeIcon ¦ Label1 ¦ ProgramENHETER ¦ Caption — FönsterNamn ¦ BildKODteknik ¦ Alla 4 Procedurer ¦ Peken ¦ Ctrl+V ¦ Resultat1 ¦ FlytBildsTEKNIK ¦ F5 ¦
BildEXPORT — Ctrl+I | PilotDISPLAY | MARKÖRACCELERATORER | Resultat2 | Flytbilden | RitaMusHÖGER | MoveMore | MultiWin ¦ Flytsätten ¦ BGOF ¦ INVERTERA ¦ RGB palett ¦ FEL1664 ¦ TBitMapInfoHeader ¦ EditColors ¦
Unit1A ¦ StreckRektangeln ¦ ClipCursor ¦ PROGRAMDIVERGENS ¦ HELPex ¦ HIMRV | Zoom | WriteText | TextIn | RamToning | CommanderDoit | Label1 | Label1 | Label1 | Label1 ¦
http://www.universumshistoria.se/AAALib/DELPHI4/HTM/AD4a1Begin.htm
29OKT2014
Behandlat | P2:
FlytBildsFunktionerna
MoveAND|Copy|SkipWHITE — Flytsätten
RitaMusHöger — motsvarar »pennan i bröstfickan»: alltid tillgänglig på bildytan
BildHantering: Invertera|Rotera90°|VändHorisontellt¦Vertikalt|Duplicera|Radera|Kopiera
— TabellHIMRV
RGB|HSB — RGB-palett med
EditColors — färgredigering och analys
WriteText — snabb, effektiv text på bild
TextIn — TrueType-text mot godtyckliga bakgrunder
RamToning — sammansmältning med flera bilder
CommanderDoit — ritaVerktyg
Elementära datorhjälpmedel — flytta kombinera sammanställa bilddetaljer UTAN NÅGON DIREKT
BILDBEHANDLINGSTEKNIK
Uppbyggnad av ett flytbildsblock i
Delphi4
Hel programform i detalj — exakt
pixelpositionering — se tabellen med alla flytbildskommandon i TabellHIMRV
Arkivet 2011 ¦ 14:
Vidareutvecklat Från DELPHI 4 Test 2011 —
BellDHARMA for UniverseHistory —
HUVUDDELEN AV VERKTYGEN MAN BEHÖVER FÖR AVANCERAD DATORANVÄNDNING I TEXT OCH
BILD
Delphi4
Programming Manual 2014|a1 — elementär
flytbildsteknik |
AllmänDistribution DELPHI4 MANUAL BellDHARMA Sep2014 — T2014
DISPOSITION T2014 |
TeckenförklaringarAllmänt: MusKLICKVänster |
Höger: |
— RullaMushjulet FRÅN |
MOTDig: |
Uppbyggnad — flytbildsblock:
1. Image1:
synlig
bildytan (»titten») vi alltid tittar på på bildskärmen;
2. Image2:
gömd
flytbilden = urklippskopian vi tar in och som ska flyttas — flyta — omkring på,
i, över, genom titten;
3. Image3:
gömd
KOPIATORN som räddar undan en tittkopia INNAN Flyten läggs på:
Nedan beskrivs detaljerna hur man kan
förverkliga verktygen: Panel1 med Image1, Image2 och Image3
— För varje ny position lägger Im3 FÖRST
tillbaka föregående uttag på TittOriginalets plats; SEDAN tar Im3 in en ny
kopia av Tittstället där Flyten kommer att läggas på i nästa snäpp — totalt med
TYP Ctrl+Pilar (eller konventionell musflyttning [jag
använder själv aldrig musen för bildflyttning i mina program; Ctrl+ NumPad 1 2
3 5 9 sätter flyttsteg om 1 5 20 Halvsida Helsida pixels: helt underbar funktion:
snabbt, exakt]) att den intagna urklippskopian FLYTER obehindrat över
Titten utan att ändra något.
Efter min erfarenhet:
1. Lägg ALDRIG en SYNLIG ImageKomponent i
DELPHI(4) direkt på en formyta = själva programfönsterkomponenten. Gör man det
upptäcker man snart ett hedjlöst FLIMRANDE vid fönsterändringar;
2. Reservera ALLTID en PanelKomponent som
bas till en SYNLIG ImageKomponent för att få störningsfria övergångar i alla
möjliga sammanhang: Panel1 med Image1 osv.
3. Principen är densamma för Labels
(textRemseKomponenter) på Image: sporadiska mindre flimmer uppkommer om
LabelKomponenten genomgår upprepade ändringar.
— Det gäller även till viss del Labels på
Panels — ett fenomen i DELPHI(4) man får försöka kämpa med och hitta lösningar
till om det börjar jävlas särskilt. Generellt sett är dock det inget problem.
— Det generella sättet att HELT eliminera
flimmertyper mellan olika pålagda komponenter är helt enkelt att skippa dem och
att skriva KOD PÅ Image direkt: I Delphi(4) finns (nämligen) ingenting man INTE
kan göra med en bild: text, grafik, foto, rit. Men dessa är bara mina egna
erfarenheten. Testa själv är bäst.
Här: DELPHI1 från Start (gavs ut som gratisprogram från
1997):
Objekt: |
|
— DELPHI4 ser ut ungefär på samma sätt, bara
med skillnaden att det finns något fler komponenter samt att hela systemet
stödjer 32-bitars databusstruktur mot endast 16 bitar i Delphi1.
— Komponenter dras från Raddan med tabbade
komponentlister till Form1 — programfönstrets bildyta — och förses med separat
KOD i Edit-fönstret som här ligger bakom Form1 (Man
växlar mellan dessa Med F12 och till ObjectInspector med F11).
— Form1-fönstret är samma som (det kommande)
programfönstret, och man fyller formen med komponenter: Knappar, Paneler
Bildytor (Image), Textboxar, Memoboxar, Listboxar, osv. — eller att man kan
skriva KOD för alla dessa.
— Bakom Form1-fönstret [F12] ligger den
avgörande centrala CodeEdit-fönstret (Unit1, Unit2, Unit ...); Programkod
skrivs där i Borland Turbo Pascal (Kodsidorna
eller Units sparas sedan i Projektkatalogen som *.pas-filer = vanliga textfiler
med specialfiländelse: sedan DELPHI4 kompilerat [Ctrl+F9] dessa till en
fungerande exe-fil, är dessa kodsidor bara »rester» — som kan byggas på, vidare
med nya kompileringar [Ctrl+9] osv.).
— Se även i INSTALLATIONSANVISNINGAR
med StartExempel hur allt ser ut från
början i DELPHI4, och hur man kan göra grundinställningar som garanterar en
maximalt smidig funktion från början.
Elementär flytbildsteknik — grundexempel i DELPHI4
Så här ser KodFönstret ut i DELPHI4 då ett
helt nytt projekt påbörjats (Alt+File), New Application:
KodFönstren i DELPHI4 finns förtecknade i ViewUnit
och anropas med Ctrl+F12,
Projekten i DELPHI4 — obs: öppnas på
SENAST ÖPPNADE — finns förtecknade i OpenProject med Ctrl+F11,
ProjektFilen man ska leta efter ock klicka på har
filändelsen dpr
med DELPHI4-logon som den gula AntikPortalen:
INGENTING AV DESSA BERÖR DOCK
NYBÖRJARENS FÖRSTA BEKANTSKAP. Ovanstående kommer senare, vid behov.
— SEDAN man initierat flera olika projekt, finns ett alternativt
sätt att växla mellan flera olika projekt — bara ett projekt åt gången får vara
öppet i DELPHI4:
— Tryck Alt+F+R(eopen);
DELPHI4 visar en lista med de senast öppnade projekten, och det är bara att
välja direkt därifrån.
— Ingen kod finns ännu inskriven. Men snart.
— Jag har här försökt trycka på F9 = KÖR för
att tvinga DELPHI4 att spara upp det nya projektet på (en av mig anvisad) plats
(Katalog P2) och ett nytt projektnamn (P2): DELPHI4 visar automatiskt
dialogrutor för detta (fyll i och fortsätt —
efter denna första initiering sköter sedan DELPHI4 automatiskt uppdateringar på
den anvisade platsen för varje ny körning;
Se mina exempel på
grundinställningar i INSTALLATIONSANVISNINGAR, AutoSaveOptions).
Jag har här (Object Inspector, tangent F11)
satt Form1-programfönstrets mått XY till 200;500pixel:
Elementär flytbildsteknik — grundexempel i DELPHI4
Nu börjar vi med att lägga in en Panel1, en
Image1, Image2, och en Image3:
— vi klickar på komponenterna på
Tabbflikarna,
släpper komponenterna på Form1-ytan, och
DELPHI4 skriver automatiskt in Grunddata åt oss;
— Ctrl+Pilar
flyttar komponenterna 1 pixel på formytan och Ctrl+Shift+Pilar flyttar 8pixels.
— Shift+PilUppNer reglerar höjd och Shift+PilVäHö reglerar längd. Dessa kan också skrivas in
med värden direkt i Object Inspector.
— Notera också Anchors på ObjectInspector:
Dubbelklicka på Achorsrutan och ställ in önskat. Standard är att varje
komponent VID FÖNSTERÄNDRINGAR ligger LÅST TopLeft. Men vi kan ändra dessa så
att t.ex. en bottenpanel alltid fortsätter ligga LeftBottom med
fönsterändringar.
— Om vi redan har en viss komponent på
formytan och vill ha flera av den typen, går det också att köra Ctrl+C, sätta fokus på formytan (annars blir den valda komponenten Parent) och
ta in en redan formaterat (Object Inspector) komponent med samma mått och
egenskaper:
Avgörande viktigt för att bildintagen ska fungera korrekt
är att vi på Object Inspector (F11) för Image2 och Image3 sätter egenskapen
AutoSize=True men False på Image1. För att säkra grundinställningarna kan vi
skriva in dem i kod på FormCreate — nedan också med en mindre aggressivt orange
bakgrundsfärg till Label1 (beskrivs
längre fram), samt en alternativ teckensnittsfärg (mörkviolett) för att
exemplifiera personliga val:
Left:= (Screen.Width -
Width) div 2;
Top:= (Screen.Height - Height) div 2;
Image1.AutoSize:= False;
Image2.AutoSize:= True;
Image3.AutoSize:= True;
Label1.Color:= RGB(255,238,221);
Label1.Font.Color:= clPurple;
De bägge översta raderna garanterar att
ProgramFönstret alltid öppnas mitt på bildskärmen.
Vad är ”clPurple”? Placera markören i
DELPHI4:s kodfönster i ordet och tryck F1: en
separat hjälpruta kommer fram från den omfattande hjälpen och beskriver
detaljerna. Grundfärger har namn (clBlack, clWhite, clBlue, clNavy, clPuple,
...), medan färger generellt kan anges i RGB eller Hexkod.
Panel1 som Parent till Image1, och två ytterligare Image separat (som kommer att fungera gömda) Image2 och Image3.
— Notera
egenskaperna Visible med True och False på komponenterna i Object Inspector: Panel1
och Image1 ska vara Visible=Synliga hela tiden, medan Image2 och 3 ska vara
Visible=False; Ctrl+Enter ändrar True/False direkt med vald komponent och
Visible i Object Inspector;
— För
att markera gemensamma egenskaper för flera komponenter åt gången: Klicka på/markera
första komponenten; håll
1. ner Shift och klicka på alla övriga som
önskas;
eller
2. MusVäNer och dra streckrektangeln över
alla;
Gå sedan till Object Inspector och sätt
önskad egenskap.
Med de ovan införda ändringarna, trycker jag
nu på Ctrl+F9 = DELPHI4 KOMPILERAR = skapar en körbar EXE-programfil som vi
sedan kör med F9 — eller bara direkt med F9 (Delphi kompilerar då först
automatiskt — och kör direkt om inga fel rapporteras).
— KodFönstrets information i Unit1 har då
ändrat utseende till följande:
Elementär flytbildsteknik — grundexempel i DELPHI4
— Vi ser att en ny Instans ”ExtCtrls” har
tillkommit — Delphi(4) lägger INTE ALLTID automatiskt till sådana i de (mycket)
speciella fallen. Men kunskaperna om dessa detaljer brukar följa med den
löpande informationen, och vi får hur som helst inblick i hemligheterna vart
efter.
— Dessutom har DELPHI4 lagt till de nu
införda komponenterna [Avancerade
programmerare kan skriva komponenter själva i VirtuellKod (som man gör i C++)
typ Image1.Picture.Create förutsatt man också städar upp efter sig innan
programslut för att inte göra datorn sur för andra som vill ha rent och snyggt
i minnet].
— PROJEKTKATALOGEN (P2) innehåller nu samtliga projektfiler enligt
Ico-filen har jag själv lagt in (från
gratisversioner på webben) för att vi senare ska testa hur man lägger in en
sådan längst upp i programfönstret. Ikonen som syns ovan för exe-filen är den
som DELPHI4 har som standard.
KODEn som krävs för att ladda in en
alternativ icon I PROGRAMFÖNSTRETS RUBRIKLIST är
Application.Icon.LoadFromFile('FilNamnet');
För att också få in en alternativ icon
i exe-filens iconInstans,
tryck Ctrl+Shift+F11 från DELPHI4, fliken Application,
LoadIcon, browsa fram till Projektkatalogen (om iconfilen finns där) och tryck
Öppna. DELPHI4 lägger då in den ikonen automatiskt i exe-filen,
— DELPHI4 förutsätter automatiskt OM INGET ANNAT ANGES att
FILNAMN UTAN SPECIELLA KATALOGREFERENSER ligger i samma katalog som exe-filen.
— OM vi använder t.ex. andra instanser
(typ sökprogram som är ute och snurrar på andra enheter) KAN vi i VARJE läge
försäkra os om att DELPHI4 hittar HemTillVåranProjektKatalog genom programkoden
ExtractFilePath(Application.ExeName);
— Vi ser redan nu, omgående, att VI MÅSTE HA
NÅGOT ENKELT VERKTYG ATT TESTA PÅSTÅENDENA från den här författaren med, se att
och HUR det verkligen fungerar
— Vi gör det genom att lägga till en Label1
(på en Panel2) på Form1,
— Synliga Namnet på Panel2 kan vi gömma undan på Object Inspector
genom att lämna Caption-boxen tom.
— Färgvalet för Label1 görs på Object
Inspector, Color — endast OMVÄND HEXkod accepteras. Exempel:
— Här är den ljusorangea RGB-färgen
255,224,184 och motsvarande HEX FF E0 B8. DELPHI4 vill emellertid ha hexformen
på omvända fasonen med inledande två nollor samt ett dollartecken
$00b8e0ff som gillas av Delphi med ändringen
$00B8E0FF om man pilar ut, med motsvarande verkställd ändrad färg. Kan också
justeras under programkörning med Label1.Color:= RGB(255,224,184);
— Avsluta programmet med Alt+F4
eller vänsterklicka på krysset.
— Eliminera ScrollBars från fönstret
via Object Inspector
genom dubbelklick på +VertScrollBar och
+HorzScrollBar och sätt (Ctrl+Enter) False på Visible.
och vilken skrivetikett vi sedan kan nå i
olika skrivuppgifter (främst, om inget annat) genom att (»baksidan» på Object
Inspector; F11, Ctrl+Tab, OnClick,
Ctrl+Enter, se nedan) aktivera ett FormKlick-kodblock i DELPHI4:
— När vi klickar på Formytan, går
programexekveringen DIT, och vi kan skriva in typ
Label1.Caption:=
ExtractFilePath(Application.ExeName);
så att vi VET att den här författaren inte
enbart pratar i nattmössan.
— »Baksidan» på Object Inspector — F11,
Ctrl+Tab OnClick, Ctrl+Enter — gör att
DELPHI4 automatiskt lägger till följande på Unit1;
Sist i type-blocket:
procedure FormClick(Sender: TObject);
Längst ner, närmast över end.:
procedure TForm1.FormClick(Sender: TObject);
begin
end;
Elementär flytbildsteknik — grundexempel i DELPHI4
Skriver vi inte in något där, och kompilerar
(Ctrl+F9) försvinner den inlagda proceduren — DELPHI4:s sätt att AutoRensa
procedurer som inte innehåller någon verkställande programkod — detta gäller
dock INTE procedurer som vi själva sedan skriver, bara DELPHI4-komponent och
händelserelaterade dito. Bara sagt i parentes.
— Vi gör nu tillägget
procedure TForm1.FormClick(Sender: TObject);
begin
Label1.Caption:=
ExtractFilePath(Application.ExeName);
ClipBoard.AsText:=
Label1.Caption;
end;
Tillägget med ClipBoard
Vi måste lägga till en Unit ”ClipBrd” till
uses-blocket först, annars reagerar DELPHI4 så här om vi försöker kompilera
(Ctrl+F9) eller köra direkt (F9):
FELMEDDEELANDEFÖNSTRET i DELPHI4 nederst
kan vara (lite) påfrestande ibland med sina »upplysningar»: Man glömmer ett och
annat, då och då i Kodningen — och lär sig med tiden uppskatta anmärkningarna:
Delphi har ALLTID rätt (på ett eller annat
sätt) MEN VI KANSKE INTE ALLTID FÖRSTÅR DET MED EN GÅNG, VAD DET ÄR FÖR
FEL VI GÖR.
— Därför är det avgörande viktigt att
nybörjaren får se EXEMPEL FRÅN REDAN FUNGERANDE ENHETER: vi vill INTE att nybörjare ska tappa
modet för att man inte lyckas med en gång.
— Säkra exempel, redan testade, är
avgörande viktiga.
Därifrån kan man sedan testa, modifiera
och ändra för att upptäcka eget.
Korrekt sätt [Se UnitRubrikerna] (Vi får leta i andra avsnitt efter lösningen, här
grundat på erfarenhet och sökningar i vad tillgängligt som finns) blir
att först lägga till [DELPHI4 har också tidigare lagt till en enhet (via
Label1) StdCtrls]
gör att jag som författare (och du som
testare) slipper skriva av visuellt från Label 1, och bara kan trycka Ctrl+V
och få in resultatet hit direkt (Vi kör F9 och
vänsterklickar på formytan):
C:\Program Files
(x86)\Borland\Delphi4\Projects\P2\
— OK. Nu har vi en INSTANS — FormClick — med
vars hjälp vi kan ändra Programikonen. Vi gör det genom att lägga till följande
programkod i proceduren FormClick:
procedure TForm1.FormClick(Sender: TObject);
begin
Label1.Caption:=
ExtractFilePath(Application.ExeName);
ClipBoard.AsText:=
Label1.Caption;
Application.Icon.LoadFromFile(
ExtractFilePath(Application.ExeName)
+ 'ImageReady.ico'
end;
Elementär flytbildsteknik — grundexempel i DELPHI4
Resultatet blev:
”Form1” läggs ut som namn på
programfönstret automatiskt av DELPHI4 om inget annat anges;
— På FormCreate, eller när som helst
under körning, kan vi skriva in annat
enligt det enkla
Caption:=
'Annat';
För vi ska få behålla den ikonen, måste den
tas in (eller på annat sätt införlivas med programmet) varje gång vi startar
programmet.
— Det finns särskilda RESOURCE-files för
ändamålet. Men jag har ALDRIG använt dessa (på grund av vissa äventyrligheter),
och tänker inte heller uppmana någon att använda sådana (det bara förkrångligar och introducerar mera än
nödvändigt — men webben kanske har Delphientusiaster som [med glädje] talar om
hur den resursen ska användas).
— Min lösning är att lägga
ApplicationIcon.koden i ett särskilt startblock OnCreate (F11, Events,
OnCreate, Ctrl+Enter):
DELPHI4 lägger automatiskt till (tillsammans
med motsvarande procedurdeklaration i början av Unit1 under Type-blocket)
procedure TForm1.FormCreate(Sender: TObject);
begin
end;
Och vi skriver nu in
procedure TForm1.FormCreate(Sender: TObject);
var
S: string;
begin
S:= ExtractFilePath(Application.ExeName);
{Extract avslutas alltid automatiskt med en
BackSlash\.}
S:= S + 'ImageReady.ico';
if FileExists(S) then
Application.Icon.LoadFromFile(S);
end;
När vi kör programmet härifrån i
fortsättningen, kommer den valda ikonen alltid att framträda direkt med
programfönstret.
— OM ikonfilen händelsevis inte skulle
finnas på plats (if FileExists ...),
hoppas bara rutinen över och standardikonen kommer fram. Utan if-satsen uppstår
fel, eventuellt programavbrott, vilket vi ALDRIG ens vill se röken av: var
frikostig med IF:s och Excepts och TryFinallyEnd-block — eller bara ”if not ... then exit;”: programmet
går då bara ur aktuell procedur och ignorerar allt under den kommandoposten. Vi
kommer säkert dit mera.
Åter till Image123
Nu kommer vi till det verkligt Avancerade i
DELPHI4:
— Konsten att få Image1 att hänga med i
svängarna med programfönstrets storleksändring — alltså när man börjar dra i
fönsterkanterna eller kör
Alt+Space, Storleksändra.
— Jag vet inte hur mycken tid och möda jag
lyckades lägga ner på den den, ändra från början med (underbara Delphi1) innan
den fullständigt flimmerfria lösningen infann sig:
Om
inget annan lösning finns — kanhända någon Delphientusiast har den, men den är
i så fall här helt okänd:
HEMLIGHETEN ligger i att AVSTÄMMA Image1 med
en TBitMap — samt ”trixa” med en extra Procedur (CoFormCreate) tillsammans med
ordinära OnResize (F11, OnResize, Ctrl+Enter):
Så här ser min lösning ut:
Närmast under TypeBlocket, en separat införd
CoFormCreate. När den sedan skrivs längre ner i aktuellt verkställande kodblock
I EN UNIT SOM HAR EN ASSOCIERAD FORM (här Form1) måste den skrivas ”Procedure TForm1.CoFormCreate;”
Procedure
CoFormCreate;
procedure FormClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormResize(Sender: TObject);
Längre ner, här alla 4 procedurer:
Elementär flytbildsteknik — grundexempel i DELPHI4
procedure TForm1.FormClick(Sender:
TObject);
begin
Label1.Caption:=
ExtractFilePath(Application.ExeName);
ClipBoard.AsText:= Label1.Caption;
end;
Procedure
TForm1.CoFormCreate;
var
B: TBitMap;
begin
{AKTUELLA Image1MÅTTEN:}
Panel1.BoundsRect:= Rect(0,1,Width-8,Height-Panel2.Height-30);
Image1.BoundsRect:= Panel1.ClientRect;
{ANPASSNING:}
B:= TBitmap.Create;
try
B.Width:= Image1.Width;
B.Height:= Image1.Height;
Image1.Picture.Assign(B);
finally
B.Free;
end;{endTry}
{Annars grå yta
vid FormResize.}
end;{endCoFormCreate}
procedure
TForm1.FormCreate(Sender: TObject);
var
S: string;
begin
Image1.AutoSize:= False;
Image2.AutoSize:= True;
Image3.AutoSize:= True;
Label1.Color:= RGB(255,238,221);
Label1.Font.Color:= clPurple;
S:= ExtractFilePath(Application.ExeName);
{Extract avslutas alltid automatiskt med en BackSlash\.}
S:= S + 'ImageReady.ico';
if FileExists(S) then
Application.Icon.LoadFromFile(S);
Label1.Caption:= 'ProjectP2|Successfully
Initialized';
with Image1.Canvas do begin
Brush.Color:= clWhite;
FillRect(ClientRect);
end;
CoFormCreate;
end;{endFormCreate}
procedure
TForm1.FormResize(Sender: TObject);
begin
CoFormCreate;
end;{endFormResize}
Försök gärna själv att testa ovanstående med
modifikationer för att se om det ev. finns något alternativ att få Image1 med
Panel1 att hänga med SNYGGT & PERFEKT & FLIMMERFRITT (Alla
WindowsVersioner) då programfönstret storleksändras. I min referens (15 års
frekvent användning): Perfekt felfri funktion.
Label1 före insättning av ljusare
orange bakgrund och annan teckensnittsfärg.
Panel2 i botten följer med i
fönsterändringen och anpassar sig i längd DÄRFÖR att jag i Object Inspector på
Anchors [DUBBELKLICKA på +Anchorboxen,
undermenyer kommer fram med alla alternativen] Panel2 har markerat akRight = True: Det mått eller den proportion
som Panel2 har på Form1 vid designtillfället, kommer då att bevaras vid alla
fönsterändringar.
— Men nu finns ju inte längre någon
Form1-yta kvar tillgänglig att klicka på. Vi skulle ju ha den för olika
»experimentella ändamål». Ahh. Ve och fasa.
— Vi kan ordna den saken galant genom
Object Inspector på Panel2, nederst ovan:
— På Panel2 OnClick fäller vi via
Alt+PilNer fram de alternativ som finns där; FormClick. Vi väljer den.
— I fortsättningen är nu MusKlick på
Panel2 ASSOCIERAT MED musklick på Form1.
— Mera programkod tillkommer för att MED EN
IMPORTERAD bild till Image1 se till att den importen också bibehålls INTAKT med
motsvarande fönsterstorleksändringar.
— Vi kommer dit, strax.
— Men först måste vi sätta in den fina
BildPeken, särskilt utformad (sedan 14 år tillbaka) och anpassad för
precisionsarbeten,
eller i varje fall se till att det finns en
sådan tillgänglig.
— StandardKrysset i DELPHI4 (och andra
bildprogram) är sannerligen och nämligen, min mening, inte mycket attg hurra
för.
Sä här går det till att lägga till en egen
skärmpekare:
1. Den måste ha en egen ico.fil;
2. Den måste ges ett specifikt FastNamn
(constant);
3. Den måste laddas in som sådan genom en
speciell procedur:
Elementär flytbildsteknik — grundexempel i DELPHI4
I ProjektKatalogen (P2) lägger vi först in
en särskilt skapad bildskärmsmarkör
Ikonen för denna markör ändras i Windows sedan man besökt
den aktuella katalogen.
— Anledningen till det är här helt okänd. Ständigt nya
ikonbilder framträder.
— Den detaljen har dock ingen innebörd för filinnehållet.
Vi måste skriva en särskild procedur för det
ändamålet
(Först procedurdeklarationen längst upp
under TypeBlocket i sedvanlig ordning,
Procedure LoadCursors(S:
string; C: Integer)), och sedan aktuellt procedurkodblock i
ImplementationSektionens Procedurblock med ”TForm1.” längst fram efter
Procedure:
Procedure TForm1.LoadCursors(S: string;
C: Integer);
var
P: PChar;
I: Integer;{HCursor}
begin
if FileExists(S) then
begin
P:= nil;
try
P:= StrAlloc(Length(S)+1);
StrPCopy(P,S);
I:= LoadCursorFromFile(P);
Screen.Cursors[C]:= I;
finally
StrDispose(P);
end; {endTry}
end;{endIfFileExists}
end;{endLoadCursors}
samt deklarera den Globala
PekarNamnKonstanten (efter UsesBlocket i Unit1), här (MouseCursorNo1) MC1
const
{MomentaryCursor:}
MC1 = 5;
På FormCreate (längst ner efter
CoFormCreate;) skrivs sedan in:
if FileExists('Cursor1.cur')
then
begin
LoadCursors('Cursor1.cur',MC1)
Image1.Cursor:= MC1;
else
Label1.Color:= clAqua;
{Aqua
= himmelsKlarblått
Lime = HavsKlarGrönt
Finns den inte ges skrikande indikering.}
När vi sedan kör igång (F9) med allt det
ovan sagda, visar sig vår nya fina kryssmarkör bara när vi för den över Image1:
Annars den vanliga pilmarkören.
— Alternativa skärmpekare finns i många
olika versioner: WindowsSystem har en hel radda inte minst (avancerat)
animerade pekare (mus som äter ost, ros som växer fram, häst som springer,
etc.) och som man själv kan använda om man så önskar. Se floran i
Windows\Cursors.
— Delphis egen PekarBank (sätt markören i
ordet Cursor och tryck F1) beskriver (delvis) sammanhangen.
— För att testa Windows olika Pekare,
kopiera aktuell Pekare från Windows CursorKatalogen till ProjektKatalogewn
(P2), och testa den peken genom att låna kommandona som ovan med *=aktuella
PekarNamnet
if FileExists('*.cur') then begin
LoadCursors('Cursor1.cur',MC1)
Image1.Cursor:= MC1;
MEN: Var kommer nu
Bilden in i bilden?
MEN: Hur får vi nu in någon bild på Image1
utifrån?
— Tangenten
PrintScreen (PrtScn) skickar in allt
som syns på bildskärmen till Urklipp;
— Alt+
PrtScn
tar in aktuellt aktivt programfönster.
— OK. Men hur får vi ut (standardkommando sedan datorernas urtid är Ctrl+V)
något sådant från Urklipp på Image1?
Det rena RÅA kodKommandot som utför den uppgiften SKULLE se(r) ut så här
i DELPHI(4):
Image1.Picture.BitMap.Assign(Clipboard);
Elementär flytbildsteknik — grundexempel i DELPHI4
VI MÅSTE EMELLERTID VARA YTTERST FÖRSIKTIGA
HÄR: Urklipp har (mängder med) olika FORMAT.
Det är det första.
Det andra är:
— Vi ska INTE ta in urklippsbilden till
Image1, utan till Image2 — flytbildsInstansen — som ska läggas PÅ Image1 när vi
(här, strax) använder Ctrl+Piltangenter för att flytta omkring Importen — i
olika kombinationer man andra intagna bildobjekt.
— För ändamålet måste vi då aktivera (t.ex.)
en ny procedur OnKeyDown för Form1
— oftast den i särklass mest innehållsrika
proceduren i hela programmet, enligt min erfarenhet. Vi passar också på att
lägga till en ny Global Variabel ”ClipBoardImported” som talar om var vi är och
som sedan kan användas inifrån andra rutiner för säker hantering, SAMT en extra
rutin för att också RENSA (F2) Image1 och nollställa för nytt.
— Koden på KeyDown (Från Autoifyllt av DELPHI4 via F11, OnKeyDown, Ctrl+Enter som ger
procedurrubriken med begin och end) ser då ut så — för
resultatredovisningens del har jag för tillfället lagt in en Image1.Canvas.Draw som ritar ut InKlippet på
Image1 så att vi ser att allt fungerar, vi ska senare modifiera den delen och
göra den verkligt avancerad — samt en liten InfoBox
för fallet att ingen BitMap finns i Urklipp:
procedure TForm1.FormKeyDown(Sender: TObject; var Key:
Word;
Shift: TShiftState);
begin
if Shift=[ssCtrl] then
begin
case
Key of
{ClipToImage:}
Ord('V'): begin
if(Clipboard.HasFormat(CF_BITMAP))then begin
{BildMåtten för Image2&3 ges automatiskt
med nedanstående:}
Image2.Picture.LoadFromClipBoardFormat(
cf_BitMap,ClipBoard.GetAsHandle(cf_Bitmap),0);
Image3.Picture.LoadFromClipBoardFormat(
cf_BitMap,ClipBoard.GetAsHandle(cf_Bitmap),0);
Image1.Canvas.Draw(0,0,Image2.Picture.Bitmap);
Label1.Caption:=
'ImageFromClip OK';
ClipBoardImported:= True;
end
{endIfClipIsBitMap} else
begin
Application.MessageBox(
'Urklipp har ingen bitmap.'
,'ClipInfo',mb_OK+mb_Iconasterisk);
end;{endElseIfClipHasFormat}
end;{endCtrl+V}
end;{endCaseCtrl+Key}
end;{endIfCtrl}
if Shift=[] then
case
Key of
VK_F2: begin
with
Image1.Canvas do begin
Brush.Color:= clWhite;
FillRect(ClientRect);
ClipBoardImported:= False;
Label1.Caption:=
'Image1CLEAR';
end;{endWithIm1Canvas}
end;
end;{endCaseKeyNoShifts}
end;{endKeyDown}
Tangenterna
Ctrl+V
tar in bilden från Urklipp och ritar ut den från TopLeft på Image1;
Tangenten
F2
rensar bildytan för nytt och nollställer alla flaggor (ClipImported=False).
Exempel som tagit bilddump av textavsnittet
närmast ovan:
Efter F2:
Vi behöver aldrig oroa oss för ÄVENTYRLIGA
BILDMÅTT — större eller mindre än själva programfönstret går på ett ut: Windows
operativsystem sköter automatiskt om alla utanföravdelningar genom
Rektangelfunktionerna som ligger till grund för bildhanteringsfunktionerna.
— Vi SKULLE (här) kunna »passa på» att redan
nu lägga till en bekväm bildhanteringsfunktion:
— Tangent F5 (»uppdatera») får verkställa en
automatisk fönsterStorleksAnpassning till aktuellt intagen bild, om vi så vill.
— EMELLERTID. Innan vi gör det finns en mera
angelägen uppgift som innefattar samma nödvändiga programkod:
— Testa (nämligen) i vänsterexemplaret ovan
att ändra fönsterstorleken: bilden raderas. Ajö. Ajö.
Hur bevarar vi en redan intagen bild vid ändring av fönsterstorleken? Mycket viktig funktion.
Hela lösningen består i
en ORDNAD SAMMANSTÄLLNING av samtliga de flytt- och REKTANGELPARAMETERAR som krävs i
synkroniseringen mellan alla Image1-3 för att få flytbilden (Im2) att fungera:
alla insättningsvärden för flytbildens TopLeft (X0,Y0) och CopyRectSource och
CopyRectDestination måste finnas med.
Vi inför först för ändamålet
Globalvariablerna CopyRektanglar (TRect) CRd(estination) och CRs(ource), samt
InsättningsReferensPunkten LeftTop X0 och Y0 för flytbilder (vi kommer till den
mera ingående längre fram)
var
CRs,CRd: TRect;
X0,Y0:
Integer;
Elementär flytbildsteknik — grundexempel i DELPHI4
GlobalVariabler
och Konstanter ska skrivas närmast över TypeBlocket
— globala procedurer skrivs inuti TypeBlocket
Unit1 och utan ”TForm1.” och med inledande TForm1. till aktuella programproceduren i
Implementationsektionen = huvudblocket för alla programprocedurer; Se även
Delphihjälpen på Public and private declarations —
så att vi sammantaget får, i nuvarande skede
från början i Unit1:
unit Unit1;
{ProjectP2|8Sep2014
— Im123FromStart}
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, ClipBrd;
{GlobalVARIABLES|Constants
.......................................:}
const
{MomentaryCursor:}
MC1 = 5;
var
ClipBoardImported: Bool;
CRs,CRd: TRect;
X0,Y0: Integer;
{GlobalVARIABLES|Constants
........................................}
type
TForm1 = class(TForm)
Panel1: TPanel;
...
Anledningen att jag (här) sätter dessa
variabler som globala, inte lokala (i så fall
längre ner, närmast över själva sektionen med de verkställande procedurblocken)
är att jag av erfarenhet redan vet att OM — mer av regel än undantag, i
programmets VÄXANDE MED TIDEN — flera Unit:s kommer med i bilden, dessa behöver
använda Unit1-variablerna. Är dessa lokala går inte det.
Vi
gör nu först följande förberedande tillägg direkt vid ClipImport Ctrl+V —
Föregående Image1.Canvas.Draw är nu avställd och har ingen operativ funktion
längre:
//Image1.Canvas.Draw(0,0,Image2.Picture.Bitmap);
X0:=0; Y0:=0;
CRs:=Rect(0,0,Image2.Width,Image2.Height);
CRd:=CRs;
Image3.BoundsRect:=
Image2.BoundsRect;
Image3.Canvas.CopyMode:= cmSrcCopy;
Image3.Canvas.CopyRect(CRd,Image1.Canvas,CRs);
Image1.Canvas.CopyMode:= cmSrcCopy;
Image1.Canvas.CopyRect(CRd,Image2.Canvas,CRs);
Sista raden explicit ERSÄTTER föregående
tillfälliga resultatritning ”Image1.Canvas.Draw(0,0,Image2.Picture.Bitmap);”.
Vi kan bara bocka för = avställa den med två delstreck (DELPHI kursiverar och
mörkblåfärgar allt som inte är kod)
//Image... eller inom listparenteser
{Image ...} eller mellan två stjärnor inom
rundparenteser
(*Image ...*).
Vi
testar först att det utlovade fungerar:
IJÄss.
— OK. Vad är Hemligheten nudå med att få ha
min bild KVAR vid ändring av fönsterstorlek?
— Vi utvidgar föregående enkla kod på
FormResize
procedure
TForm1.FormResize(Sender: TObject);
begin
CoFormCreate;
end;{endFormResize}
Elementär flytbildsteknik — grundexempel i DELPHI4
till — du måste se det för att tro det:
Tryck PrtScn, Starta P2, Tryck
Ctrl+V, Bildskärmsdumpen kommer in TopLeft; tryck Alt+Space för att fälla ned
fönsterändringsmenyn, tryck S för Ändra storlek; pila markören till
HögerBotten; pila Höger Neråt;
— vartefter fönsterstorleken ökas, syns nu
alltmer av den intagna hela skärmbilden; Testa också Alt+Space med X för
Maximera: hela skärmdumpen syns — och tillbaka med Alt+Space och Enter för
ÅterställFönsterstorleken till föregående; inte ett enda flimmer; helt perfekt rent:
procedure TForm1.FormResize(Sender: TObject);
var
BR,CRsB,CRdB: Trect;
B: TBitmap;
begin
{FÖRBEREDER
intagning av Image1:}
B:= TBitmap.Create;
try
{BILDYTAN
TBitmap:}
BR:= BitmapRect(Image1.ClientRect,B);
{Lägger
in (föregående) Image1 på Bitmap'en:}
B.Assign(Image1.Picture.Graphic);
B.Canvas.CopyRect(CRd,Image3.Canvas,CRs);
{KÖR
NYA KOMPONENTPLACERINGAR:}
CoFormCreate;
{ANPASSAR
nya bildmått:}
CRsB:=Rect(0,0,Image2.Width,Image2.Height);
CRdB:=CRsB;
Image1.Canvas.CopyMode := cmSrcCopy;
Image3.Canvas.CopyRect(CRdB,Image1.Canvas,CRsB);
{Lägger
tillbaka Im1BeforeResize på nya Im1:}
Image1.Canvas.CopyRect(BR,B.Canvas,BR);
{Kopierar
FlytBildsRektangeln av Im1(=Im2-ytan med Im1-bilden) till Im3:}
Image3.Canvas.CopyRect(BR,B.Canvas,NewOR(BR,X0,Y0));
finally
B.Free;
end;
{Återställer
FlytBilden (Im2) på Im1:}
//Image1.Canvas.CopyMode
:= cmSrcAnd;
Image1.Canvas.CopyRect(CRd,Image2.Canvas,CRs);
end;{endFormResize}
Anledningen varför jag (här) skrivit ut
CopyMode:= cmSrcCopy är bara för att (i mina allmänna DELPHIrefrenser) SÄKRA sådan
kopieringsmod då programkoden i övrigt är (oerhört) välbesutten på många andra
typer: Standard från start är cmSrcCopy för en TImage eller TBitMap, men ändras
den för den komponenten eller instansen, kvarstår den inställningen också tills
ändrad igen.
— Hur de olika sätten fungerar får vi
se först när vi kan kombinera flera olika bildintag över, i eller genom
varandra.
— Vi ska strax försöka komma dit.
med (TypeBlocket, början Unit1: global som
kan nås av alla kommande Units) [Se BMR]
function BitMapRect(R:TRect; var B:TBitmap):TRect;
function NewOR(R: TRect; X,Y: integer): TRect;
som i ImplementationBlocket (aktuella
funktioner och procedurer i Unit1) har formen (+TForm1.)
{Skapar en ny, LeftTop-nollad, TRect som
bildytan för
en medsänd TBitmap:}
function TForm1.BitMapRect(R:TRect; var B:TBitmap):TRect;
begin
OffsetRect(R,-R.Left,-R.Top);
B.Width:= R.Right;
B.Height:= R.Bottom;
BitmapRect:= R;
end;
{Skapar en ny, flyttad, TRect från en
medsänd:}
function TForm1.NewOR(R: TRect; X,Y: integer): TRect;
begin
OffsetRect(R,X,Y);
NewOR:= R;
end;
Se särskilt beskrivningen i BMR.
Användbarheten i speciellt BitMapRect-funktionen är i min erfarenhet
utomordentligt omfattande i Delphiprogrammeringen: ytterst stor användbarhet.
Elementär flytbildsteknik — grundexempel i DELPHI4
Anpassning F5 — programfönstrets storlek anpassas till importerad bildstorlek
minsta: Image1.Height = 50p: WindowsSystem ser automatiskt till att MINST
avslutningsknappen finns med.
Form1ToppListen tar up 23pixels [eg.22, men vi har här lagt till en extra till Image1-kanten
av designskäl]:
Panel2 ytterligare + 2×3 pixel i rammarginalen för
programfönstret
Nu kan vi förverkliga fönsteranpassningen
till den importerade bildstorleken, om så önskemål finns.
— På FormKeyDown skriver vi då in koden (var iW,iH,x,y:
Integer; tillagt på FormKeyDown):
{ANPASSA EFTER IMPORT · 29Jun2011|9Sep2014:}
VK_F5: begin
if not ClipBoardImported
then
exit;
iW:= Image2.Width +2;
iH:= Image2.Height+2;
Panel1.Width:= iW;
Panel1.Height:= iH;
x:= iW + 6 +1;
if iH
> Panel2.Height
then
y:=
iH +
+ Panel2.Height
+ 23 + 6 +1
else
y:=
Panel2.Height
+ 50 + 6 +1;
if x
> Screen.Width then y:=Screen.Width;
if y > Screen.Height then y:=Screen.Height;
Width:= x;
Height:= y;
if BoundsRect.Right
> Screen.Width then
Left:= Left -
(BoundsRect.Right - Screen.Width);
if BoundsRect.Bottom
> Screen.Height then
Top:= Top
- (BoundsRect.Bottom - Screen.Height);
{Ta
om Im2Kopieringen:}
ClipBoard.Assign(Image2.Picture);
{RENSAallt:}
Key:= VK_F2;
FormKeyDown(Self,Key,[]);
{TaOmImporten:}
Key:= Ord('V');
FormKeyDown(Self,Key,[ssCtrl]);
end;{endF5}
Width
och Height utan den sedvanliga komponentspecificeringen behöver aldrig
göras om komponenten är Form1.
— Ovanstående kan skrivas med samma
funktion: Form1.Width:= och Form1.Height:= .. .
Direkt efter ClipImport med Ctrl+V:
Efter F5:
Perfekt.
— Jag har här lagt till en marginal
högerBotten på 1 pixel som visar Image1-bakgrunden, här vitt, och som ger lite
extra relief för mörkare bildImporter högerBotten.
Elementär flytbildsteknik — grundexempel i DELPHI4
Rutin för
BildExport — Ctrl+I
Vi vill nu också DIREK förverkliga EXPORT av
aktuell bildyta till Urklipp. Tillägget nedan ImageToClip
på FormKeyDown [Ctrl] — vi lägger till variabler lokalt i FormKeyDown vartefter
de behövs, här en B: TBitMap; och en R: TRect; :
var
B: TBitMap;
R: TRect;
iW,iH,x,y: Integer;
begin
if Shift=[ssCtrl] then
begin
case
Key of
{ImageToClip:}
Ord('I'): begin
B:= TBitmap.Create;
try
R:= Image1.ClientRect;
BitMapRect(R,B);
B.Canvas.CopyMode:= cmSrcCopy;
B.Canvas.CopyRect(R,Image1.Canvas,R);
Clipboard.Assign(B);
finally
B.Free;
end;{endTry}
Label1.Caption:= 'ImageToClip|OK';
end;{endCtrl+I}
{ClipToImage:}
Ord('V'): begin
if(Clipboard.HasFormat(CF_BITMAP))then begin
...
Vi testar resultatet genom att köra Ctrl+I
från en intagen bild Ctrl+V, minska fönsterstorleken, köra Ctrl+V och sedan F5
som bevisar att ursprunget återtas: ... IJjjj .. Äss. Stämmer bra det.
(Det händer ibland att det blir ... IJjjj .. ävlar — man missar ibland.
Bara att ta paus och försöka med BättreKod).
Indikering för intagen
bildstorlek och aktuella skärmkoordinater för Peken
DatorPilotens
MinimiPanel:
1. Färgen under Peken — en liten [topp]ruta som ALLTID visar
vilken färgen är under bildmarkörens HotSpot
2. Pekens ImageKoordinater X;Y — vi måste ha en OnMouseMove-rutin
för det
3. Bildmåtten efter import från Urklipp — vi behöver hur som
helst en extra panel under programfönstrets topplist
Innan vi nu går vidare måste vi ha
PILOTCERTIFIERANDE BASINFO — paneldata — som talar om för
oss var vi är i framstegen:
0. En liten ruta som visar aktuell FÄRG
under peken — mycket användbart (enkla färgval, bl.a. vid ritning)
1. En Display som visar ImportMåtten från
bilden i Urklipp;
2. En allmän Peka(X;Y) som visar var
pekarKrysset befinner sig på Image1, bildytan som är vårt arbetsbord.
Jag
sa ju det:
— DELPHI4 i Windows7 är Kanon.
Form1 Project P2 ovan efter import av en
enklare RGB-palett, samt insatta 3 nya paneler: Panel3 för färgvisning under
Peken, Panel4 för XY-koordinaterna och Panel5 för Importens bildmått. Nöj dig
inte med mindre.
— KODEN på Image1MouseMove (Image1, Object
Inspector, OnMouseMove, Ctrl+Enter):
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Panel4.Caption:=
IntToStr(X) + ';' +
IntToStr(Y);
V:=
Image1.Canvas.Pixels[X,Y];
Panel3.Color:=
V;
{Eliminerar marginellt flicker:}
Panel3.Refresh;
end;
Variabeln V: TColor Global; samt infogat på
ClipToImage FormKeyDown Ctrl+V för Panel5:
Panel5.Caption:=
IntToStr(Image2.Width)+';'+
IntToStr(Image2.Height);{}
end;
Elementär flytbildsteknik — grundexempel i DELPHI4
och på F2 efter ClearIm1,
Panel5.Caption:=
'Dimensions';
så att inga siffror »ligger och skräpar»
sedan sista Importen raderats.
Inrättning av
markörflyttning med piltangenter och acceleratorer (CursAcc)
Innan vi går vidare måste vi nu koppla ihop
det (snygga) ovan med en EXAKT PekarNavigering — inte minst för ändamålet att
KUNNA pricka in exakta färgmakeringar i olika tillval (färgenUnderPeken), utan
mera allmänt för exakta bildarbeten med exakta passningar och positioner: det hänger på pixeln. Utan det kan vi lika gärna kasta ut
datorn direkt: värdelöst SKRÄP.
— Tänk KLASSISKT:
— Vi som är uppfödda med Penna, Linjal,
Passare som GRUNDBLOCK, vill ALLTID ha MINST »en fungerande ritpenna i
bröstfickan»: räta linjer, enkla figurer PÅ STUBINEN.
— Vi ska återkomma till den detaljen, strax.
Betingelser
för att realisera funktionerna MARKÖRFLYTTNING:
1. FormKeyUp måste introduceras
för att nollställa den allt växande heltalsvariabeln CursAcc efter Piltangerna (KeyDown), annars kommer
Peken att accelerera iväg för evigt med allt högre hastigheter och allt större
steglängder.
2. En separat MarkörMove-procedur måste inrättas som styr funktionen via
KeyDown-tangenterna PilUpNerVäHö.
3. En särskild procedur som uppdaterar
Image1-Måtten — kopplar till Rezise:
Procedure TForm1.SetSCRIm1Rect;
begin
{GENERELLT
Image1RectDimensions}
SCRIm1.TopLeft:=Image1.ClientOrigin;
SCRIm1.BottomRight:= Point(
Image1.ClientOrigin.X +
Image1.ClientWidth + 1,
Image1.ClientOrigin.Y +
Image1.ClientHeight + 1 );
end;{endSetSCRIm1Rect}
Proceduren ovan används (så småningom ju mer avancerat funktionerna flätas
samman) av flera instanser i flytbildshanteringen, och gör sig därför
bäst som fristående, global, procedur som kan användas av alla.
— Test visar att FormCreate ALLTID genomgår
Resize-blocket, i vilket fall, och vi kan därför förlägga ett separat anrop
till Image1UppdateringsRutinen ovan DIREKT i FormResize (sist: SetSCRIm1Rect;): Därmed ges Image1-dimensionerna
direkt i SCRIm1-rektangeln från programstart: och sedan vidare med varje
storleksändring av programfönstret;
4. Fyra separat BEKVÄMA positionerare behövs
(ibland, bekvämt) för att sätta peken i endera bildhörnet; vi använder här
tangenterna HOME(LeftTop), END(LeftBottom), PageUp(RightTop) och
PageDown(RightBottom) för det;
— KODEN i DELPHI4 för att realisera
ovanstående:
NyaGlobalaVariabler:
SCRIm1:
TRect; {Image1Rectangle}
CursAcc: Integer; {MarkörAcceleratorn}
MarkMoveProceduren, Global (TForm1. i
TypeBlocket, utan TForm1. i procedurblocket) — Programexekveringen skickas hit
från KeyDown om rena piltangenter utan Ctrl och Shift:
{MARKÖRFLYTTNINGEN|orig.Rot1:}
Procedure TForm1.MarkMove(Key:
word);
var
P:
TPoint;
X,Y,W,H: Integer;
begin
with Image1 do
begin
X:= ClientOrigin.X;
Y:= ClientOrigin.Y;
W:= ClientWidth;
H:= ClientHeight;
end;
GetCursorPos(P);
{DIREKTREFERENS
I HELSKÄRMSKOORDINATER:}
if
(PtInRect(SCRIm1,P)=True) then begin
case
Key of
VK_RIGHT: begin
if P.X+CursAcc<X+W then begin
P.X:= P.X + CursAcc;
Inc(CursAcc);
end else CursAcc:= X + W - P.X - 1;
end;{endRight}
VK_LEFT: begin if P.X-CursAcc+1>X then begin
P.X:= P.X - CursAcc;
Inc(CursAcc);
end else CursAcc:= P.X - X;
end;{endLeft}
VK_UP: begin if P.Y-CursAcc+1>Y then begin
P.Y:= P.Y - CursAcc; Inc(CursAcc);
end else CursAcc:= P.Y - Y;
end;{endUp}
VK_DOWN: begin if P.Y+CursAcc<Y+H then begin
P.Y:= P.Y + CursAcc;
Inc(CursAcc);
end else CursAcc:= Y + H - P.Y - 1;
end;{endDown}
end;{endCaseKey}
{VERKSTÄLLER:}
SetCursorPos(P.X,P.Y);
end;{endIfPtInRect}
end;{endProcedureTForm1.MarkMove}
{NOTERING.
1
För att markörflyttningen ska fungera måste en särskild
rutin för bildkoordinaternas uppdatering
(via SCRIm1)
finnas på den särskilda proceduren vid
OnPaint|Resize.
2.
CursAcc måste återställas till stegning för 1 pixel
på FormKeyUp, annars steppas allt större
distanser i
varje steg.}
Elementär flytbildsteknik — grundexempel i DELPHI4
FUNKTION:
När vi trycker ner en piltangent, här
PilHöger, och håller tangenten nedtryckt, ackumuleras flyttstegningen
successivt med tiden (värdet i CursAcc ökar), och Peken drar iväg allt snabbare
över bildskärmen. När den når fönsterkanten, retarderar den (snabbt) och
stannar.
— Det gör det LÄTT för oss att SNABBT
hitta/nå EXAKTA positioner — med en kombination av MusRörelse och Piltangenter.
— Koden på KeyDown för HomeEndPageUpDown,
Peken i endera bildhörnet:
VK_PRIOR: begin
{PageUp | HögerÖvre:}
SetCursorPos(Image1.ClientOrigin.X+Image1.ClientWidth-1,
Image1.ClientOrigin.Y);
exit;
end;
VK_NEXT: begin {PageDown | HögerNedre:}
SetCursorPos(Image1.ClientOrigin.X+Image1.ClientWidth-1,
Image1.ClientOrigin.Y+Image1.ClientHeight-1);
exit;
end;
VK_END: begin {PageDown |
VänsterNedre:}
SetCursorPos(Image1.ClientOrigin.X,
Image1.ClientOrigin.Y+Image1.ClientHeight-1);
exit;
end;
VK_HOME: begin {PageDown |
VänsterÖvre:}
SetCursorPos(Image1.ClientOrigin.X,
Image1.ClientOrigin.Y);
exit;
end;
Ctrl+V Importera
Bild FrånUrklipp
Ctrl+I Exportera
HelaBildytan TillUrklipp
F2 Rensa
Bildytan
F5 Anpassa
programfönstret till ImporteradBild
Piltangent Fri,
accelererad markörflyttning, eller exakt enskild pixelstegning
Home Peken
LeftTop
End Peken
LeftDown
PageUp Peken
RightTop
PageDown Peken
RightDown
Jag har också lagt in VK_HOME-kommandot på
FormCreate så att programförnstret alltid startar upp med peken där.
(Detta
grepp är mindre lämpligt med hänsyn till klickutflykter för andra
programfönster på bildskärmen. Jag har t.v. bockat av den delen då vi i vilket
fall bara behöver trycka HOME för att få se peken LeftTop med aktivt P2).
— För Programnamnlisten, se Caption.
Flytbilden, Tabell
Målet nått 9Sep2014 — [det tog 5 dagar att sammanställa]
Flytbilden
Nu är vi klara för att förverkliga drömmen:
— Importerade UrklippsBilder ska kunna
flyttas på, över, i och genom bildytan Im1 efter de olika ELEMENTÄRA »transportsätten».
— Vi kallar här ett sådan flyttbart
bildobjekt för en flytbild.
Vi
studerar det.
Ctrl+Pilar flyttar
UrklippsImporter Ctrl+V
över bildytan i FLYTSTEG om Ctrl+NumPad|1
2 3 5 9 antal pixels 1 5 20 halvsida(höjd) helsida(höjd);
— Från programstart är flytintervallet
inställt på 20 pixels (min erfarenhet, bästa
kompromissen för alla fall i grov flyttning).
— Intaget ovan från hel skärmbild
(PrtScn), textområdet har flyttats så att bara text syns, sedan en separat
ClipExport från annat program med RGB-paletten, denna in via Ctrl+V sedan
flyttad med Ctrl+PilHöger i CopyMode standard cmSrcCopy: Flytbildens hela bildrektangel ligger
täckande underlaget. Vi ska senare
se hur också samtliga övriga flytbildsSÄTT kan förverkligas via
DELPHI4-KOD. Den delen kräver att vi måste genomgå alla flytbildssätten i ett
gemensamt block (s.k. FLYTBILDSFLAGGOR: dessa
styr tillvalen och kräver extra PilotPaneler i DISPLAY för vår Info).
— Genom speciell kodning [vidare nedan:
MarkMove(0)], uppdateras
här även färgrutan nedrevänster som visar färgen under peken då flytbildens
färger passerar i flytten — utan någon MouseMove (»It’sMacig»).
Elementär flytbildsteknik — grundexempel i DELPHI4
Koden i DELPHI4 som slutligen förverkligar
flytbilden som ovan ser ut så här — KeyDown i Ctrl-blocket med tillagd
globalvariabel
ArrowStep: Integer; 20pixels från
programstart [ASMM ännu bara = 1; –1 ger
omvända flytriktningar]:
VK_LEFT,VK_UP,VK_RIGHT,VK_DOWN:
begin
{ASMM·piltangentsvändare|ArrowSwapperMoveMore|,
ArrowStep·1,5,20 pixels:}
{PREPARE
SourceDestinationRECTANGELS:}
CRs:=Bounds(0,0,Image2.Width,Image2.Height);
CRd:=Bounds(X0,Y0,Image2.Width,Image2.Height);
{ÅTERSTÄLLER
Image1|Lägger ut föregående InKopia i Im3:}
Image1.Canvas.CopyMode:=
cmSrcCopy;
{cmSrcAnd här = avtryck
efter varje flyttning.}
Image1.Canvas.CopyRect(CRd,Image3.Canvas,CRs);
{VERKSTÄLL
FLYTSTEG:}
case Key
of
VK_LEFT: X0:=X0-ArrowStep*ASMM;
VK_RIGHT: X0:=X0+ArrowStep*ASMM;
VK_UP: Y0:=Y0-ArrowStep*ASMM;
VK_DOWN: Y0:=Y0+ArrowStep*ASMM;
end;{endCaseKey}
{UPPDATERAR
Destinationskoordinaterna:}
CRd:=Bounds(X0,Y0,Image2.Width,Image2.Height);
{SPARAR
UNDAN originalytan, CRd/s omvända:}
Image3.Canvas.CopyRect(CRs,Image1.Canvas,CRd);
{FLYTBILDEN|Im2
LÄGGS PÅ NY PLATS:}
Image1.Canvas.CopyRect(CRd,Image2.Canvas,CRs);
MarkMove(0);
{MarkMove(0)|AktiverarMouseMove via en
DoNothing.
Därmed uppdateras Färgrutan, samt
övriga data
som (ev.) finns på Im1 i anslutning
till olika
PekRörelser/Flytbilder.}
exit;
end;{endIf Ctrl+Arrows}
Förstummande galant.
— GRUNDJOBBET till allt det ovan — nu använt
under mer än 15 år — gjordes (faktiskt) på 16 bitars Delphi1: värdens
underbaraste MasterProgram (slutet av 1990-talet, Windows 95), just på grund av
dess NÄRA anslutning till MIKROPROCESSORN: 16-bitars programmering som tvingade
mig att lösa problemen med sömlösa övergångar i BitMaps med gränsblock om
65535Byte — och som ibland förorsakade kommersiella WindowsKrascher för
Microsofts egna programvaror (MsWorks Utskrifter) [som bara bevisade hur
marknaden SLARVAR med KOD (Microsoft kan ännu i denna dag inte lösa ELEMENTÄRA
programuppgifter: jämför SökMotorerna på datorns hårddisk: rena katastrofen i
Microsoft)].
Enkelt ritverktyg tillagt. MusHögerNer.
Alltid tillgängligt. MED piltangenter som Kan Accelerera. Rakt.
Följande tillägg på Image1MouseMove ger
ovanstående enkla MANUELLA MED ACCELERERANDE PILTANGENTESFUNKTIONEN INKLUDERAD
pennritningsfunktion: Höger musknapp ner
— när som helst. AnyTimeYouWant:
var
C1: Integer;
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
...
{DRAW SIMPLE
LINES|MouseRight:}
if GetKeyState(VK_RBUTTON)<=-127
then
begin
with Image1.Canvas
do
begin
if C1=1 then
begin
Pen.Style:= psSolid;
Pen.Color:= 0;
Pen.Width:= 1;
LineTo(X,Y);
end else
begin
MoveTo(X,Y);
C1:= 1;
exit;
end;
end;{endWithIm1Canvas}
end{endIfMouseRight}else
C1:= 0;
Separata variabler (var) som deklareras omedelbart före en procedur ses av
(bara) den proceduren (och alla efterföljande) som en »global» variabel. Sätter
vi C1 som en variabel i själva proceduren, fungerar inte koden därför att
värdet på C1 då förloras med programmets exekverande procedurutgång [DELPHI4 nollställer i allmänhet alla
procedurutanförstående variabler från programstart — men man bör inte ta det
för säkert. Säkert är dock att alla reguljärt globalt deklarerade variabler
ALLTID nollas från programstart av DELPHI4. Se vidare i DelphiHjälpen (Declaring
variables)].
Elementär flytbildsteknik — grundexempel i DELPHI4
Ctrl+M Reverserar flytriktningen via
piltangenterna Move|More:
— M-panelen ovan (Panel6) har lagts till med
koden nedan på Ctrl-FormKeyDown-blocket
{ArrowsSwapMoveMore|ASMM:}
Ord('M'): begin
ASMM:= - ASMM;
if
ASMM=1 then
Panel6.BevelOuter:= bvRaised
else
Panel6.BevelOuter:=
bvLowered;
end;
ASMM=1 från programstart: flyttning av
importbilder från urklipp lämpat för bilder mindre än fönsterstorleken: MOVE.
— Större bilder vill man ser mer av MED
SAMMA TANGENT som då uppför sig rebelliskt »åt andra hållet».
— Ett tryck på Ctrl+M ändrar den situation
och ger det man vill ha: showmeMORE.
— Notera att ASMM-värdet kopplar (se längre
upp) bildflyttningens X0|Y0-ArrowStep*ASMM.
FleraÖppnaFönster, MultiWin — 10Sep2014
Flera öppna
programfönster
Vi kan öppna i
princip hur många programfönster som helst av typen som skapas av
DELPHI4-Windowsprogram. Enda problemet är att vi måste utforma något SÄTT att
dels skilja dem åt — här genom numrering — och dels kunna identifiera vad som
gäller speciellt vid programavslutning, om uppgiften gäller att spara undan
data som man sedan vill kunna återuppta vid en senare programstart. Här är
DelphiKoden för det:
Öppnas n stycken fönster och ett i
högen klickas av, kommer nästa programfönster som startas upp att ta platsen
för det fönster som klickats av med lägsta ordningsnummer: inga tomrum tillåts.
Koden nedan (testat
speciellt på det krångliga vildsinta operativsystemet Windows Vista — tenderar
att gruppera program med samma ursprung)
har
[med
nuvarande 10Sep2014 viss reservation för WindowsVista: min Vistadator har
slutat fungera efter 7 år, och den delen kan här inte testas längre med den
numera modifierade Delphikoden nedan
[avställt {(NumWin=0)and} i if{(NumWin=0)and}(MultiWin=False)then]
testats upp till Windows 7 och har visat sig
fungera galant:
1. Vi behöver först en särskild procedur som
skannar av vilka öppna Windowsprogram som finns (GlobalProceduren deklareras
som vanligt i TypeBlocket överst i Unit1 som nedan men utan TForm1.), NumWin: Integer; är global
(deklareras efter UsesBlocket, Unit1):
Procedure TForm1.CheckMultiWin;
var
T:
TStringList;
S:
string;
N,Z,X,C: Integer;
PC:
PChar;
begin
T:= TStringList.Create; T.Sorted:=
True;
NumWin:= 0; C:= 0; Z:= 1;
PC:= StrAlloc(51);
X:= GetWindow(Form1.Handle,GW_HwndFirst);
try
{SKANNA
AV ALLA ÖPPNA WINDOWSFÖNSTER:}
repeat
Inc(C); X:=
GetWindow(X,GW_HwndNext);
GetWindowText(X,PC,50);
S:= StrPas(PC);
{INGEN
FRÅN FÖRSTA:}
if Pos('
P2 | Form1 ',S)>0 then
begin
Inc(NumWin);
{Caption:= ' P2 | Form1 | — ' }
{ 123456789012345678 :}
Delete(S,1,18);
T.Add(S);
{REDAN
BEFINTLIGA FÖNSTERNUMMER N-1:}
N:= StrToInt(S) +1;
{FYLLER
PÅ MED +1 EFTER SENAST HÖGSTA VÄRDE:}
if N>Z
then
Z:= N;
end;
until(X=0)or(C>=1000);
{ClipBoard.AsText:= IntToStr(C)|Test visar C=242 vid X=0.}
{SÄKRA
FÖRST RAKA NUMRERINGEN|Om inget annat gäller:}
NumWin:= Z;
{KOLLA
OM LUCKOR FINNS I NUMRERINGEN|OmSå, ta närmast lägsta lediga:}
for
N:= 0 to T.Count-1 do
if StrToInt(T[N])<>
N+1 then
begin
NumWin:= N+1;
Break;
end;
finally
StrDispose(PC);
T.Free;
end;
if NumWin-1>1
then
MultiWin:= True else MultiWin:=False;
{Numreringen för sista fönstret kommer
att sluta på NumWin=2:
— Första sökningen på
GetWindowText(X,PC,50) ger noll eftersom första
programfönstret ännu inte finns. Då
sedan (sista) programmet avslutas,
finns redan en förekomst, och som
räknas upp internt i ifPos-blocket.}
end;{endCheckMultiWin}
På FormCreate ersätter vi sedan föregående
enkla ”Caption:= ' P2 | Form1” med det
mera avancerade
{SEPARATA
FÖNSTERNAMN FÖR FLERA ÖPPNADE PROGRAMFÖNSTER:}
CheckMultiWin;
Caption:= ' P2 | Form1 | — ' +
IntToStr(NumWin);
{DELPHI4Test2014|4Nov2013|10Sep2014|P2.}
{WindowsVista
KAN försöka stänga flera (9+) öppna fönster som GRUPP — vilket resulterar i
FEL:
CannotCreate
DATA.txt-file på FormClose: Bara ETT programfönster åt gången får stängas:
FÖRKLARING:
— Om var och en av nst öppnade P2 försöker
spara data vid Close för åtkomst vid nästa öppning,
är det givet att »systemet pajar».
LÖSNING:|4Nov2013 — se tillägget
MultiWin-flaggan, FormClose. TestatOK till 12st. Hela gruppen stänger utan
protest.}
{Forts.
FormClose.}
Left:= (Screen.Width - Width)
div 2 + (NumWin-1)*20;
Top:=
(Screen.Height - Height) div 2 + (NumWin-1)*20;
tillsammans med en GlobalVariabel MultiWin: Bool;.
— Vi lägger sedan till en FormClose via
Object Inspector Form1, F11, OnClose, Ctrl+Enter: Mellan begin-end skriver vi
in, samt lägger till variabler:
procedure TForm1.FormClose(Sender: TObject; var Action:
TCloseAction);
var
S: string;
TS:
TStringList;
begin
exit;
{REKOMMENDERAT
FÖR DEN SOM VILL FORTSÄTTA PROGRAMUPPGIFTEN SJÄLV:}
{Använd följande rutinblock — ge
alternativt namn — om uppgiften
är att spara undan programdata som ska
användas nästa gång programmet
startar upp — typ använda färger eller
värden eller text eller vad
det kan vara:}
{SEPARAT
PROCEDUR — används på FormCreate och FormClose:}
CheckMultiWin;
{Här
exekveras TestVillkoret:}
{Se
MultiWin på FormCreate|Endast sista CloseFönstret berörs:}
if(MultiWin=False)then
begin
{SaveDATA:}
TS:= TStringList.Create;
try
SetCurrentDirectory('C:\');
S:= ExtractFilePath(Application.ExeName);
TS.Add('Data1');
TS.Add('Data2');
TS.Add('Data3');
finally
TS.SaveToFile(S+'DATA.txt');
TS.Free;
end;
end;{endIfOnlyOneLastOpenProgramWindow}
end;{endFormClose}
Modifiera, utvidga eller ändra
TS.Add-posterna efter egna önskemål.
— Bockas exit;-raden av (//exit;
eller {exit;}) kommer en ny fil DTA.txt att läggas in i projektkatalogen
med raderna.
Data1
Data2
Data3
Flytsätten, MoveCOPY och MoveAND
Elementär flytbildsteknik — grundexempel i DELPHI4
Flytbildens olika
transportsätt över bildytan
— Ovanstående resultat för flytbilden
motsvarar MoveCOPY: flytbildens totala UrklippsRektangel flyttas över den
underliggande bildytan som en enskild fast yta.
— Vi inför nu först anpassad DELPHIkod för
att också få den andra ELEMENTÄRA flytbildsmaken med:
— MoveAND: flytbildens pixels AND-as
tillsammans med den underliggande bildens pixels:
1. Vi inför först två nya paneler, Panel7(C)
och Panel 8(W)
C: upphöjd,
Indikerar MoveCOPY = fristående flytbildsobjekt med separata pixelkanaler
nedsänkt,
Indikerar MoveAND = kombinerar pixels hos underlag OCH flytbild
tangent C togglar=växlar mellan dessa — vi återkommer
till W (SkipWhite)
2. Vi anpassar kod med tre nya globala
variabler
CopMod: TCopyMode;
FleetState,SkipWhite: Integer;
och en särskild global procedur
för uppdatering UpdateMergeFlags,
Procedure TForm1.UpdateMergeFlags;
begin
if FleetState=0 then
{MoveAND:}
Panel7.BevelOuter:= bvLowered else
{MoveCOPY:}
Panel7.BevelOuter:= bvRaised;
if SkipWhite=-1 then
Panel8.BevelOuter:= bvRaised else
Panel8.BevelOuter:= bvLowered;
{Om
MoveANDgäller har SkipWhite ingen funktion:}
if FleetState=0 then
Panel8.BevelOuter:= bvNone;
{}
end;
med motsvarande tangentkommandon på
FormKeyDown, blocket utan skifttangenter, CaseKeyBlocket,
{MoveCOPY|AND|10Sep2014:}
Ord('C'): begin
if
FleetState=0 then
{MoveCOPY:} FleetState:= 1 else
{MoveAND:} FleetState:= 0;
UpdateMergeFlags;
end;{endC|A}
{SkipWHITE|10Sep2014:}
Ord('W'): begin
SkipWhite:= -SkipWhite;
UpdateMergeFlags;
{ImmediateKeyResponse:}
{I:=ArrowStep;
ArrowStep:=0;
W:= VK_DOWN;
FormKeyDown(Self,W,[ssCtrl]);
ArrowStep:=I;{}
end;
med motsvarande StartVärden på FormCreate,
{MoveCOPY|TakeWhite:}
FleetState:= 1;
SkipWhite:= 1;
och VERSKTÄLLANDE på BildFlyttningen,
FormKeyDown, här de nya posterna markerade med orange och gult,
VK_LEFT,VK_UP,VK_RIGHT,VK_DOWN:
begin
if FleetState=0
then CopMod:=cmSrcAnd else CopMod:=cmSrcCopy;
{ASMM·piltangentsvändare|ArrowSwapperMoveMore|,
ArrowStep·1,5,20 pixels:}
{PREPARE
SourceDestinationRECTANGELS:}
CRs:=Bounds(0,0,Image2.Width,Image2.Height);
CRd:=Bounds(X0,Y0,Image2.Width,Image2.Height);
{ÅTERSTÄLLER
Image1|Lägger ut föregående InKopia i Im3:}
Image1.Canvas.CopyMode :=
cmSrcCopy;
{cmSrcAnd här = avtryck
efter varje flyttning.}
Image1.Canvas.CopyRect(CRd,Image3.Canvas,CRs);
{VERKSTÄLL
FLYTSTEG:}
case
Key of
VK_LEFT: X0:=X0-ArrowStep*ASMM;
VK_RIGHT: X0:=X0+ArrowStep*ASMM;
VK_UP: Y0:=Y0-ArrowStep*ASMM;
VK_DOWN: Y0:=Y0+ArrowStep*ASMM;
end;{endCaseKey}
{UPPDATERAR
Destinationskoordinaterna:}
CRd:=Bounds(X0,Y0,Image2.Width,Image2.Height);
{SPARAR
UNDAN originalytan, CRd/s omvända:}
Image3.Canvas.CopyRect(CRs,Image1.Canvas,CRd);
{FLYTBILDEN|Im2
LÄGGS PÅ NY PLATS:}
Image1.Canvas.CopyMode:= CopMod;
Image1.Canvas.CopyRect(CRd,Image2.Canvas,CRs);
MarkMove(0);
{MarkMove(0)|AktiverarMouseMove via en DoNothing.
Därmed uppdateras Färgrutan, samt
övriga data
som (ev.) finns på Im1 i anslutning
till olika
PekRörelser/Flytbilder.}
exit;
end;{endIf Ctrl+Arrows}
med resultatet (skärmdump på texten ovan,
sedan separat intag av RGB-palett och Tangent C som växlar till MoveAND):
Resultatet talar för sig självt: MoveAND
låter oss se underlaget genom flytbildsobjektet i kombination med flytbildens
pixels.
Trycker vi C igen återgår flytsättet till
MoveCOPY:
Det finns (nu) EGENTLIGEN bara ett flytsätt
kvar att beskriva — frånsett möjligheten att flytta objekten TONANDE genom
varandra, vi kommer strax dit också: MoveMedSkipWHITE.
— En del (»elementära») ritprogram (Paint,
Windows 7) kallar det flytsättet för »transparent», då det i själva verket
»bara» betyder SKIPPA BAKGRUNDSFÄRGEN, mestadels vitt.
— När vi kopierar bildobjekt sker det
ALLTYID via en omgivande begränsningsrektangel. Men den bildytan innehåller inte
alltid heltäckande färger. Ofta använder vi stora bildytor med bara några få
färger, typ cirklar, grafiska element generellt, som vi vill kunna passa in
enbart på kurvformens figur. Det sättet kallas här generellt flytta med
SkipWhite (eller annan bakgrundsfärg).
Omgående
tangentrespons
För att få OMEDELBAR TANGENTRESPONS vid
tryckning på tangent C — växlingen till nytt MoveSÄTT verkställs och syns
omgående UTAN FLYTT — formulerar vi ett INTERNT MAKRO på UpdateMergeFlags sist
(variablerna I: Integer; W: Word;):
I:=ArrowStep;
ArrowStep:=0;
W:= VK_DOWN;
FormKeyDown(Self,W,[ssCtrl]);
ArrowStep:=I;
Förklaring:
— FÖRST spar vi undan vad aktuellt som finns
i ArrowStep i I;
— Sedan simulerar vi en flytbildsflyttning
via tangenterna Ctrl+PilNer (vilkensom) och vilken rutin finns på FormKeyDown:
— Genom att vi påtvingar ArrowStep=0 sker
ingen bildflyttning, bara en kopiering i repris, men nu i aktuell form.
— Sist lämnar vi tillbaka lånet. Perfekt
funktion.
HELP
Vänsterklick på den
här introbilden öppnar en htm-fil (i datorns förinställda webbläsare) som
beskriver programinnehållet, om ej redan bekant.
Ta bort den här
introbilden genom att trycka på valfri tangent.:
— JäMFÖR
MicrosoftSWEDEN:
DU TAR BORT DEN HÄR
BILDEN GENOM ATT DU SÄTTER IGÅNG MED ATT BÖRJA TRYCKA PÅ VALFRI TANGENT.
— DU gör. DU tar.
Och sen när DU har gjort det, KAN DU ta och göra det. Sen kan du göra det där
andra också.
— Imperialismens
Slavparadis på Jorden.
— MicrosoftSWEDEN
(maktkåta översättarproffs) har möjligen aldrig reflekterat över att engelskans
YOU i allmänhet i beskrivningar betyder det generaliserade MAN gör det och det,
YOU do that and that, inte DU gör det och det. Det senare är OFÖRSKÄMT. Byt
företag nu. Snälla.
— OM MAN INTE DIREKT
har avancerat till FÖRSTÅENDE FÖRKLARANDE GUD, håller man sig städat och snyggt
på nivån RekommenderaT, enligt erfarenhet: MAN kan göra si och så, och om det
gäller att REALISERA det och det: man trycker först på den och sedan den, sedan
kan man fortsätta ... . DU är reserverat för PERSONEN, det personliga valet,
och det har ingen SOM INTE ÄR INBJUDEN med att göra.
Elementär flytbildsteknik — grundexempel i DELPHI4
MoveSkipWHITE
— Dramatiskt:
— Ett AccessViolationFEL envisades tills nyligen att återkomma — till
synes kaotiskt — på MoveSkipWHITE-proceduren.
— Upprepade observationer visade strax:
— AcVi-avbrottet uppkommer om, och endast
då, intagsbilden är större än ELLER LIKA MED bildskärmsbilden (Screen.Width
resp. Screen.Height).
— När en extra marginal på minus en pixel lades till i ScanLine-blocket,
upphörde felet.
— Funktionen MoveSkipWhite har nyligen
testats med intag av STORA bilder (från digitalkamera) och fungerar utan
avbrott.
— Notera dock att
STORA bilder med MoveSkipWhite tar MÄRKBART lång tid: flytbilden kräver för
varje ny position runt 1/2 sekund för att uppdateras.
BaraFörVITT
I föregående kod
{FLYTBILDEN|Im2
LÄGGS PÅ NY PLATS:}
Image1.Canvas.CopyMode:= CopMod;
Image1.Canvas.CopyRect(CRd,Image2.Canvas,CRs);
finns bara en enda rad vi behöver
koncentrera oss på för att förverkliga MoveSkipWHITE: den sista ovan.
Hur görs det?
Vi
ska utforma en separat BitMap (B), lägga flytbilden Im2 på denna, tilldela B
egenskapen Transparent=True, anställa vilken TransparentFärgen ska vara, och
sedan helt enkelt använda Image1.Canvas.Draw(X0,Y0,B) direkt istället för
ovanstående CopyRect:
if{(CopMod=cmSrcCopy)and}(SkipWhite=-1)then begin
B:=
TBitMap.Create;
try
B.Assign(Image2.Picture);
B.Transparent:= True;
B.TransparentColor:= clWhite;
Image1.Canvas.Draw(X0,Y0,B);
finally
B.Free;
end;
end
else
Image1.Canvas.CopyRect(CRd,Image2.Canvas,CRs);
Med
CopMod-parentesen:
BARA då MoveCOPY gäller får SkipWHITE
mening:
— I flytläge MoveAND har SkipWHITE
ingen innebörd — om vi ska vara konsekventa mot AND.
Utan
CopMod-parentesen:
SkipWHITE ignorerar MoveAND:
— I flytläge överrider SkipWHITE
tillfälligt ett MoveAND med MoveCOPY.
— Detta senare alternativ är EGENTLIGEN
att föredra [ofta förekommande rutiner, man
slipper trycka på två tangenter för att få SkipWhite från ett MoveAND]
då SkipWHITE-funktionen (min erfarenhet) är den oftast förekommande framför
MoveAND.
Vi sätter bara in koden ovan omedelbart
efter föregående
Image1.Canvas.CopyMode:= CopMod;
— B finns redan deklarerad från tidigare i
FormKeyDown:
MoveCOPY ovan: Hela intagsrektangeln med den
vita ytan täcker för underlaget.
— Vi trycker nu på W = SkipWhite:
FörGrund¦BakGrund, FärgDisplay
Jag har här passat på att
lägga till 2 ytterligare bottenpanelerVänster:
— Panel9(störreVita=Bakgrundsfärg)
och Panel10(lillaSvartaMitten=Förgrundsfärg):
— Tangenterna BN sätter Bakgrundsfärg
och FörgruNdsfärg respektive som finns just då under Peken.
— DelphiKODen är på
FormkeyDown, caseKeyBlocket, variabeln D: TPoint; tillagd lokalt i FormKeyDown
och globalerna fgCol,bgCol: TColor; längst upp i Unit efter UsesBlocket:
{SÄTT FÄRG —
bAKGRUND FÖRGRUnD;}
{NoShift|BakgrundsFärg|B|Förgrund|N:}
Ord('B'),Ord('N'):
begin
GetCursorPos(D);
D:=
Image1.ScreenToClient(D);
if not PtInRect(Image1.ClientRect,D)
then exit;
case Key of
Ord('B'): bgCol:= Image1.Canvas.Pixels[D.X,D.Y];
Ord('N'): fgCol:= Image1.Canvas.Pixels[D.X,D.Y];
end;
Panel9.Color:= bgCol;
Panel10.Color:= fgCol;
UpdateMergeFlags;
end;{endBN}
Voila.
— Ctrl+Pilar får nu flytbilden att åka över
bildytan med den omgivande vita intagsrektangeln eliminerad: bara BildFiguren
framträder.
Elementär flytbildsteknik — grundexempel i DELPHI4
Komplikationer i
DELPHI(4) — BitMapTransparensen »Jävlas»
— Men håll ut: Befrielsen är nära.
SkipWHITE blocket ovan fungerar utmärkt med
”B.TransparentColor:=
clWhite;”.
Försöker man, emellertid, med andra bakgrundsfärger uppkommer (stundtals) rena
snurrren: DELPHI4 förvandlas (ibland, ibland inte, på sätt som verkar helt
oförutsägbara) till en vildhäst med fruktansvärda krafter. Med olika kodförsök
ser det ibland ut som att en lösning är i antågande. Just närman TROR att man
kan pusta ut, raseras snabbt hela arbetet till i stort sett ett osynligt
dammoln, bara med en enda verkställande tangenttryckning: inget händer. Inte
ett liv.
Test med typen
with Image2.Picture.BitMap do begin
PixelFormat:= pf32Bit;
Transparent:= True;
TransparentColor:= bgCol;
Image1.Canvas.Draw(X0,Y0,Image2.Picture.BitMap);
end;{notOK|IngetHänder}
kan köras utan några som helst problem. Men
inget händer: Den valda bakgrundsfärgen försvinner inte när man trycker
W — om den inte är VIT förstås. Då går det. Inte annars. Flytbilden svarar helt
enkelt inte på ovanstående allmänna transparenskommando.
Inte heller den till synes mera preciserade typen
if{(CopMod=cmSrcCopy)and}(SkipWhite=-1)then begin
B:= TBitMap.Create;
iW:= Image2.Width;
iH:= Image2.Height;
R:= Rect(0,0,iW,iH);
try
Image2.Picture.BitMap.PixelFormat:= pf32bit;
B.PixelFormat:= pf32bit;
BitMapRect(R,B);
with B.Canvas do begin
Brush.Color:= bgCol;
FillRect(R);
end;
B.Assign(Image2.Picture);
B.Transparent:= True;
B.TransparentColor:= bgCol;
Image1.Canvas.Draw(X0,Y0,B);
finally
B.Free;
end;
end else
Image1.Canvas.CopyRect(CRd,Image2.Canvas,CRs);
visar livstecken, utom på vitt.
— Vi (min erfarenhet) vet redan i DELPHI4
att en TBitMap INTE svarar på typ Transparent=True om INGEN OPERATION ÄNNU HAR
UTFÖRTS PÅ bildens minnesyta. Heldött. Går inte.
— Ovanstående försök innefattar emellertid
just ett sådant klargörande: ytfyllnad med färg, samt särskild rutin för
bildmått, säkerställer ATT TBitMap:en ska fungera.
Likväl. Intet. Sten dött i Berget.
BakgrundsOberoendeFlytbild, BGOFbegin
Allafärger
Lösningen
Lösningen är av typen radikal, vi tar hela
blocket för exakt jämförelse:
if{(CopMod=cmSrcCopy)and}(SkipWhite=-1)then
begin
B:= TBitMap.Create;
iW:= Image2.Width;
iH:= Image2.Height;
zW:=0; zH:=0;
if iW >= Screen.Width then zW:=1;
if iH >= Screen.Height then zH:=1;
R:= Rect(0,0,iW,iH);
try
Image2.Picture.BitMap.PixelFormat:= pf32bit;
B.PixelFormat:= pf32bit;
B.Assign(Image2.Picture);
B.Transparent:= True;
B.TransparentColor:= bgCol;
B.Canvas.Brush.Color:= bgCol;
B.Canvas.FillRect(R);
bR:= GetRValue(bgCol);
bG:= GetGValue(bgCol);
bB:= GetBValue(bgCol);
for y:= 0 to iH-1-zH
do begin
Pa:= Image2.Picture.BitMap.ScanLine[y];
Pb:= B.ScanLine[y];
for x:= 0 to iW-1-zW
do begin
{IGNOREbgCol:}
if (bR=Pa[4*x+2])and(bG=Pa[4*x+1])and(bB=Pa[4*x+0])then Continue;
{FörÖverALLT från Im2 till B utom bgCol:}
Pb[4*x+2]:= Pa[4*x+2];
Pb[4*x+1]:= Pa[4*x+1];
Pb[4*x+0]:= Pa[4*x+0];
end;{endForX}
end;{endForY}
Image1.Canvas.Draw(X0,Y0,B);
finally
B.Free;
end;
end else
Image1.Canvas.CopyRect(CRd,Image2.Canvas,CRs);
20Sep2014: Utan tillägget med zW och zH
uppkommer ett AccessViolation = funktionen kapas = avbryts då och endast då
intagsbilden är större än eller lika med bildskärmsbilden.
B.PixelFormat kan undvaras utan bieffekter, enligt test:
— Däremot om PixelFormat för Image2.PictureBitMap bockas för, uppkommer vid första nedtryckningen tangent W TOM
FLYTBILD: den bara försvinner, och återkommer sedan utan vidare avbrott med
bildflytten via Ctrl+Pilar.
— ScanLineOperationer i allmänhet tillhör kategorin maximalt snabbgående, även för
STORA bilder om matematiken i ScanBlocken inte är allt för omfattande: i 3D-
och animeringsprogram är den just det — enorma ServerLandskap krävs,
miljondatorer, för att bearbeta varje bildpixels slutdata. Här är vi mera
blygsamma.
— PASSA HÄR GÄRNA PÅ att KOLLA HUR DELPHI4
visar information i typen Komplicerat programfel genom följande ändring i
koden ovan:
—
Ersätt iH i forYloopen med iW och iW med iH i forXloopen:
— Ctrl+F9 sker utan
protester, P2 startar som vanligt med F9. Men, sedan vi importerat något
(Ctrl+V) och trycker W i det startade programmet, sker avbrott med ett
meddelande över nära hela bildskärmen:
”Error
Project P2.exe raised exception class EAccessViolation with
message 'Access violation at address 004428BB in module 'P2.exe.' Read of
address 01E8F832'. Process stopped. Use Step or Run to continue.”.
— Tryck OK och sedan Ctrl+F2 för att avsluta P2 och återgå till Kodfönstret.
— Ovanstående
typFELmeddelande visar sig UTESLUTANDE
ALLTID när man missar kod i samband med TBitMaps-rutiner eller gör slarvfel,
som i ovanstående medvetet iscensatta exempel — ALLTID i samband med
minneshanteringsrutiner. Ytterst svåra »kompileringsfel» att hitta och åtgärda
om man som här INTE REDAN VET HUVUDORSAKEN. Ha det gärna i bakhuvudet för
vidare. Fel gör vi alla, förr eller senare. (Ju grundligare, desto bättre,
förutsatt VILJA att komma igen).
BakgrundsOberoende
flytbild, exempel
Elementär flytbildsteknik — grundexempel i DELPHI4
Galant. Befriande. Grymt snabbt — förutsatt intagna bilder är mindre än bildskärmen:
ju mindre desto snabbare. Test på Intagna bilder från digitalkamera (flera
gånger större än en 23 tums bildskärm) visar att MoveSkipWHITE kräver runt 1/2
sekund för att uppdatera flytbilden. Perfekt funktion.
Verifierande test
Nedan
Vänster:
TestBild. Mitten: Efter Import Ctrl+V till P2 och Fönsteranpassning F5. Höger: Efter ytterligare Ctrl+V — vi använder en kopia av underlaget som
flytbild och lämplig passning för kontroll:
— MoveCOPY med IncludeWHITE som standard för
att se intagsrektanglarna i flytbilderna från start:
|
Nedan
Vänster:
Efter W=SkipWHITE. Mitten: Efter B=bgCol med
Peken över gråytan. Höger: Efter B=bgCol med
Peken över svartytan.
|
Perfekt. Exakt som vi ville ha det.
— Nu framträder även vit text (som skapats på given homogen färgyta) i
flytbilderna och som obehindrat kan flyttas över till andra godtyckliga
bildytor, synligt(med bakgrunden) eller osynligt(utan bakgrunden), tangent W
växlar.
— Observera här (återigen, för den som bara ser den här presentationen): alla
ändringar i flytbildssätten framträder omedelbart visuellt med en enda enkel
tangentnedtryckning: W C B N. Inget musklickande. Inget armvevande över halva
bildskärmen för att hitta. Inget letande efter menyer och ToolBars. Lugnt.
Ingen stress.
20Okt2014 — Mera
TransparensenJävlasProblem:
— Men LÖSNINGEN ovan (BGOF) grusades snart med
följande upptäckt:
— Perfekt funktion — tills plötsligt (och
turligt för upptäcktens del) ett bildmått 388;256 kom med i bilden (även
2·388×256 ger AcVi-avbrott):
— AccessViolationAVBROTT inträder när
SkipWhite-funktionen aktiveras.
LÖSNINGEn — vi gör oss oberoende sv ScanLine-funktionen genom att läsa
direkt från och skriva direkt till bildens dataminne:
{ENDA
FUNGERANDE HELHETSLÖSNINGEN:
—388;256-felet,
och även >Screen-Felet eliminerat som det ser ut|20Okt2014:}
Procedure TmMoveSkipWHITE;
var
A,B: TBitMap;
Pa,Pb,aP,bP: PChar;
TMa,TMb: TMemoryStream;
W,H,x: Integer;
R: TRect;
aR,aG,aB: Byte;
begin with Form1 do begin
TMa:= TMemoryStream.Create;
TMb:= TMemoryStream.Create;
A:= TBitMap.Create;
B:= TBitMap.Create;
W:= Image2.Width;
H:=
Image2.Height;
R:= Rect(0,0,W,H);
{Tar
ut bakgrunden för jämförelse:}
aR:=
GetRValue(bgCol);
aG:=
GetGValue(bgCol);
aB:=
GetBValue(bgCol);
try
{SpecialRutin,
etablerar bitmap:ens dimensioner:}
BitmapRect(R,A);
BitmapRect(R,B);
A.Canvas.Brush.Color:= clWhite;
A.Canvas.FillRect(R);
{Preparera|BehandlingsBitMaps:}
A.PixelFormat:= pf32bit;
B.PixelFormat:= pf32bit;
{FLYTBILD=Källbild|Im2¦Copy|Im1¦MarkRect|TillA|}
A.Canvas.CopyRect(R,Image2.Canvas,R);
{PREPARERA
MÅLBILDENS BITMAP FÖR BAKGRUNDSELIMINERING:}
B.Canvas.Brush.Color:= bgCol;
B.Canvas.FillRect(R);
B.TransparentColor:= bgCol;
B.Transparent:= True;
{SPARA
TILL MemoryStreamen så att vi kan göra ändringar därifrån:}
A.SaveToStream(TMa); //Källbilden|FlytBildeIm2.
B.SaveToStream(TMb); //Målbilden|SkipBackGroundColorResult.
{TILLDELA
MemoryStreamen en AdressPekare - vårt HuvudTransportMedel i ändringarna:}
Pa:= TMa.Memory;
Pb:= TMb.Memory;
{Samma
som hela BMP-strukturen|Med BitMapInfoHeader: börjar från pos54:}
{En
enda lång sammanhängande DataMinnesAdressRad för hela bilden:}
for x:= 0 to H*W - 1 do begin
bP:= Pb + 54 + 4*x;
aP:= Pa + 54 + 4*x;
{SkipBgCOL:}
if (aR=Byte((aP
+2)^))
and(aG=Byte((aP
+1)^))
and(aB=Byte((aP
+0)^))
then
Continue;
{BG-ytan
kvarlämnas orörd på B för slutlig transparens via Im1Draw:}
Byte((bP +2)^):= Byte((aP
+2)^);
Byte((bP +1)^):= Byte((aP
+1)^);
Byte((bP +0)^):= Byte((aP
+0)^);
end;{endForX}
{FINALIZING:}
{UPPDATERA
ÄNDRINGARNA TILL den ursprungliga bitmap:en|B:}
{Förbered
MemoryTillBitMap:}
{Börjar
från MinnesPekarensPosition - funkar inte om annat än från 0:}
TMb.Position:= 0;
{UPPDATERAR
ÄNDRINGARNA:}
B.LoadFromStream(TMb);
{FlytbildsPreparering|OK|Bilden
ritas ut|X0|Y0 flytbildsparametrar:}
Image1.Canvas.Draw(X0,Y0,B);
finally
A.Free;
B.Free;
TMa.Free;
TMb.Free;
end;
end;
{endWithForm1}
end;
{endTmMoveSkipWHITE}
{Överflyttad
kopia från T2014|20Okt2014.}
Med denna justering har ytterligare fel ännu
inte observerats
— För vidare observation (20Okt2014).
Kommentar allmänt DELPHI4 ScanLines:
— Något är alldeles
tydligt uppenbart fel — antingen i DELPHI4 eller på annat sätt i förening med
SAcanLine-funktionen (subrutin) som under speciellt taskiga lägen åstadkommer
försmädliga AccessViolationAvbrott — i sig inte farliga, men tillräckliga för
att den egentliga funktionen hoppas över. Vi har nu SÄKERT studerat TRE
ScanLineFELområden: 16;64-felet, 388;256-felet och StörreÄnScreen-felet.
— Samtliga dessa
ScanLineFEL försvinner (tydligren) om TMemoryStream-metoden används istället,
vilket garanterar fullständigt ScanLineOberoende (med exakt 32-bitars
minneshantering).
Elementär flytbildsteknik — grundexempel i DELPHI4
Invertera
flytbilden — tangent I
Vi lägger till ytterligare en sådan enkel,
elementär, flytbildsinstans: FormKeyDown CaseBlocket utan Shift, alla variabler
finns redan:
{INVERTERA FLYTBILDEN|11Sep2014:}
Ord('I'): begin
with Image2.Canvas
do
begin
R:=
Rect(0,0,Image2.Width,Image2.Height);
B:= TBitMap.Create;
try
BitMapRect(R,B);
B.Assign(Image2.Picture);
CopyMode:= cmDstInvert;
CopyRect(R,B.Canvas,R);
finally
B.Free;
end;
CopyMode:= cmSrcCopy;
end;{endWithIm2Canvas}
UpdateMergeFlags;
end;
Checking: Vänster: Efter Ctrl+V och
F5. Höger: Efter I:
Utomordentligt. Att Inverteringsfunktionen
fungerar perfekt kontrollerar vi genom att lägga den inverterade kopian över
originalet och köra MoveAND (Tangent C). Korrekt funktion (ickeINV + INV =
helsvart) betyder att bilderna tar ut varandra med resultat i helsvart:
Vänster: Efter Ctrl+V No2
och Tangent C; helsvart. Höger: Ctrl+Numpad1(Step1p), Ctrl+ PilHö:
Vi ser att KONTURER BÖRJAR FRAMTRÄDA med
minsta förskjutning på en pixel RightDown i leden XY mellan två varandra
inverterade original.
— Det är också programgrunden till det mycket
eftertraktade — och mycket effektiva
fotoredigeringsverktyget/bildbehandlingsverktyget — SHARPENING generellt.
Elementär flytbildsteknik — grundexempel i DELPHI4
Enkel RGB-palett
F4 med FärgUnderPeken — Numpad|0
Ofta, ibland, behöver vi få i varje fall
ungefärliga färger som motsvarar NATRLIGA SPEKTRUMets färger:
Färgkartan ovan (från FinishingTouch Windows
95-eran) — orienterad vertikalt — finns inlagd som Palett3.bmp i projektkatalogen för P2.
Tangent F4 tar fram den på Image1 och lägger
ut den som flytbild enligt DELPHI4-koden på FormKeyDown F4, CaseKeyBlocket:
{PALETT RGBflytbild:}
VK_F4: begin
S:= 'Palett3.bmp';
if not
FileExists(S) then exit;
Image2.Picture.LoadFromFile(S);
Image3.Picture.LoadFromFile(S);
{Anger bildmåttet,
PanelLabeln överst i mitten:}
Panel4.Caption:=IntToStr(Image2.Width)
+';'+IntToStr(Image2.Height);
X0:=0; Y0:=0;
CRs:=Image2.ClientRect;
CRd:=CRs;
OffsetRect(CRd,X0,Y0);
Image3.BoundsRect:=
Image2.BoundsRect;
Image3.Canvas.CopyRect(CRs,Image1.Canvas,CRd);
Image1.Canvas.CopyMode:=
cmSrcCopy;
Image1.Canvas.CopyRect(CRd,Image2.Canvas,CRs);
SetCursorPos(Left+Panel1.Left+32, Top+Panel1.Top+Y0+26+4);
ClipBoardImported:= True;
end;{endF4}
ClipBoardImported här inlagt om man
vill optimera fönsterstorleken (F5) för detta speciella fall.
— Med F5 (P2-fönstret här roterat +90°) ger
F4-kommandot Palett3 intagen med Peken förinställd på svart:
Fortsättningen i FÄRGANALYSATOR RGB|HSB OCH
FÄRGREDIGERARE med DELPHI4.
VisuellaSpektrumPalettRitningen
i DELPHI4 — Pixels-metoden
A,N,Z: Integer; Blocket nedan ger endast EN
horisontell rad, denna har sedan dubblerats i höjd:
A:= 255;
Z:= 0;
with Image1.Canvas
do
begin
for N:= 0 to 127 do Pixels[N+0*127,50]:=
RGB(A,2*N,Z);
for N:= 0 to 127 do Pixels[N+1*127,50]:=
RGB(A-2*N,A,Z);
for N:= 0 to 127 do Pixels[N+2*127,50]:=
RGB(Z,A,2*N);
for N:= 0 to 127 do Pixels[N+3*127,50]:=
RGB(Z,A-2*N,A);
for N:= 0 to 127 do Pixels[N+4*127,50]:=
RGB(2*N,Z,A);
end;{endWithIm1}
Normal — också maximal färgmättnad
TONSEKTORERNA avgränsas och bestäms av
ELEMENTARSPEKTRALFÄRGERNA resp
0|RÖD(255,0,0) 1|GUL(255,255,0)
2|GRÖN(0,255,0) 3|INDIGO(0,255,255) 4|BLÅ(0,0,255)
5|VIOLETT(255,0,255), sedan
åter mot 6|0|RÖD(255,0,0)
— inte medtagen ovan: ingår inte i det visuella spektrumet:
För att få med även sista intervallet 5 som sluter spektrumcirkeln mot rött
igen, ska det skrivas med B från 255 mot 0: 5: C:=
RGB(A,Z,A-K*N);.
— Vi måste ha med detta sista intervall för att fullt kunna
omvandla mellan RGB och HSB: H [eng.
Hue, FärgTON eller FärgNYANS] i HSB är just ovanstående visuella
spektrum.
VisuellaSpektrumPalettRitningen
i DELPHI4 — SetPixel-metoden (10ggr snabbare)
H: THandle; A,N,Z,K,I:
Integer; C: TColor; — K-faktorn bestämer TonSektorIntervallet, här förkortat till
51pixels:
— Programblocket nedan ger endast en
horisontell pixelrad, denna sedan dubblerad i höjd:
H:=
Image1.Canvas.Handle;
A:=
255;
Z:=
0;
C:=
0;
K:=
5;
I:= 255 div K;
with Image1.Canvas do
begin
for TonSektor:= 0 to 4 do
for N:= 0 to I do begin
case TonSektor of
0: C:= RGB(A,K*N,Z);
1: C:= RGB(A-K*N,A,Z);
2: C:= RGB(Z,A,K*N);
3: C:= RGB(Z,A-K*N,A);
4: C:= RGB(K*N,Z,A);
end;
SetPixel(H, N + TonSektor*I, 50, C);
end;
end;{endWithIm1}
VisuellaSpektrumPalettRitningen
i DELPHI4 — ScanLine-metoden (1000ggr snabbare)
B: TBitMap; R: TRect;
Pb: PByteArray; bR,bG,bB: Byte;
K,A,Z,N,TonSektor,I,J: Integer; :
— Programblocket nedan ger hela bilden som
ovan:
R:=
Rect(0,0,300,10);
B:=
TBitMap.Create;
try
BitMapRect(R,B);
B.PixelFormat:= pf32Bit;
B.Canvas.Brush.Color:= clWhite;
B.Canvas.FillRect(R);
A:= 255;
Z:= 0;
K:= 5;
I:= 255 div K;
bR:=0; bG:=0; bB:=0;
Pb:= B.ScanLine[0];
for TonSektor:= 0 to 4 do
for N:= 0 to I do begin
J:= 4*(N + TonSektor*I);
case TonSektor of
0: begin bR:= A; bG:= K*N; bB:=
Z; end;
1: begin bR:= A-K*N; bG:= A; bB:= Z;
end;
2: begin bR:= Z; bG:= A; bB:= K*N; end;
3: begin bR:= Z; bG:= A-K*N; bB:= A; end;
4: begin bR:= K*N; bG:= Z; bB:= A; end;
end;
Pb[J + 2]:= bR;
Pb[J + 1]:= bG;
Pb[J + 0]:= bB;
end;
for I:= 0 to 20 do
Image1.Canvas.Draw(0,I,B);
finally
B.Free;
end;
Fortsätt i EditColors — färgredigering
och analys RGB|HSB.
Elementär flytbildsteknik — grundexempel i DELPHI4
112;320-felet
16;64-felet —
ScanLineFEL i DELPHI4
B:= TBitMap.Create;
try
for W:= 16 to 200 do
for H:= 16 to 200 do
begin
R:= Rect(0,0,W,H);
BitMapRect(R,B);
ClipBoard.Assign(B);
D:= Ord('V');
FormKeyDown(Self,D,[ssCtrl]);
ClipBoard.AsText:=
IntToStr(W)+';'+IntToStr(H);
D:= Ord('R');
FormKeyDown(Self,D,[]);
end;
finally
B.Free;
end;
AVBROTT
sker för alla n heltalskombinationer n16;n64 eller n64;n16 som pixelmått på
den källbild som ska vändas horisontellt eller roteras +90° OM ScanLine-funktionen
i DELPHI4 används: första stannar på 16;64 med ett programexekveringsdavbrott
av typen AccessViolation: funktionen har
havererat.
— Används istället en TMemoryStream — direkt ByteÅtkomst i
BitMapens Dataminne — ger ovanstående testgenomgång (33.856=184² stycken
rektanglar testade) perfekt avbrottsfri körning. Tangenterna Ctrl+V tar in
Urklippskopian, och R leder till rotationsblocket. Det faktum att TMemoryStream
klarar biffen utan protester styrker misstanken (starkt) att:
— 32bitars
rektangelvändning på ByteBaserad Horisontell — men inte vertikal
— dataomkastning och överföring av bilddata från Längd till Bredd och vice versa INTE är korrekt utformat i DELPHI4. Det blir svårt att
se saken på annat sätt med TMemoryStreamBeviset. Procedurerna följer nedan.
I samband med test
av ovanstående (15Sep2014) — P2-fönstrets mått efter anpassning (F5) till den
importerade Palett3-bilden — med import av det fönstret till T2014 och sedan
FlipHorizontal och Rotate90, visas ACCESS VIOLATION:
— Har aldrig
tidigare inträffat under de snart 15 år som programformen använts.
— Inspektion visade
att det är bildmåtten som är kritiska:
— Skiljer det på
bara en pixel, visas inte felet.
Elementär flytbildsteknik — grundexempel i DELPHI4
Efter Inside WINDOWS FILE FORMATS s57, Tom
Swan, Sams Publishing 1993
|
15-18 4 1.DWORD biSize:
...................... Longint; 19-22 4 2.LONG biWidth:
................... Longint; 23-26 4 3.LONG biHeight:
.................. Longint; 27-28 2 4.WORD biPlanes:
................. Word; 29-30 2 5.WORD biBitCount:
.............. Word; 31-34 4 6.DWORD biCompression:
...... Longint; 35-38 4 7.DWORD biSizeImage:
........... Longint; 39-42 4 8.LONG biXPelsPerMeter:
.... Longint; 43-46 4 9.LONG biYPelsPerMeter:
.... Longint; 47-50 4 10.DWORD biClrUsed: ................ Longint; 51-54 4 11.DWORD biClrImportant: ........ Longint; |
RGB-formatets datalängd — formen oven samma
som via DELPHI4:s TMemoryStream.
— Pixeldatats offsetadress
är 54. DataPekaren ska ställas på P + 54 för att få bildens första
pixel (B-värdet i första färggruppen BGR#).
Elementär flytbildsteknik — grundexempel i DELPHI4
Proceduren nedan testad OK 15|16Sep2014 — FlipHorizontal:
Procedure TMFlipHorizontal(SourceIm: TImage);
var
A,B: TBitMap;
Pa,Pb,iP,P: PChar;
TMa,TMb: TMemoryStream;
W,H,x,y,Sx,Ex: Integer;
begin with Form1 do begin
TMa:= TMemoryStream.Create;
TMb:= TMemoryStream.Create;
A:= TBitMap.Create;
B:= TBitMap.Create;
try
{SpecialRutin, etablerar bitmap:ens
dimensioner:}
BitmapRect(CRs,A);
BitmapRect(CRs,B);
{Källbilden|Im2¦Copy|Im1¦MarkRect|TillA|CRd|s|Avgörande:}
A.Canvas.CopyRect(CRd,SourceIm.Canvas,CRs);
{Preparera|BehandlingsBitMaps:}
H:= A.Height;
W:= A.Width;
A.PixelFormat:= pf32bit;
B.PixelFormat:= pf32bit;
B.Canvas.Brush.Color:= clWhite;
B.Canvas.FillRect(CRs);
{SPARA
TILL MemoryStreamen så att vi kan göra ändringar därifrån:}
A.SaveToStream(TMa);
B.SaveToStream(TMb);
{TILLDELA
MemoryStreamen en AdressPekare - vårt HuvudTransportMedel i ändringarna:}
Pa:= TMa.Memory;
Pb:= TMb.Memory;
{Samma
som hela BMP-strukturen|Med BitMapInfoHeader: börjar från pos54:}
for
y:= 0 to H-1 do begin
Sx:= (H-1-y)*W;
Ex:= (H - y)*W - 1;
for
x:= Sx to Ex do begin
iP:= Pb + 54 + 4*(Ex + Sx - x);
P:= Pa + 54 + 4*x;
Byte((iP +2)^):= Byte((P +2)^);
Byte((iP +1)^):= Byte((P +1)^);
Byte((iP +0)^):= Byte((P +0)^);
end;{endForX}
end;{endForY}
{FINALIZING:}
{UPPDATERA ÄNDRINGARNA TILL den
ursprungliga bitmap:en|B:}
{Börjar från MinnesPekarensPosition -
funkar inte om annat än från 0:}
//TMa.Position:=
0|Behövs inte|InteÄndrad.
TMb.Position:= 0;
{UPPDATERAR
ÄNDRINGARNA:}
B.LoadFromStream(TMb);
{FlytbildsPreparering|OK|Bilden
ritas ut:}
Image1.Canvas.CopyMode:= cmSrcCopy;
BitmapToIm(B);
//Image1.Canvas.Draw(X0,Y0,B);
finally
A.Free;
B.Free;
TMa.Free;
TMb.Free;
end;
end;{endWithForm1}
end;{endTMFlipHorizontal}
Proceduren nedan testad OK 15|16Sep2014 — RgB till BgR:
Elementär flytbildsteknik — grundexempel i DELPHI4
RGB till BGR:
{Färgvändningen|BitMap
A|RGB till BGR:}
{Samma
som ovan men enbart med BitMap A och ByteKoden:}
R:=
Byte((aP +2)^);
Byte((aP
+2)^):= Byte((aP +0)^);
Byte((aP
+0)^):= R;
TestatOK 16Sep2014. Bägge procedurerna fungerar ännu så länge utan observerade fel.
NEJ. NYLIGEN ÄNNU ETT AVBROTT. FlipHorizontal.
— Nej. Berodde på att jag hade satt
H:= SourceIm.Height;
W:= SourceIm.Width;
istället för korrekta
H:= A.Height;
W:= A.Width;
EFTERSOM SourceIm i fallet MarkRect är Image1 (kopiering sker
från större till mindre):
— Avbrott med MarkRect och sedan direkt H, medan en kopia som
går till Image2 inte gav avbrott.
— Ordnat, således. DELPHI4-dramatik.
— Märkvärdigt är det. Testade nyligen återigen
Rot90° på »gamla ScanLineBlocket» Unit1 T2014:
— Nu uppför sig den delen ytterligare
rebelliskt: för varje rotation minskas originalbildens bild, inte bildytan, med
1 pixelrad, så att det som blir kvar minskar med antalet rotationer.
— Det var något nytt. Har aldrig tidigare
visat sig.
— Mitt fel:
R:= Bounds(0,0,CRd.Bottom+1,CRd.Right+1); REST efter nyligen genomförda TEST.
— Tas tillägget bort fungerar det som
tidigare, frånsett 16;64-felen.
— Rättat med hjälp av gamla Project2002.
DELRESULTAT AV FELSÖKNINGEN 16;64-felet:
EFTERSOM TMemoryStream INTE visar något fel på 112;320-Fönstret från P2,
men att ScanLineBlocket gör det, UPPSTÅR MISSTANKEN att 16;64-felet
ligger hos DELPHI4 i ScanLine-algoritmen.
— Nästa steg blir att försöka utforma en
TMemoryStreamProcedur för Rot90°-fallet också. Det kommer att avgöra.
Elementär flytbildsteknik — grundexempel i DELPHI4
Proceduren nedan testad OK 15|16Sep2014 — Rotate90°:
Procedure TMScanRot(SourceIm: TImage);
var
A,B: TBitMap;
R: TRect;
P,iP,Pa,Pb,
TMa,TMb: TMemoryStream;
W,H,x,y,Sx,Ex,
iX: Integer;
begin with Form1 do begin
TMa:= TMemoryStream.Create;
TMb:= TMemoryStream.Create;
A:= TBitMap.Create;
B:= TBitMap.Create;
try
{Målbildens
roterade källrektangel|Width¦Height¦omvända|Rect eller Bounds här egalt:}
R:= Bounds(0,0,CRd.Bottom,CRd.Right);
{SpecialRutin, etablerar bitmap:ens
dimensioner:}
BitmapRect(CRs,A);
BitmapRect(R, B);
{Källbilden|Im2¦Copy|Im1¦MarkRect|TillA|CRd|s|Avgörande:}
A.Canvas.CopyRect(CRd,SourceIm.Canvas,CRs);
{Preparera|BehandlingsBitMaps:}
H:= A.Height;
W:= A.Width;
A.PixelFormat:= pf32bit;
B.PixelFormat:= pf32bit;
B.Canvas.Brush.Color:= clWhite;
B.Canvas.FillRect(CRs);
{SPARA
TILL MemoryStreamen så att vi kan göra ändringar därifrån:}
A.SaveToStream(TMa);
B.SaveToStream(TMb);
{TILLDELA
MemoryStreamen en AdressPekare - vårt HuvudTransportMedel i ändringarna:}
Pa:= TMa.Memory;
Pb:= TMb.Memory;
{Samma
som hela BMP-strukturen|Med BitMapInfoHeader: börjar från pos54:}
{Överföringen
från A till B|Sx = WH - W - Wy| Ex = WH - 1 - Wy|iX=x-Sx= 0 1 2 3 .. :}
for
y:= 0 to H-1 do begin
Sx:=(H-1-y)*W;
Ex:= Sx + W-1;
for x:=
Sx to Ex do begin
iP:= Pb+54 + 4*(y + H*(x-Sx));
P:= Pa+54 + 4*x;
Byte((iP +2)^):= Byte((P
+2)^);
Byte((iP +1)^):= Byte((P +1)^);
Byte((iP +0)^):= Byte((P +0)^);
end;{endForX}
end;{endForY}
{FINALIZING:}
{UPPDATERA ÄNDRINGARNA TILL den
ursprungliga bitmap:en|B:}
{Börjar från MinnesPekarensPosition -
funkar inte om annat än från 0:}
TMb.Position:= 0;
{UPPDATERAR
ÄNDRINGARNA:}
B.LoadFromStream(TMb);
{FlytbildsPreparering|OK|Bilden
ritas ut|S|GlobalSträng|SpeciellSluthantering:}
S:='ScanRotCompleted';
BitmapToIm(B);
//Image1.Canvas.Draw(X0,Y0,B);
finally
A.Free;
B.Free;
TMa.Free;
TMb.Free;
end;
end;{endWithForm1}
end;{endTMScanRot|16Sep2014.}
Ex = Sx + W–1 =
(H-1-y)*W + W–1 = WH-W-Wy + W–1 = WH-Wy
–1 = W(H-y) –1
Enda som skiljer FlipHorizontal från
Rotate90° i DataLoopen är
FH iP:= Pb + 54 + 4*(Ex + Sx - x);
R90 iP:= Pb + 54 + 4*(y + H*(x-Sx));
Råformen i 90°-rotationerna är
Byte((Pb+54+(4*y)+ 4*(iX)*H
+2)^):= Byte((Pa+54+ 4*x+2)^);
Byte((Pb+54+(4*y)+ 4*(iX)*H
+1)^):= Byte((Pa+54+ 4*x+1)^);
Byte((Pb+54+(4*y)+ 4*(iX)*H
+0)^):= Byte((Pa+54+ 4*x+0)^);
med
iX = x – Sx = x – W(H–1–y);
Pb+54+(4*y)+
4*(iX)*H
kan då förenklas via
Pb+54+
4*(y+ H*iX) = Pb+54+ 4*(y+H*(x–Sx)) = iP;
— Hur gick det, då, med 112;320-fönstret?
Perfekt.
— En säker TESTFORM som bevisar att
90°-rotationerna fungerar perfekt är att ta ut en himmelsdel på ett foto och
rotera 4 ggr:
Efter fjärde 90°-rotationen ska uttaget
smälta in tillbaka på exakt plats det togs ut ifrån — och »utan förluster»,
dvs., inga borttagna kantlinjer (eller annat) får förekomma. Bilden ovan efter
test av föregående TMScanRot.
— Det skulle, då, betyda: ScanLine-funktionen
i DELPHI4 är inte korrekt utformad.
— Det är heller ingen avundsvärd
programuppgift att försöka göra en KOMMERSIELL programprodukt som ska täcka samtliga
möjliga PixelFormat-fall (man behöver nog avancera till närmast GUD för den
uppgiften);
— En öppen svårighet — och som visat sig så
svår att ens få visuell koll på (nu först efter 15 år[!]) — KAN just vara
BILDREKTANGELOMVÄNDNINGAR kontra den YTTERST känsliga
minneshanteringsalgoritmen: missas en enda BIT eller Byte är det KÖRT: Access
Violation @Address ... . Säkert som amen i kyrkan.
— ScanLine i
DELPHI4 FUNGERAR FÖR ÖVRIGT PERFEKT
— om inga andra
Det-Tar-Runt-15år-Att-Upptäcka-Felen-Övningar är att vänta.
Så
länge man inte laborerar med VÄNDNING av bildrektanglarna — FlipHorizontal
Rotera90°: FlipVertical lider inte av 16;64-felet — verkar allt fungera utan
några som helst problem: inga observerade avbrott (än).
Separat test med rektanglar från 16×16p upp till 200×200p
gjordes nyligen (Speciell TestLoop 16Sep2014|T2014 33856st Rect) på TMScanRot: helt galant felfritt. Det styrker bevisningen.
B:= TBitMap.Create;
try
for W:= 16 to 200 do
for H:= 16 to 200 do
begin
R:= Rect(0,0,W,H);
BitMapRect(R,B);
ClipBoard.Assign(B);
D:= Ord('V');
FormKeyDown(Self,D,[ssCtrl]);
ClipBoard.AsText:=
IntToStr(W)+';'+IntToStr(H);
D:= Ord('R');
FormKeyDown(Self,D,[]);
end;
finally
B.Free;
end;
ClipBoardKopian för W;H ifall avbrott skulle
ske (vetskap om var). Här: NoProblemo.
EditColors
Senast
vald Bakgrund(B)|Förgrund(N) redigeras — sliderna 1. dras med musen, 2. flyttas med PilVäHö Ctrl+ NumPad|123 sätter 1 5 20 steg, 3. numeriskt med Alt+nnn; PilUppNer Radval; CapsLock Kolumnval RGB|HSB, markering visar parameter; Enter Verkställer, Esc ångrar&avslutar, R åter utgångsläget.
Elementär flytbildsteknik — grundexempel i DELPHI4
FÄRGANALYSATOR
RGB|HSB
med FÄRGREDIGERARE
i DELPHI4
Panel12|Image5
·
MusVäNER på aktuell
knapp|slid ger skjutreglageeffekt
·
Alt+ nnn med siffror nnn på sifferbordet
NumPad|0-9 skriver in värdena direkt på vald post (markerat som ovan,
himmelsblå bakgrund)
·
Piltangenter VäHö steppar (flyttar alla RGB-slider om HSB är valt) i steg om 1 5 eller 20
pixels med inställning Ctrl+ NumPad|1 2 3
·
Piltangenter UppNer växlar rad
R(H)G(S)B(B), CapsLock växlar kolumn RGB eller
HSB
·
Enter sätter senast vald färg
fgCol FÖRGUND eller bgCol BAKGRUND; Esc avslutar utan ändring
(Space+Enter öppnar)
·
Tanget O = Enter = SättNy; Tangent C = Escape = Exit = AvslutaUtanÅtgärd; Tangent R = TaOmRedigeringenFrånInslagspunkten.
·
EditColorsPanelen visas
längst ner till höger i P2:
·
RedigeraFärgen är den som SIST valdes
av fgCol=Förgrundsfärgen=LillaRutanNedreVä
Tangent N eller bgCol=Bakgrundsfärgen=StoraRutanUnder
Tangent B (närmsta tangenten Bakom N)
Ett mer eller mindre OUNDGÄNGLIGT
bildhanteringsverktyg är tillgång till FÄRG + detaljerad färgförklaring:
— Det innebär att man alltid i alla lägen
har tillgång till
·
en FÄRGANALYSATOR — enkelt elementär inblick i
spektralmatematiken (HSB) tillsammans med RGB-värden
·
en FÄRGREDIGERARE integrerad för att PÅ ENKLASTE SÄTTET få fram
exakt önskad färg (bakgrund eller förgrund) med numeriska
värden, om så önskas
DELPHI4kod:
1. Unit1C, ny — EditColorsUnit
2. uses Unit1C, tillägg
till usesBlocket Unit1
3. Panel12
och Image5|alClient|Visible|AutoSize=False: Unit1; ecTimer: deklareras på Unit1C efter usesBlocket
enligt
type
TecTimer = class(TTimer)
Procedure OnEditColors(Sender:
TObject);
end;
och som skrivs (vidare nedan) i
ImplementationBlocket Unit1C på det (notera) speciella sättet
Procedure TecTimer.OnEditColors(Sender:
TObject);
...
(och Vilket
PunktPåt Garanterar att nybörjaren har det JÄTTESVÅRT med Delphi[4] de första
50 åren ...: i princip OMÖJLIGT att »räkna ut logiskt» på förhand de olika
sätten: man måste ha detaljerad inblick i Delphis/Pascals type-class-system).
och som deklareras GlobalVariabel i Unit1C i
varIABELblocket efter usesBlocket
ecTimer: TecTimer;
— ecTimer (EditColorsTimer)
skapas separat Unit1 på FormCreate (sist) enligt
ecTimer:= TecTimer.Create(nil);
with
ecTimer do begin
Enabled:= False;
OnTimer:= OnEditColors;
end;
(nil
[”ingenting”] anger att ecTimer saknar Parent, annars ska ParentEgenskapen stå
i parentesen, typ ”Form1”; nil
används generellt för att säkra att en variabel INTE upptar någon direkt plats
i datorminnet, typ [innan ..Create] BitMap1:= nil;.
— Delphihjälpen [Overview of pointers]
skriver på nil:
”The reserved word nil is a special
constant that can be assigned to any pointer. When nil is assigned to a pointer, the
pointer doesn’t reference anything.”)
och entledigas från DatorMinnet på Unit1
FormClose enligt
ecTimer.Free;
Allt det övriga finns i Unit1C med
procedurerna i typeBlocket
Procedure vRGBtoHSB(var C1,C2,C3: Integer);
Procedure vHSBtoRGB(var C1,C2,C3: Integer);
Procedure
EditColors(var Key: Word; Shift:
TShiftState);
och sedan deras ordinarie kodblock i
Implementationsdelen, tillsammans med den nu särskilt originellt, till skillnad
från de andra, angivna TecTimer.OnEditColors (först i kön):
— Proceduren nedan TecTimer.OnEditColors är INTE deklarerad globalt i Unit1C:
— Vi gör så ibland — skriver LOKALA
procedurer närmast ÖVER en undre MasteProcedur (alternativt,
sätter in den som en INRE NÄSTAD procedur i mastern direkt efter varBlocket):
Mastern kan använda en icke globalDeklarerad procedure OM, och endast då, denna
står FÖRE i aktuell Unit. Står den efter, känns den inte igen.
{EditColorscTimer|Används
för att simulera MouseMove|RGB|HSB-sliderna på Image5:}
Procedure TecTimer.OnEditColors(Sender: TObject);
var
W: Word;
begin with Form1 do begin
if not Panel12.Visible
then exit;
if
GetKeyState(VK_LBUTTON)<=-127 then
begin
ecTimer.Interval:= 10;
W:= Ord(#2);
EditColors(W,[]);
exit;
end
else
begin
{STANDby:}
ecTimerON:=False;
ecTimer.Interval:= 100;
{RENSA
Alt+NumPad0..9 Input om Ångra före 3 inslag:}
if
(GetKeyState(VK_MENU)>-127)
and(Length(S)<3)
and(KeyNP09)
then
begin
S:= '';
KeyNP09:=False;
Label1.Caption:= 'Clear';
end;{endIfÅngraInslagFöre3}
end;{endEcTimerStandBy}
end;{endWithForm1}
end;{endTForm1ecTimerTimer|14Jul2014 Uni5 T2014|17Sep2014|Uni1C|P2}
{ANVÄNDS
till RGB|HSB|ScrollRows istf.MouseMove.}
RENSA-blocket: Inmatning av RGB eller
HSB-värden kan ske manuellt med Alt+NumPad 0..9 i TRE siffror (0 skrivs då
000):
— ÅNGRAR man sig (efter typ 53 ... jä..)
rensas inslaget med visningen ”Clear” på Statusradens Label1 om man släpper upp
Alt-tangenten. Sedan är det bara att slå om.
— Typen Alt+”5378” resulterar bara i ”255”,
övriga sätt ignoreras.
Se DELPHI4-koden
för de tre övriga procedurerna ovan särskilt i
Ytterligare OUNDGÄNGLIGA
FLYTBILDStillståndsSÄTT med enkla tangenttryckningar [Se HIMRV]:
H vändHorisontellt
V vänd
Vertikalt
R Rotera
i steg om +90°
M Tona (motVitt)[Vid
programstart, börja från 50%]
NumPad+ ÖkaToning (max100)
NumPad– MinskaToning (min0)
Space+H färgvänd RGB till BGR (MånskensFärger blir SolUppgångsDito och v.v.)
NumPad0 visa
färgenUnderPeken i RGB(0-255) och HSB(0-255)
Space+NumPad0 Som ovan men kopieras i text till Urklipp
Sedan vi infört STECKREKTANGEL med
uttagsfunktioner:
Ctrl+D Duplicera
Ctrl+Shift+D FlyttaUt
(samma som ovan men originalet under raderas)
Ctrl+C Kopiera
till Urklipp
Ctrl+X Klipp
ut till Urklipp
Ctrl+Delete Radera
(alt.ev. Ctrl+E[rase])
Ctrl+ T Text
(läggs ut som flytbild | Fet, kursiv, AllaSTORAellersmå m.m.)
T Som
ovan efter första (senast finns kvar)
Unit2=Unit1A
Elementär flytbildsteknik — grundexempel i DELPHI4
Med ovanstående, vidare utvidgningar i DEN
ELEMENTÄRA (DELPHI4) programkoden för ett ELEMENÄRT flytbildsverktyg (P2),
introduceras vi (allt mer) för SYSTEMATISKA STRUKTURER:
— kodblock med inre SPECIELLA
sammansättningar och inbördes beroenden som INTE DIREKT hör till formytans
komponenter.
— För att (något) skilja dessa
kodDepartement åt (Programfönstrets KodBasic,
Bildhanteringens olika KodBasic) väljer jag här att införa en ny
komplementär Unit (’Unit2’) till Unit1, och som här kommer att namndöpas om
till Unit1A (med ev. vidare Unit1B, Unit1C,
osv.) — för att reservera ev. kommande ENKLA grepp åt DELPHI4 själv om
man vill införa ytterligare FORMytor i projektet: DELPHI4 tillordnar då
automatiskt Form2 med Unit2, Form3 med Unit3, osv. Det finns ingen anledning
att bryta tillfället att utnyttjade den enkla självserveringen.
Alt+F, New ..., Unit, Enter
resulterar i att DELPHI4 lägger ut ett nytt kodfönster som ser ut så:
Vad DELPHI4 lägger till
automatiskt vid införd ny enhet.
Inget mer. Inget mindre.
— Kompilera direkt med Ctrl+F9, och kör sedan med F9:
DELPHI4 lägger nu DIREKT som första händelse
ut en dialogbox:
Notera att DELPHI4 ovanstående dialog INTE kommer upp MED
KATALOGEN MARKERAD SAMMA SOM DET SENAST ÖPPNADE PROJEKTET utan det senaste sparade projektet.
Är man inte
uppmärksam på det — man tror (utan att direkt läsa
dialogens detaljer) att »sparkatalogen är samma som projektkatalogen» — kan ett ENTER resultera i att den
nya enheten sparas på helt fel plats. I så fall: Bläddra fram till aktuell
projektkatalog och spara om, och gå sedan till felkatalogen och radera
felsparfilen därifrån manuellt.
— Ändra namnet ”Unit2” till ”Unit1A”,
sedan Enter.
— Avsluta sedan P2 (Alt+F4).
Vi ska nu PREPARERA den nya Enheten Unit1A
och göra den direkt KODKOMPATIBEL med Unit1 (samt sedan, vidare ev. övriga
Units).
— För att göra det behöver vi göra olika
tillägg (Här markerade särskilt med ljusgult och orange text). Dessa finns
sammanställda nedan med inlagda förklaringsblock som rubricerar de olika
partierna.
För särskild förklaring, se sammanställning i UnitRubrikerna.
Hela blocket med enheter i uses nedan är samtliga de (främsta) som
behövs (min erfarenhet) för att kunna koda DELPHI4 optimalt. Testa att ta bort
de som inte behövs: Om någon enhet tas bort som behövs, meddelar DELPHI det
(går inte att kompilera, då).
— Procedure ExecuteHRV har här lagts in som inledande exempel på
hur procedurer ska deklareras i en separat Unit i DELPHI4.
Elementär flytbildsteknik — grundexempel i DELPHI4
Den nydöpta enheten
Unit1A..
unit Unit1A;
{Unit1A|12Sep2014|BildHanteringsRutiner|TillUnit1.}
interface
uses
Windows, Messages, SysUtils, WinTypes, WinProcs,
Classes, Graphics, Forms, Dialogs, StdCtrls,
FileCtrl,ExtCtrls, Controls, ShellAPI,
Math, Clipbrd, ComCtrls;
{GlobalVARIABLES|Constants
.....................................:}
{GlobalVARIABLES|Constants
......................................}
{GlobalPROCEDURES
& Functions — GlobalDeclarations .............:}
Procedure ExecuteHRV(SourceIm: TImage; Key: Word);
{GlobalPROCEDURES
& Functions — GlobalDeclarations ..............}
implementation
uses
Unit1;
{MOTSVARANDE
»uses Unit1A» måste tillfogas på Unit1 antingen
1.
i |uses| direkt efter |interface| LÄNGST UPP — om detaljer som står
explicit
under Unit1:s Interface används, eller
2.
som närmast ovan i Unit1-makens Implementation|Uses.
—
Se dessa detaljer utförligt i DELPHI4help,
Circular
unit references: regeln är att Unit:s inte får referera
varandra
i samma uses-block|Delphi vägrar kompilera då.}
{LocalVARIABLES|Constants
......................................:}
{LocalVARIABLES|Constants
.......................................}
{ActualPROCEDURES
& Functions - - - - - - - - - - - - - - - - - :}
Procedure ExecuteHRV(SourceIm: TImage; Key: Word);
begin
exit;
end;
{ActualPROCEDURES
& Functions - - - - - - - - - - - - - - - - - .}
end.
Motsvarande uses Unit1A på Unit1 införs
ENKLAST OCH KONSEKVENT ALLTID (alternativet i 1 ovan) längst upp enligt
— Importera ovanstående tillägg, och
VERIFIERA med kompilering Ctrl+F9 och körning F9:
— Projektet P2 är nu färdigt att använda den
nya enheten med full pedal.
Lägg märke till följande:
— olikheten i Unit1A mot Unit1 i
GlobalaLokalaProcedurDeklarationer:
OM vi —som i Unit1 som HAR en egen Form1 där
alla Globalt deklarerade ImplementationProcedurNamn MÅSTE börja med ”TForm1.” — testar att
deklarera ImplementationProceduren ovan på formen
Procedure TForm1.ExecuteHRV(SourceIm:
TImage; Key: Word);
vägrar DELPHI4 att kompilera med
upplysningen
”
[Error] Unit1A.pas(30): ';' expected but '.'
found
[Error] Unit1A.pas(13):
Unsatisfied forward or external declaration: 'ExecuteHRV'
[Fatal Error] P2.dpr(6): Could not compile
used unit 'Unit1A.pas'
”
— Tryck TAB (eller
klicka på kodfönstret) för att komma tillbaka till kodfönstret sedan Meddelandefönstret
klickats av,
Alltså:
— I den separata Unit-enheten (här Unit1A
som ovan):
— Utelämna den inledande typen ”TForm1.” från alla
procedurNamn;
— För att kunna ANVÄNDA Form1-komponenterna
SOM OM UNIT1A NU VORE EN INTEGRERAD DEL AV UNIT1, börja ALLTID varje procedur i
begin med exemplifierat
Procedure ExecuteHRV(SourceIm: TImage; Key: Word);
begin with
Form1 do
begin
exit;
end;{endWithForm1}
end;{endExecuteHRV}
Då fungerar det utmärkt.
— Skriv sedan alla variabler i Unit1A — SOM SKA KUNNA
LÄSAS AV OCKSÅ Unit1 — längst upp i det anvisade blocket ovan [GlobalVariables].
— Alternativt, för enstaka förekomster, om
inte ”with Form1 do begin” används, måste varje Form1-komponents användning i
Unit1A inledas med ett ”Form1.”,
t.ex. Form1.Label1.Caption:= ..
.
FÖRUTSATT att nu en viss procedur är
deklarerad Globalt i Unit1A, kan den nås OMEDELBART från Unit1 med
direktkommandot, här exemplifierat (t.ex. från FormKeyDown),
ExecuteHRV(Image2,Key);
Det är allt.
— På samma sätt kan Unit1A använda och
utnyttja alla globalt deklarerade procedurer i Unit1 med samma typ av enkla
anrop, t.ex. BitMapRect(R,B); förutsatt R och B känns igen internt i Unit1A,
eller kopplar globalt för alla.
Alla föregående
ev. deklarerade lokala globaler i Unit 1 (under Implementation) och som nu
kommer att användas av Unit1A måste vi flytta upp i GlobalSektionen (efter Uses
under Interface) Unit1, annars syns de inte för Unit1A. Vi förutsätter här den
operationen bekant och anger den inte vidare i framställningen: DELPHI4 säger i
vilket fall till om vi glömt något.
OK. Då kan vi börja resan in till det verkliga äventyret.
StreckRektangeln, markeringar för uttag
Elementär flytbildsteknik — grundexempel i DELPHI4
Streckrektangeln
Första åtgärden, vidareutvecklingen av
Projekt P2.
— Vi fortsätter att hålla oss ett tag till i
Unit1.
Utan ett verktyg — streckrektangel — som kan
markera eller ta ut önskade partier för olika ändamål — kopiera, duplicera,
radera, vända, rotera, invertera — är det ELEMENTÄRA flytbildsprogrammet
fortfarande bara ett halvdant dito.
Hur DELPHI4-kodar man en streckrektangel —
vars bildyta sedan kan användas för olika bildhanteringsändamål?
På Image1MouseDown (Image1 Object Inspector F11, OnMouseDown, Ctrl+Enter)
skriver vi in koden (globala variabler Xm0,Ym0,Xm1,Ym1: Integer;)
if (Button=mbLeft)then
begin
Image1.Cursor:= crArrow;
Image1.Canvas.Pen.Width:= 1;
SCRIm1.TopLeft:=Image1.ClientOrigin;
SCRIm1.BottomRight:= Point(
Image1.ClientOrigin.X +
Image1.ClientWidth+1,
Image1.ClientOrigin.Y +
Image1.ClientHeight+1 );
{INITIERAR
STRECKREKTANGELN:}
Image1.Canvas.Rectangle(Xm0,Ym0,Xm1,Ym1);
{Raderar
föregående, XOR-styrd|Här markeras startpunkten:}
Xm0:=X; Ym0:=Y;
Xm1:=X; Ym1:=Y;
end;{endIfButtonLeft}
{Om man sätter koordinatblocket på denna
plats,}
{Xm0:=X; Ym0:=Y;
Xm1:=X; Ym1:=Y;}
{konserveras streckrektangeln med
högerklick,
den kan sedan inte klickas bort.}
På Image1MouseMove verkställs
motsvarande
//Screen.Cursor:=
MC1
{STRECKREKTANGELN:}
with Image1.Canvas do begin
Brush.Color:=clWhite;
with
Pen do
begin
Color:= 0;
Style:= psDot;
Mode:= pmNotXor;
end;
if(Shift=[ssLeft])and(PtInRect(SCRIm1,CursP)=True)then
begin
{RADERAR
GAMLA:}
Rectangle(Xm0,Ym0,Xm1,Ym1);
{RitarNya:}
Rectangle(Xm0,Ym0,X,Y);
Xm1:=X; Ym1:=Y;
end;
end;{endWithIm1Canvas}
Variablerna X|Y|m0|1 och CursP är speciella
och kan deklareras i Unit1 som lokala (i ImplementationBlocket)
var
CursP: TPoint;
Xm0,Xm1,Ym0,Ym1: Integer; {MarkRectMouseMove}
Vi kontrollerar att streckrektangeln
fungerar (Peken nedan förminskad kopia av originalet för att inte
distrahera|sammanblanda med normalpeken):
Perfekt funktion.
— Men Peken kan flyttas
utanför fönsterkanterna, medan streckrektangeln begränsas av bildytan (Image1).
— Hur löser vi det?
EMELLERTID:
— Streckrektangeln, men inte Peken, håller
sig inom Image1-ytan med MusVä nedtryckt: Peken kan obehindrat flyttas ut
utanför det aktuella avgränsade MÖJLIGA streckrektangelområdet.
Vi
skulle vilja att Peken stannar inom Image1-området, oberoende av vidare musrörelser.
Elementär flytbildsteknik — grundexempel i DELPHI4
ClipCursor
Peken stannar inom
Image1-området så länge MusVänster hålls nedtryckt,
oberoende av
vidare musrörelser
Funktionen för det finns särskilt i Windows
API och heter ClipCursor.
— VARNING:
— Följande DELPHI4-kod är
utformad, testat, prövad och fungerar oklanderligt:
— Vill du försöka själv att testa med ClipCursorFunktionen — den
är WindowsSystemBaserad, vilket innebär att den är en DeladResurs för alla
WindowsProgram:
— missar man något i kod här, kommer datorns muspekarfunktion garanterat att låsa sig, garanterat.
Enda
sättet i så fall: dra ur pluggen: starta om datorn.
— OM du vill testa DELPHI4 på det sättet,
FÖRBERED DIG:
— se först till att ha typ
AKTIVITETSHANTERAREN öppen, för säkerhets skull, eller annat möjligt
TANGENTTILLGÄNGLIGT hjälpfönster som kan nås och på den vägen ev. starta om
datorn.
— Är du det minsta tveksam till den typen av
Test: avstå.
Här är DELPHI4-koden som får ClipCursor att
fungera perfekt:
1.
En global Pointer-rektangel deklareras på
Unit1: PR: PRect;
En global Sim1-rektangel deklareras på
Unit1: Sim1: TRect;
En global SCRIm1-rektangel finns här redan insatt från tidigare;
Försöker man
deklarera alla de 3 ClipCursor-variabler som ingår — SCRIm1, Sim1, PR — i skilda sektioner lokalt och globalt ger DELPHI4
meddelandet vid försök att kompilera Ctrl+F9 (här Sim1 separat lokalt),
”[Hint] Unit1.pas(98): Variable 'Sim1' is declared
but
never used in 'Unit1'”.
Det är den visst det. Men ...
— »Never used» —
Trots att Koden (3 nedan) på MouseUp använder just Sim1.
Flyttas alla tre ingående variablerna till samma variabelsektion upphör mysterierna.
— Vi väljer här
att sätta dem globalt, vilket ger snabbast möjliga åtkomst i alla lägen.
2.
På Image1MouseDown lägger vi till koden
GetMem(PR,
SizeOf(Sim1));
PR^:=
SCRIm1;
Screen.Cursor:= crDefault;
ClipCursor(PR);
3.
På Image1MouseUp (Image1 Object
Inspector F11, OnMouseUp, Ctrl+Enter) verkställs den slutliga operationen i kod
som avslutar ClipCursorSessionen:
if
Button=mbLeft then begin
FreeMem(PR,SizeOf(Sim1));
PR:= nil;
ClipCursor(PR);
CurFlag:=0;
UpdateInsertFlag;
end;
Ovanstående insatt ska fungera oklanderligt,
från första stund.
— Vi återkommer senare till CurFlag
(deklarerad Curflag: Integer;) och UpdateInsertFlag.
Nu stannar Peken kvar inom Image1-ytan så
länge MusVä hålls nedtryckt.
— Klick på bildytan tar bort rektangeln
Elementär flytbildsteknik — grundexempel i DELPHI4
Städkod för
streckrektangel
Vi behöver säkra ev. rester om vi ångrar
initieringen eller bara vill ta bort streckrektangeln utan att göra något, utom
att klicka av den med MusVäKlick förstås.
— Koden nedan införd på FormKeyDown med DELS
Escape-tangenten och DELS på F2 (Rensa hela bildytan):
VK_ESCAPE:begin
if Xm0<>Xm1
then
{StreckRektangel finns:}
begin
Image1.Canvas.Rectangle(Xm0,Ym0,Xm1,Ym1);
Xm0:=Xm1;
Ym0:=Ym1;
CurFlag:= 0;
UpdateInsertFlag;
end;
end;{endEscape}
— Vi återkommer senare till CurFlag och delproceduren UpdateInsertFlag.
Streckrektangeln dras med XNor-funktion (påverkar inte övrigt
bildunderlag). Vilket betyder att om en XNor-rit finns kvar vi bara behöver
upprepa den en gång till (på samma koordinater som sist) för att få bort den.
Tillägget på VK_F2 för att säkra att streckrektangeln inte kommer
tillbaka vid nästa MusVäKlick:
{NOLLSTÄLL INSÄTTNINGSPUNKTER FÖLR
FLYTBILD:}
X0:=0;
Y0:=0;
{NOLLSTÄLL STRECKREKTANGEL:}
Xm0:=Xm1;
Ym0:=Ym1;
Streckrektangeln, Synkronisering
Elementär flytbildsteknik — grundexempel i DELPHI4
Streckrektangelns
SYNKRONISERING
Ytterligare en detalj krävs för att
streckrektangeln ska fungera — utan att DELPHI4 pajar ihop — MED SÄKRADE
MUSDRAGNINGSMÅTT:
Delphi pajar ihop helt
och hållet om Left/Top blir mindre än
Right/Bottom — på
CopyRect-funktionen. Med
Rectangle-funktionen har
det aldrig funnits
några sådana problem.
Med alla möjliga SÄTT att dra streckrektangeln uppkommer, strax,
möjligheten att få NEGATIVA KOORDINATVÄRDEN i bestämningen av början och
slutpunkter: vi vill definitivt inte ha sådana. Delphiprogrammet kraschar då.
— Streckrektangeln måste under alla
omständigheter kunna redovisa EN ENTYDIGT DEFINIERAD
LeftTopRightBottom-rektangel i slutänden som anvisar arbetsytan för samtliga
möjliga efterföljande operationer.
Så här ser den väl beprövade säkringen för synkronisering av
streckrektangelns fyra koordinater ut:
{Allmänna
villkor · Endast om streckrektangel finns:}
X:=0; Y:=0; X1:=0; Y1:=0;
if (Xm0<>Xm1)and(Ym0<>Ym1)
then
begin
if Xm1>Xm0 then begin
X:= Xm0; X1:=Xm1; end;
if Xm0>Xm1 then begin
X1:=Xm0+1; X:= Xm1; end;
if Ym1>Ym0 then begin
Y:= Ym0; Y1:=Ym1; end;
if Ym0>Ym1 then begin
Y1:=Ym0+1; Y:= Ym1; end;
{Gäller
samtliga fall|HIMRV:}
{Slutrektangeln|OPERATIVA
STRECKREKTANGELN|LeftTopRightBottom:}
Rekt:=
Rect(X,Y,X1,Y1);
{Denna
sista rad tar bort streckrektangeln:}
Image1.Canvas.Rectangle(Xm0,Ym0,Xm1,Ym1);
{AnnarsÅterEfterAvslutMedMusVäNer:}
Xm0:=Xm1; Ym0:=Ym1;
...
end;
Elementär flytbildsteknik — grundexempel i DELPHI4
CurFlag och
UpdateInsertFlag
Har du märkt (ibland — speciellt omkring
”eran” Windows XP) det här:
— Man prickar in (manuellt) stället man vill
börja dra eller göra en marking med en streckrektangel för att ta ut något
parti.
— I samma ögonblick man trycker ner vänster
musknapp inträffar följande Roliga Tilltag:
den surt förvärvade Pekpositionen HOPPAR
(flera pixels) till någon ny Intern Position — på grund av att den snabba
datorn med den känsliga musplattan hinner uppfatta smärre mikrorörelser med
handen innan Klicket kopplar.
Ajö med den precisionen.
Här är Boten:
— Placera Peken, Tryck INSERT där
insättningspunkten önskas: insättningspunkten SPARAS.
1: 2: 3: 4:
1: Insert No1 vid Peken:
— Bottenpanelen (Panel2)
skjuts 24 pixels åt höger för att ge plats för en grön InsertFlagga:
Koordinaterna vid Insert No1 sparas och står kvar i den svarta X;Y.displayen:
Peken kan röras fritt.
2: När sedan Musknapp
vänster trycks ner, hoppar Peken till den sparade insättningspunkten, och
Streckrektangeln kan nu börja dras:
— Manuellt eller/och med
piltangenterna kan även en slutposition bestämmas exakt med en Insert No2:
3: Insert No2 frikopplar
Peken från streckrektangeln och lägger in en motsvarande KlarFlagga. Med
fortsatt MusVä nedtryckt kan Peken flyttas oberoende av streckrektangeln.
Kopplingen har upphört.
4: Streckrektangeln raderas
först med ett nästa MusVäKlick, ett Esc eller i samband med (kommande)
operationer på den markerade bildytan. Bottenpanelen (Panel2) skjuts tillbaka i
normalläge
— Naturligtvis finns
också det vanliga klassiska normala KlickaMusVänsterDirekt-alternativet kvar.
— Musen kan sedan röras fritt (tryck ESCape
om Ångra):
— Så snart MusVä trycks ner HOPPAR Peken DIT
Insert sattes och streckrektangeln kan nu dras med perfekt exakt precision.
— En andra INSERT No2 (om så önskas)
frikopplar Peken HELT från streckrektangeln VID Insertpositionen.
— Därmed är exakta positioner vid Insert1o2
garanterade.
Ofta förekommande (min erfarenhet):
— HOME Insert, nyligen intaget (något objekt
via Ctrl+V). Peken till LeftTop med insättningspunkten 0;0 preparerad.
Superfint.
Projektet P2, så långt [12Sep2014]
Den nuvarande 11Sep2014
(från 4Sep) samlingen filer i projektkatalogen för P2.
Streckrektangeln, FlaggIkonerna
Elementär flytbildsteknik — grundexempel i DELPHI4
Flaggikonerna
Flaggikonerna finns sparade som bmp-filer i
projektkatalogen som respektive
FLAGUP.BMP och FLAG.BMP.
— Koden i DELPHI4 som verkställer helheten
ovan lyder:
Image1MouseDown:
if (Button=mbLeft)then
begin
Image1.Canvas.Pen.Width:= 1;
Image1.Cursor:= crArrow;
Screen.Cursor:= crArrow;
{omINSÄTTNINGSFLAGGA
VIA KEY INSERT:}
if CurFlag=1
then
begin
SetCursorPos(CurP.X,CurP.Y);
CurP:= Image1.ScreenToClient(CurP);
X:= CurP.X; Y:=CurP.Y;
CurFlag:=0;
UpdateInsertFlag;
end;
{UPPDATERA
KOORDINATER:}
SCRIm1.TopLeft:=Image1.ClientOrigin;
SCRIm1.BottomRight:= Point(
Image1.ClientOrigin.X +
Image1.ClientWidth+1,
Image1.ClientOrigin.Y +
Image1.ClientHeight+1 );
{CLIPcURSOR:}
GetMem(PR, SizeOf(Sim1));
PR^:= SCRIm1;
Screen.Cursor:=
crDefault;
ClipCursor(PR);
{INITIERAR
STRECKREKTANGELN:}
Image1.Canvas.Rectangle(Xm0,Ym0,Xm1,Ym1);
{Raderar
föregående, XOR-styrd|Här markeras startpunkten:}
Xm0:=X; Ym0:=Y;
Xm1:=X; Ym1:=Y;
...
Image1MouseMove:
{FrikopplarPeken
från Streckrektangeln om InsertNo2:}
if
CurFlag=1 then exit;
...
{LeftMouseBUTTON:}
if Shift=[ssLeft]
then
begin
Screen.Cursor:= crArrow;
{STRECKREKTANGELN:}
with Image1.Canvas do begin
Brush.Color:=clWhite;
with Pen do begin
Color:= 0;
Style:= psDot;
Mode:= pmNotXor;
end;
if(Shift=[ssLeft])and(PtInRect(SCRIm1,CursP)=True)then
begin
{RADERAR
GAMLA:} Rectangle(Xm0,Ym0,Xm1,Ym1);
{RitarNya:}
Rectangle(Xm0,Ym0,X,Y);
Xm1:=X; Ym1:=Y;
end;
end;{endWithIm1Canvas}
end else Screen.Cursor:= MC1;
Image1MouseUp:
if
Button=mbLeft then begin
FreeMem(PR,SizeOf(Sim1));
PR:= nil;
ClipCursor(PR);
CurFlag:=0;
UpdateInsertFlag;
end;
UpdateInsertFlag — separat globalt
deklarerad procedur på nyinrättade Unit1A:
Procedure UpdateInsertFlag;
var
B: TBitMap;
S: string;
R: TRect;
begin with Form1 do begin
R:= Bounds(0,Height-25-23,23,21);
{CurFlag=0:}
if
CurFlag=0 then
{DeleteKey:}
begin
Canvas.Brush.Color:=
clBtnFace;
Canvas.FillRect(R);
Panel2.Left:= 0;
GetCursorPos(CurP);
{Action to update Panel4Coordinates:}
SetCursorPos(CurP.X+1,CurP.Y);
SetCursorPos(CurP.X,CurP.Y);
end{endCurFlag=0}
else
{CurFlag=1:}
begin
{MouseLeftIsDown:}
if GetKeyState(VK_LBUTTON)<=-127
then
S:='FLAGUP.BMP' else S:='FLAG.BMP';
if not FileExists(S)
then
begin
Label1.Caption:='Flag*.bmp·NotFound';
exit;
end;
B:= TBitmap.Create;
try
B.LoadFromFile(S);
//B.Transparent:= True;
//B.TransparentColor:=
clWhite;
Panel2.Left:= 24;
Canvas.Brush.Color:=
clWhite;
Canvas.FillRect(R);
Canvas.Draw(5,Height-23-23,B);
finally
B.Free;
end;
end;{endCurFlag=1}
end;{endWithForm1}
end;
{endUpdateInsertFlag}
Används Transparensen för BitMap B (avställt ovan med //) ritas flaggikonerna
direkt som fristående figurer utan deras bildrektangels täckning på den ljusgrå
Form1-ytan.
Elementär flytbildsteknik — grundexempel i DELPHI4
Allmän kommentar
kodrelaterad
PROGRAMDIVERGENS
KODBLOCKEN OVAN I SAMARBETE — MouseDown|Move|Up
— är ett utmärkt exempel på den PROGRAMDIVERGENS vi aldrig kommer ifrån i all
(avancerad) programmering:
— Vi kan OMÖJLIGEN ha »allt samlat på samma
ställe»:
Alla procedurer vi
framställer innehåller FICKOR som man kan »stoppa in» vissa nya funktioner i:
— Det blir en FRESTELSE
TILL UTMANING — som i värsta fall resulterar i en veritabel »myrstack» av
instoppade kodavsnitt som bara i efterhand kan begripas ENDAST med STOR
svårighet — speciellt av den som satt ihop påtet.
— Med NOGGRANNA KOMMENTARER
OCH FÖRKLARINGAR KAN en sådan »myrstack» förvandlas till rena gudomliga
Romanen, förutsatt TID att beskriva allt i detalj.
Foto: 27Aug2014 Bild11
E18
En liten sjö håller på att växa igen — supervarma somrar. Bara
för några få år sedan, helt öppen. Nu alltmer fylld av bottenuppväxande gräs
och näckrosväxter.
Det finns ALLTID en stam, ett rotverk, och över det ett grenverk med BLAD längst ut: allt åtskilt av
OBÖNHÖRLIG distans.
— »Distansen mellan kodblocken» ÄR
utmaningen i datorprogrammering:
— RÄTT ansats ger programmeringen som helhet
en tendens att vara KONVERGENT: satsbilder, kopplingar, anslutningar, fungerar
som ett TRÄD: samlat, snyggt, oerhört ändamålsenligt.
— ASSOCIATIVT leder den typen till FOKUS.
— »FEL ansats» ger DIVERGENTA flöden: ju
mera man lägger till, desto mer OBEGRIPLIG, svårhanterlig, OFOKUSERAD och
obändigt KOMPLICERAD blir helheten: »Trädet» blir snarare en »odefinierad
Explosion» — i utveckling. Domaren är du, och jag. (»Nej, det här går inte
..»).
KODORGANISATION SOM
MOTVERKAR DIVERGENT PROGRAMMERING — exempel
Speciellt bilder (Image) och paneler (Panel)
är i alla datorprogram föremål för olika åtkomstmanövrer:
1. KlickaPå
2. MusRörelserÖver
3. MustangenterHögerVänster|NerUpp
4. Mushjul
Vi kan i DELPHI4 FÖR VARJE ENSKILD KOMPONENT
(som har dessa egenskaper) skapa särskilda direkt DELPHI4-genererade procedurer
genom Object Inspector (F11, den komponenten), markera aktuell händelseform,
och trycka Ctrl+Enter. DELPHI4 lägger då automatiskt in startfrasen för den proceduren,
och vi behöver bara fylla i ev. variabler över begin och sedan skriva
verkställande programkod mellan begin och end.
Hur DELPHI4 initierar en komponentprocedur
procedure TForm1.FormClick(Sender: TObject);
begin
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X,
Y: Integer);
begin
end;
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
end;
...
Om komponenternas antal tenderar att bli av
typen större, får (min erfarenhet och mening) dessa separata procedurblock en
tendens att just uppvisa DIVERGENS i programmeringen.
— Nämligen med följande jämförande
alternativ:
— Vi använder för SAMTLIGA MouseKlick-MouseDown-MouseMove-MouseUp ETT
OCH SAMMA procedurblock. Nämligen det som gäller för programfönstrets Form(MouseKlick-MouseDown-MouseMove-MouseUp).
SJÄLVA ANLEDNINGEN bakom DET alternativet
(enligt min erfarenhet):
— EN VISS KOMPONENT — som också ibland kan
LÅNAS/delas mellan olika programavsnitt — tenderar (allt eftersom programmet växer i kod) att hamna i ett
programflöde som INTE DIREKT kopplar till Form1|Unit1 — typ separat RitProgram,
separat Grafprogram, separat BildHantering (Unit1A),
separata Specialrutiner särskilt (Unit1B),
separat FärgAnalys(Unit1C) ... : separat insatta Unit:s för att skilja programavsnitten
åt, att göra kodläsning, redigering och utveckling maximalt överskådlig —
alltid med noggrant utformade kommentarer och förklaringar.
— Nämligen just UTSTRÄCKNINGEN av dessa
antydda individuella specialprocedurer (och sedan i sin tur deras förgreningar,
om alls):
— Unit1-procedurerna
TENDERAR nämligen att bli långdragna KodAvhandlingar i takt med att
programmet (och dess oerhörda
DELPHI4-potential upptäcks, och därmed) utvecklas, om man helt villkorslöst
OCH ÖVERALLT följer den enkla DELPH4-ordningen exemplifierad ovan:
— Man får leta — hoppa
omkring
inom långa kodavsnitt VILKET SAMTIDIGT TAR FOKUS FRÅN mera viktiga AKTUELLA VIKTIGA PROGRAMKONCEPT under utformning.
— Nämligen det som alla som programmerat
något redan möjligen upptäckt: mängden UPPSLAG i programmering i löpande associativ takt under arbetets fortlöpande
är ENORM: för att MATCHA den associativa tankeströmmen UTAN ATT STÖRAS är det
avgörande viktigt att MELLANLIGGANDE EFTERSÖK INTE FÅR TA FÖR LÅNG TID, för då
TAPPAR MAN TRÅDEN, speciellt om uppslaget man har i sin tanke är av typen MERA
KOMPLICERAT. Det har ingenting med ÅLDERN att göra (min erfarenhet). Det
handlar om FÖRMÅGAN ATT HÅLLA X BOLLAR I ORDNAD RÖRELSE I LUFTEN
SAMTIDIGT.
— Ett samlad programkoncept gör sådana utflykter med uppslag till en ren NJUTNING.
Ligger däremot koden man letar efter utspridd på många olika ställen, hinner
man tappa suget innan något kopplar: man glömmer plötsligt av vad det var man
skulle leta efter. Jag har observerat det fenomenet ända från mina barnsben upp
till nu (2014). Och det är ALLTID på samma sätt: har för många bollar i luften
samtidigt.
Det man missade, som man tänkte på, KOMMER ALLTID UNDANTAGSLÖST TILLBAKA
— OM man praktiserar följande enkla recept: Ta en paus. Stäng av datorn. Koppla
av. Förr eller senare »knackar det på dörrn». Håll bara ut med avkopplingen,
hetsa inte. Säkert som amen i kyrkan.
Hur gör man då i DELPHI4 för att säkra en
»MERA fokuserad» programordning?
För att effektivt motverka en klart
divergent programbild — olika programavsnitt
man HELST vill se i ett SAMLADT kodblock, inte med utspridda kopplingar på
olika ställen — behöver vi ett DISTRIBUTIONSNAV — ett distributionscenter — i varje typ Form(MouseKlick-MouseDown-MouseMove-MouseUp).
Vi behöver också ett sådant särskilt på det avgörande FormKeyDown för att kunna säkra avgränsade
programdomäner och deras privata KeyDown-rutiner.
— ALTERNATIVET är att KeyDown-rutinerna —
som var tänkta att leda till de olika avsnitten genom KORTA kommandon —
tenderar att bli veritabla villkorsAvhandlingar — långa, dryga kodavsnitt med
specialvariabler för att gardera och säkra — med allt växande svårighet i
GEMENSAM ÖVERSIKT.
Exempel som
introducerar typen »distributionsnav» — F1
I Projektet P2 — elementär
flytbildshantering — vill vi SOM TILLÄMPNINGSEXEMPEL [se speciellt Punkt5 nedan] mötas av det
här när programmet startar upp:
— Ett INTRODUKTIONSinfo som inte stör den normala tangentåtkomsten:
·
Vänsterklick på introbilden öppar upp ett htm-dokument med
programHjälp;
— En P2Help.htm-fil finns preparerad i en separat underkatalog Help som skapats
särskilt för ändamålet,
,
— Separat tangent F1 leder också dit, FormKeyDown.
·
Valfri tangent (utom PrtScn) tar bort introbilden;
·
När introbilden försvinner framträder en liten I-panel nederst
höger,
den fungerar som KlickIkon (med en Hint, ”Key § ¦ InfoP2”) för att få IntroBilden
åter. Klickar man på den (eller använder tangent §) kommer infobilden åter och
i-panelen försvinner. Osv.
Infobilden som sådan kan utvecklas (mycket)
avancerat med indelning i olika bildrektanglar (åtkomst via MouseMove): interna
understrukturer: Högerklick kan t.ex. användas för att bläddra bland
inforemsorna = programbeskrivningar på komprimerad kortform — och vänsterklick
för motsvarande direkt åtkomst till separat htm-dokument som beskriver
innehållet mera i detalj.
Vi
ska (i varje fall ännu) inte avhandla den möjligheten här, bara omnämner
möjligheten.
ÖppnaHELPhtm
Välkomstbild med HELPinfo
Panel11|Image4
Komponenter och kod i DELPHI4 som realiserar
ovanstående — öppna HELP-htm:
1. En ny Panel11 med en ny bild Image4 bildar en enhetlig
komponentgrund (Enklast: kopiera Panel1 med Image1: håll
MusVä nere och dra streckrektangel över bägge Pan1Im1, släpp upp, Ctrl+C,
klicka sedan på Form1 och ta in med Ctrl+V: ändra egenskaper separat):
Med Image4 täckande över Panel11 för att komma
åt Panel11Markering: Klicka på Image4, tryck ESCape.
Egenskaperna
(övriga orörda) för Panel11 på Object Inspector:
Visible True(alltid); Width 50; Height 50; HändelseKopplingarna:
OnClick FormClick; OnMouseMove FormMouseMove;
Egenskaperna för
Image4 (nu Parent= Panel11) på Object Inspector:
AutoSize True; Visible False; Width 50; Height 50 (efter
AlClient, AlNone);
Visible True(alltid); Width 50; Height 50;
Dessa justeras
sedan senare separat i vilket fall via kod; HändelseKopplingarna:
OnMouseDown FormMouseDown; OnMouseMove FormMouseMove;
2. Vi lägger till en global IntroP2: Bool; på Unit 1 — vi behöver
den här egentligen inte, då användningen av Image4 som Show eller Hide kommer
att fylla samma funktion; IntroP2 ger bara en starkare rent beskrivande
indikering;
3. Vi introducerar en
ny enhet Unit1B — se Unit1A hur det går till i
detalj — med rubriken
unit
Unit1B;
{Unit1B
— SpecialProcessing|13Sep2014}
med en första global procedur Pan11:
{INTRO
— Pan11|Image4|Key§: — anropas först från FormCreate:}
Procedure Pan11;
var
S: string;
begin with Form1 do begin
{INTRODUKTIONSBILD
med htm-hänvisning|11Sep2014:}
S:= 'IntroP2.bmp';
if not FileExists(S)then exit;
{SHOWinitialization|Im4HiddenFromStart|Pan11AlwaysVisible:}
if not
Image4.Visible then
begin
Panel11.Parent:= Form1;
Panel11.Anchors:= [];
Panel11.Caption:= '';
Panel11.ShowHint:= False;
Panel11.BringToFront;
Image4.Picture.LoadFromFile(S);
Panel11.BoundsRect:=
Bounds(0,0,Image4.Width+1,Image4.Height+1);
{Centrerat:}
Panel11.Top:=
Panel1.Top + (Image1.Height -
Panel11.Height)div 2;
Panel11.Left:=Panel1.Left +
(Image1.Width - Panel11.Width )div 2;
Image4.Show;
IntroP2:= True;
exit;
end;{endIfInfoP2Visible}
{ShowAs|i-Button|TopRight|AnyKeyDownFromUnit1—UnlessExceptionS:}
{AfterAnyKeyDown|Unit1:}
if Image4.Visible
then
begin
Image4.Hide;
IntroP2:= False;
with Panel11
do
begin
Parent:= Panel2;
BoundsRect:=
Bounds(Panel2.Width-16-2-2,1,18,17);
Anchors:=
[akRight,akBottom];
ShowHint:= True;
Hint:= 'Key § ¦ InfoP2';
Font.Size:= 12;
Font.Style:= [fsBold];
Font.Color:= clWhite;
Font.Name:= 'Times New
Roman';
Color:= RGB(0,149,255);
Caption:= 'i';
end;
end;{endIfInfoP2iButton}
end;{endwITHfORM1}
end;{ENDpAN11}
VINSTEN FRÄMST ÄR ATT VI SLIPPER HA DEN OVAN
(och alla liknande) SPECIELLA SEPARATA PROCEDURMANGLINGEN »skräpande» i UNIT 1.
Rent, prydligt, snyggt.
4. På FormCreate
skriver vi sedan in (sist) det enkla, förlösande:
{INTRODUKTIONSBILD
med htm-hänvisning|11Sep2014: — IntroP2|Unit1B:}
Pan11;
Därmed tar startexekveringen automatisk
vägen över till Unit1B, Pan11Proceduren ovan, och laddar in IntroBilden.
— Introbilden som sådan (IntroP2.bmp) finns inlagd separat i projektkatalogen;
Panel11.måtten anpassas som ovan automatiskt till den bildens mått.
5. På FormKeyDown
skrivs nu SOM TILLÄMPNINGSEXEMPEL motsvarande DISTRIBUTION:
{INTRODUKTIONSinfo|Unit1B:}
if IntroP2
then
Pan11 else
if
Key=Ord(220) then Pan11;
{Ord220=Key|§|Paragraph|StartUpProgramItems|Unit1B.}
Slutligen skriver vi först in
HÄNDELSEKOPPLINGARNA via procedurerna på Form1 och sedan proceduren för
htm-dokumentens öppning:
— Vi inrättar först speciella allmänna
DISTRIBUTIONSNAV i händelseprocedurerna OnClick|OnMouseDown|OnMouseMove, här
inledningsvis för Pan11|Im4, och senare på enklare sätt för alla ytterligare:
{GENERAL|MouseClick|14Sep2014:}
procedure TForm1.FormClick(Sender: TObject);
begin
{FÖRDELNINGSNAV
FÖR FLERA MouseClick-KOMPONENTER:}
if Sender
as
TObject <> Form1 then
begin
{Pan11|Unit1B:}
if Sender
= Panel11 then begin
Pan11;
exit;
end;{endPan11|Unit1B:}
end;
{FÖRDELNINGSNAV
FÖR FLERA MouseClick-KOMPONENTER.}
//exit;
Label1.Caption:=
ExtractFilePath(Application.ExeName);
ClipBoard.AsText:= Label1.Caption;
end;{endFormClick}
{GENERAL|MouseDown|14Sep2014:}
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
{FÖRDELNINGSNAV
FÖR FLERA MouseDown-KOMPONENTER:}
if Sender
as TObject <> Form1 then
begin
if
Sender = Image4 then
begin
if IntroP2
and(Button = mbLeft)then
OpenHtmHelp('P2Help.htm','');
exit;
end;{endIfIm4|LBdown|OpenHtmHelp|Unit1B}
end;
{FÖRDELNINGSNAV
FÖR FLERA MouseDown-KOMPONENTER.}
end;{endForm1MouseDown}
{GENERAL|MouseMove|14Sep2014:}
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Screen.Cursor:= crArrow;
end;{endForm1MouseMove}
Vinsten med
ovanstående allmänna organisation är att man får EN ENDA ENHETLIG procedur för
En Viss Händelse för alla möjliga komponenter — att jämföra med
alternativet en särskild händelseprocedur för varje komponent, och som
resulterar i motsvarande mängd utspridda procedurer — ofta på inbördes vitt
skilda ställen i Unit:en, och därmed svåröverskådligt.
— Missar vi {FÖRKLARINGSPARENTESERNA} blir det för övrigt
(med växande program till slut) hart
när omöjligt att hitta Rätt och Snabbt. Dessa är tveklöst avgörande för
överskådligheten och sammanhanget.
Öppningskoden för
htm-dokument
Koden för htm-dokumentens öppning, globalt
deklarerad på Unit1B (under usesBlocket), över ovanstående (under
ImplementationBlocket):
{Unit1B:}
Procedure OpenHtmHelp(S,L: string);
var
A,I: Integer;
T,U: string;
begin
//S:=
'P2Help.htm';
L:= S + L;
U:=
ExtractFilePath(Application.ExeName);
if not FileExists(U+'Help\'+S)
then
begin
Form1.Label1.Caption:= 'File ' + S +
' NotFound';
exit;
end;
{Skicka
med ev. Htm-Länk|L till Urklipp:}
for
I:= 1 to Length(U) do
if
U[I]='\' then U[I]:= '/';
U:= 'file:///' + U + 'Help/HTM/' + L;
ClipBoard.AsText:= U;
{ÖPPNA:}
T:=
ExtractFilePath(Application.ExeName) + 'Help\';
A:= ShellExecute(
0,
nil,
PChar(S),
nil,
PChar(T),
SW_SHOW);
{Programmet
öppnar inte:}
if
A<=32 then
Form1.Label1.Caption:=
'OpenDocumentError';
end;{endOpenHTMhelp}
DELPHI4 kan inte direkt
åstadkomma länkhopp i ett öppnat htm-dokument.
— Däremot kommer
länkstället fram med ovanstående medsända länkdel till Urklipp så:
— Tryck F6 (eller Tab i InternetExplorer), det fokuserar URL-boxen; Tryck Ctrl+V och sedan Enter.
F1 — Help
Tangent F1 koppar direkt (FormKeyDown, CaseKeyBlocket):
{HELP|Unit1B:}
VK_F1: OpenHtmHelp('P2Help.htm','');
Ovanstående garanterar (enligt min
erfarenhet):
— En avancerad program(för)fattningsgrund
med minimala möjligheter att bilda DIVERGENT programkod.
Distributionsnavets
mera praktiskt sammansatta exempelform
Ovanstående programexempel med HELP innefattar
egentligen alldeles för lite kod för att vara en bra praktisk exempelform på
ett DISTRIBUTIONSNAV. Vartefter
P2-projektet utvecklas, infinner sig emellertid allt fler möjligheter att visa
och exemplifiera en mera fördjupad sammansatthet — och samtidigt exemplifiera
de redan antydda fördelarna.
Praktiskt
exempel
Programutvecklingen för P2 omfattar nu
(4Okt2014) tre separata procedurblock som vart och ett kräver fullständig
tillgång till KeyDown-nycklar, utan att inkräkta på varandras domäner.
Organisationen på FormKeyDown Unit för alla dessa ser ut så, här med
efterföljande kort beskrivning:
SExit:= False;
//if Key in
[VK_NUMPAD5,Ord('T'),Ord('Z')]
{Den
enkla formen ovan — kolliderar med Ctrl+NumPad5 för ArrowStep. För att
parera
för denna måste följande mera preciserade anordning anställas:}
if((Shift=[]) and(Key in [VK_NUMPAD5,Ord('Z')]))
or((Shift=[]) and(WTini)and(Key in [Ord('T')]))
or((Shift=[ssCtrl]) and(Key in [Ord('F'),Ord('T')]))
then
begin
case
Key of
{INITIALIZING||SPECIAL PROCEDURES|Takes All
KeyDown .·°·.·°·.·°·.·°·.·:}
{ACTIVATE|deActivate
·················································:}
VK_NUMPAD5: begin if not Busy
then
EditColors(Key,
Shift);
end;{endNP5|Unit1C}
Ord('T'): begin if not Busy then
if (Shift=[ssCtrl])
or ((Shift=[])and(WTini))
then
WriteText(Key,
Shift);
end;{endCtrlT|Unit1T}
Ord('Z'): begin if not Busy
then
ZoomGeneral(Key, Shift);
end;{endCtrlS|Unit1A}
{ACTIVATE|deActivate
·················································.}
end;{endCaseKey}
if SExit then exit;
end;{endIfSpecialProcedureModuleKeys}
{INITIALIZING||SPECIAL PROCEDURES
.·°·.·°·.·°·.·°·.·°·.·°·.·°·.·°·.·°·.}
{IfActive|SPECIAL
PROCEDURES|ModulensAktiveringsNyckel ···············:}
if ecPanON then begin
EditColors(Key, Shift);
if SExit then exit;
end;{EditColors|Unit1C}
if
TextWrite then begin
WriteText(Key, Shift);
if SExit then exit;
end;{WriteText|Unit1T}
if Im2StretchDraw
then
begin
ZoomGeneral(Key, Shift);
if SExit then exit;
end;{StretchDrawIm2|Unit1A}
{IfActive|SPECIAL PROCEDURES
·········································.}
Förklaring:
— Ovanstående kodblock STÅR ALLRA FÖRST i
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
— Varje särskild KeyDownÄgare (EditColors,
WriteText, ZoomGeneral) — KÄ-domän —
säkrar sitt KeyDownÄgande genom att
0. specificera en unik tangentkombination
KeyDown (NP5,
Ctrl+T eller sedan aktiverad T, Z),
1. aktivera sin (DN) domän(ägar)nyckel (ecPanON, TextWrite, Im2StretchDraw) och
2. ange SExit:=True
i den procedurens initiering (början eller slut, vilket som passar).
— KÄ-domänen avslutar sedan sitt
KeyDownÄgande genom att avställa DN (=False).
— KÄ-domänen behöver aldrig verkställa
SExit:=False eftersom den delen i vilket fall alltid står först i FormKeyDown.
— Busy-tillståndet (Bool|True¦False) motsvarar »ett ömsesidigt
handelsavtal» mellan KÄ-domänerna och som garanterar att ALLA TANGENTER — även
den som aktiverar en annan domän — får användas av den aktuellt aktiva
KÄ-domänen.
— Eftersom (således) bara EN aktiv KÄ-domän
kan finnas vid varje tillfälle, finns ingen risk för »överhörning» mellan de
skilda KÄ-domänerna: varje KÄ-domän garanteras absolut isolation mot övriga.
— Busy:=True aktiveras inifrån varje
KÄ-domän i procedurens början, och måste avställas vid utgången (Busy:=False
tillsammans med DN:=False).
— SExit:=True innebär att
ALLA EFTERFÖLJANDE ORDINÄRA KEYDOWNKOMMANDON hoppas ÖVER. Dessa berör här (i
P2) f.ö. allt som innefattar Flytbildsrutiner (Ctrl+Pilar, Invertera, Rotera,
Duplicera, Kopiera, Tona, m.fl. OM sådana behövs inifrån resp. KÄ, kan sådana
utformas separat för just den individens behov — precis som det är i
NaturFloran).
Med ovanstående PRINCIPIELLA uppställning,
blir det nu enkelt att, i princip, lägga till »hur många som helst» ytterligare
KÄ-domäner (Frame, Draw, Clone, PhotoEdit ...) UTAN
ÖVERDRIVET UPPTAGANDE PLATS i själva distributionsnavet på FormKeyDown: aktiveringsnyckel (DN) och identifieringsnyckel (UnikKey) [samt GOD
anteckningsTeknik] är allt som krävs.
— Enda som krävs för översikten: SKRIV IN
VAR specialProcedurerna finns, så att man lätt hittar VAR vilken finns. Jag
brukar LISTA alla Units i Unit1 överst med en liten förteckning som orienterar
vad som finns, typ (nuvarande)
unit Unit1;
{Unit1 | 8Sep2014|ProjectP2 — Im123FromStart}
{Unit1A
|12Sep2014|BildHanteringsRutiner|ZoomGeneral|Merge|ExecuteHRV...}
{Unit1B
|13Sep2014|SpecialProcessing|OpenHtmHelp|Pan11Im4INTRO}
{Unit1C |17Sep2014|EditColorsUnit}
{Unit1T |27Sep2014|TEXTRutiner}
interface
...
*
Med ovanstående
genomgångar är vi nu klara att sätta in HCDIMRVXZ-funktionerna i
flytbildsprojektet P2: vänd H|orisontellt V|ertikalt D|uplicera I|nvertera
M|erga R|otera X|portera C|opiera Z|oomera.
Projektet P2, så långt [12Sep2014] — UnitRubrikerna
Den nuvarande 11Sep2014
(från 4Sep) samlingen filer i projektkatalogen för P2.
CRsEmpty:=True;
infört:
CRsEmpty: Bool; Unit1 Global, sätts TRUE på ClearImage1|F2 och FALSE på första
Ctrl+V — Används på Ctrl+C för att eliminera (frekvent) felinslag|Ctrl+C efter
bildrensning|F2 då man vill ta in|Ctrl+V från Urklipp. Utan CRsEmpty resulterar
Ctrl+C med tom bildyta att Im2VITT kopieras till Urklipp = raderad intagskopia.
Elakt InslagsFel. Lösningen som ovan.
— Tillagt 18Sep2014|Unit1 FormKeyDown¦Ord('V')¦F2|Unit1A
PrepareExecuteHRV¦Ord('C').
TABELLEN NEDAN är i sammanställning alla
flytbildskommandon i P2 (20Sep2014) — Zoomning ingår inte ännu.
— Utöver dessa
behövs i varje fall en ytterligare: en StretchDraw (i allmänhet mindre god bildkvalitet vid förminskningar [utom för rena
fotografier], som ändå ibland kan ha viss praktisk användbarhet för GROV
översikt) för bekväm GROV bildrektangelÄndringar — MED tydlig display i
%-förhållanden mellan bredd/höjd relativt originalet — och via PilTangenter för
EXAKT representation.
— Ett verktyg av den
kalibern associerar EMELLERTID GÄRNA till Zooming UppNer: Det är här (ännu)
inte bestämt eller ens känt HUR en sådan förnämlig funktion ska realiseras i
ETT verktyg med ENKLA manöverspakar (»ALLT i ett»).
HIMRV
Tangentkommandon P2¦19Sep2014|Alla
FLYTBILDSOPERATIONER:
Ctrl+X|C|D|Delete — H|I|M|R|V — Ctrl+Shift+D
SPACE+H
Alla de 11+ ELEMENTÄRA
flytbildsoperationerna — de BÖR vara så ENKLA att man LÄTT minns dem utantill
SHIFT |
Key |
Makes |
Makes ¦ Toggle |
PrepHRV |
Ctrl+ |
I |
ExportImage |
|
KeyDown |
Ctrl+ |
V |
ImportFromClip |
|
ja |
Ctrl+ |
C |
CopyToClip |
|
ja |
Ctrl+ |
D |
Duplicate |
|
ja |
Ctrl+Shift |
D |
MOVE ¦ MarkRect |
Duplicate + EraseOriginal |
ja |
Ctrl+ |
X |
CutToClip |
|
ja |
Ctrl+ |
Delete |
Delete = PaintWhite |
|
ja |
SHIFT |
Key |
Makes |
Makes ¦ Toggle |
|
SPACE+ |
H |
RGB to BGR |
|
ja |
|
H |
FlipHorizontal |
|
ja |
|
V |
FlipVertical |
|
ja |
|
R |
Rotate90° |
|
ja |
|
I |
InvertImage |
|
KeyDown |
SHIFT |
Key |
Makes |
Makes ¦ Toggle |
|
|
M |
Merge |
OnOff |
KeyDown |
NumPad |
+ |
IncreaseMergeImpact |
max100% |
KeyDown |
NumPad |
– |
DecreaseMergeImpact |
min0% |
KeyDown |
|
C |
MoveCOPY |
MoveAND |
KeyDown |
|
W |
MoveSkipWHITE |
MoveWHITE |
KeyDown |
SHIFT |
Key |
Makes |
Makes ¦ Toggle |
|
Ctrl+ |
M |
MoveAsObject |
MoveAs SHOW more |
KeyDown |
NumPad |
5 |
EditColors |
Back| Foreground |
KeyDown |
|
Insert |
ExactMarkRectPos |
|
KeyDown |
PepHRV = PrepareExecuteHRV — ja anger om kodnyckeln leder dit
Allmän
KODblocksOrganisation för ovanstående | projekt P2 DELPHI4|Sep2014
Koden i DELPJI4 | projekt P2 | 19Sep2014:
— Unit1¦FormKeyDown — (nästan) alla ovan
sammanställda till gemensamt DISTRIBUTIONSNAV:
Generellt, först på FormKeyDown¦Unit1:
{GENERAL¦KEYandSHIFT MIX|HIMRV:}
if((Shift=[]) and(Key
in [Ord('H'),Ord('R'),Ord('V')]))
or((Shift=[ssCtrl])and(Key in
[Ord('C'),Ord('D'),Ord('X'),VK_DELETE]))
or((Shift=[ssShift,ssCtrl])and(Key in [Ord('D')]))
then
begin
PrepareExecuteHRV(Key);
if(Key=Ord('R'))and(MergeFlag=1)then
MakeNewFleetStateVisible;
exit;
end;{endTo|PrepareExecuteHRV(Key)}
Motsvarande UTSKRIFT av SHIFT + Key på
PrepareExecuteHRV(Key) ser ut så här:
X:=0;
if
GetKeyState(VK_SHIFT)<=-127 then Inc(X);
if
GetKeyState(VK_CONTROL)<=-127 then Inc(X);
if
X=0 then
Label1.Caption:= Char(Key) else
if
X=1 then
Label1.Caption:=
'Ctrl+ ' + Char(Key) else
if
X=2 then
Label1.Caption:=
'Ctrl+Shift '+ Char(Key) else
Label1.Caption:=
'PrepareExecuteHRV|NoKey';
samt särskilt på den speciella FlipRGBtoBGR
(»Månskenslandskap» blir »SoluppgångsDito»)
Label1.Caption:=
'SPACE+ H';
Utskriften visas nederst på StatusRaden för
varje aktivering.
Alla ovanstående skickas till Unit1A PrepareExecuteHRV(Key).
— PrepareExecuteHRV(Key) synkroniserar
fördelningen mellan STRECKREKTANGEL och IckeDito för kommandonycklarna, med
vissa förberedelser som streckrektangelns viktiga FORMATERING,
{Allmänna
villkor · Endast om streckrektangel finns:}
X:=0; Y:=0; X1:=0; Y1:=0;
if (Xm0<>Xm1)and(Ym0<>Ym1)
then
begin
if Xm1>Xm0 then begin
X:= Xm0; X1:=Xm1; end;
if Xm0>Xm1 then begin
X1:=Xm0+1; X:= Xm1; end;
if Ym1>Ym0 then begin
Y:= Ym0; Y1:=Ym1; end;
if Ym0>Ym1 then begin
Y1:=Ym0+1; Y:= Ym1; end;
{Gäller
samtliga fall|HIMRV:}
{Slutrektangeln|OPERATIVA
STRECKREKTANGELN|LeftTopRightBottom:}
Rekt:=
Rect(X,Y,X1,Y1);
{Denna
sista rad tar bort streckrektangeln:}
Image1.Canvas.Rectangle(Xm0,Ym0,Xm1,Ym1);
...
end;
radering och allmänna BitMap-förberedelser
(MarkRectIm1ToIm2) som reducerar återstående operationer till HRV-nycklarna.
— Från PrepareExecuteHRV(Key) skickas de
återstående kommandonycklarna vidare till HIMRVdistribution(Image2,Key),
case Key of
Ord('H'):
ExecuteHRV(SourceIm,Key);
Ord('V'):
ExecuteHRV(SourceIm,Key);
Ord('R'):
ExecuteHRV(SourceIm,Key);
end;{endCase}
med en inkluderad förberedelse för den mera
sammansatta Merge-operationen|KeyM
[särskild BIM-bitmap
BIM.Assign(Image2.Picture);] som styrs av NumPad ±-UppNer-räkningarna samt
bildflytten Ctrl+Pilar.
— ÅTERSTODEN kommandonyclar HRV verställer
sedan sina operationer på
ExecuteHRV(SourceIm:
TImage; var Key: Word);:
·
FlipVertical
·
FlipHorizontal
·
FlipRGBtoBGR — samma men förenklad kod som FlipHorizontal
·
Rotate90°
med den viktiga och avgörande gemensamma
slutformen för flytbildens preparering och visning,
·
Procedure BitmapToIm(B: TBitmap);:
Procedure BitmapToIm(B: TBitmap);
begin with Form1 do begin
Image2.Picture.Assign(B);
Image3.Picture.Assign(B);
Panel5.Caption:=IntToStr(Image2.Width)
+';'+IntToStr(Image2.Height);
{Anger bildmåttet, PanelLabeln överst i mitten.}
{X0:=0; Y0:=0;
{PlaceLeftTopAt0;0 om använt.}
CRs:= Image2.ClientRect;
CRd:=CRs;
{CENTRERA
ROTERAT:}
if
S='ScanRotCompleted' then
begin
{För rotationerna (RoteraCentrerat):}
X0:=
X0+(CRs.Bottom-CRs.Right)div 2;
Y0:=
Y0+(CRs.Right-CRs.Bottom)div 2; S:='';
end;
{VERKSTÄLL
FLYTBILDEN:}
OffsetRect(CRd,X0,Y0);
{PlaceLeftTopAtX0;Y0.}
Image3.Canvas.CopyRect(CRs, Image1.Canvas,CRd);
Image1.Canvas.CopyMode :=
cmSrcCopy;
Image1.Canvas.CopyRect(CRd,
Image2.Canvas,CRs);
end;{endWithForm1}
end;{endBitmapToIm}
Övriga flytbildsoperationer (Ctrl+Pilar,
Duplicate, Merge) som inte direkt använder ovanstående, är av liknande (mindre
sammansatt) typ.
H vändHorisontellt
V vänd
Vertikalt
R Rotera
i steg om +90°
Space+H färgvänd RGB till BGR (»MånskensFärger» blir »SolUppgångsDito» och v.v.)
PrepareExecuteHRV(Key):
Från föreg. anteckningar via T2014:
{STRECKREKTANGEL
SAKNAS:}
begin
case Key of
Ord('C'):
begin
{Original:}
if
CRsEmpty then exit;
ClipBoard.Assign(Image2.Picture);
{Ctrl+C
utan streckrektangel=CopyFleetToClip.}
end;
{InvertFlipDirect:}
Ord('D'),Ord('H'),Ord('I'),Ord('R'),Ord('V'):
begin
{Test if Image2 has picture:}
X:=0;
B:=TBitmap.Create;
try
B.Assign(Image2.Picture);
if
B.Empty then X:=-1
finally
B.Free;
end;
if(X=-1)then exit;
{NoFleet·AppliesToAllKeys.}
{DUPLICATEdirect:}
if
Key=Ord('D') then
begin
CRd:= Image2.ClientRect;
CRs:= CRd;
CRsEmpty:=False;
OffsetRect(CRs,X0,Y0);
{*}
Image3.Canvas.CopyRect(CRd,Image1.Canvas,CRs);
{Vid
nästa utläggIm1 läggs FlytKopian på från Im3=bevaras påIm1.}
{*} {Om också Ctrl+D =
TaBortUndre|FöreOvan|StreckRekt
måste finnas:
Image1.Canvas.Brush.Color:= clWhite;
Image1.Canvas.FillRect(CRs);}
exit;
end;
{Återställer
Image1|Förbereder för kommande resultat:}
Image1.Canvas.CopyMode := cmSrcCopy;
Image1.Canvas.CopyRect(CRd,Image3.Canvas,CRs);
CRs:= Image2.ClientRect;
CRd:= CRs;
{CRd/s
vilketsom kan användas för Objektet.}
{Resten
sköts på InvertFlip|HIMRVdistribution:}
HIMRVdistribution(Image2,Key);
end;{endDHIRV}
end;{endCaseKeyNoMarkRect}
end;{endNoMarkRect}
Nedanstående har här i efterhand justerats
med nya rutiner (TMemoryStream — samma exekveringshastighet [om möjligt något
snabbare]) i samband med upptäckten av 16;64-felet.
{VÄND H|ORISONTELLT V|ERTIKALT
R|OTERAi+90°-steg:}
Procedure TForm1.ExecuteHRV(SourceIm:
TImage; Key: Word);
var
x,y,y3,s:Integer;
A,B :
TBitMap;
Pa,Pb:
PBytearray;
H,W,Z,E: Integer;
R:
TRect;
begin
A:= TBitMap.Create;
B:= TBitMap.Create;
try
BitMapRect(CRs,A);
BitMapRect(CRs,B);
A.Canvas.CopyRect(CRd,SourceIm.Canvas,CRs);
{SourceIm är Im1 vid MarkRect, annars (i
allmänhet) Im2.}
A.PixelFormat:= pf32bit;
B.PixelFormat:= pf32bit;
{KEYS:}
case
Key of
Ord('I'):
begin
{INVERT|I:
— denna rutin finns redan ordnad via
det
enklare WindowsAPI med CopyMode cmDestInvert:}
W:= A.Width -1;
H:= A.Height-1;
for
y:= 0 to H do
begin
Pa:= A.ScanLine[y];
Pb:= B.ScanLine[y];
for
x:= 0 to W do
begin
{Sista
Byten överhoppas alltid(RGBQuadStandard):}
Pb[4*x+0]:= 255-Pa[4*x+0];
Pb[4*x+1]:= 255-Pa[4*x+1];
Pb[4*x+2]:= 255-Pa[4*x+2];
{Om
första byten överhoppas ersätts svart med blått.}
end;{endForX}
end;{endForY}
end;{end|I}
Ord('H'):
begin
UTGÅR på grund av 16;64-felet: ..................................................................................................................................... :
{FLIP HORIZONTAL|H|Space+H:}
if GetKeyState(VK_SPACE)<0 then E:=1
else
E:=0;
{ReverseradPalett: Tryck Space+H.}
W:= A.Width-1;
H:= A.Height-1;
Z:= 4*W;
for y:= 0 to H do
begin
Pa:= A.ScanLine[y];
Pb:= B.ScanLine[y];
for x:= 0 to W do
begin
s:= 4*x;
Pb[(1-E)*Z +
(2*E-1)*s + 0]:= Pa[s + (1-E)*0 + E*2];
Pb[(1-E)*Z +
(2*E-1)*s + 1]:= Pa[s + 1];
Pb[(1-E)*Z +
(2*E-1)*s + 2]:= Pa[s + (1-E)*2 + E*0];
end;{endForX}
{SPACE+H ger
färgvändningen R|G|B till B|G|R}
end;{endForY}
UTGÅR på grund av 16;64-felet: ..................................................................................................................................... .
end;{end|H}
Ord('V'):
begin
{FLIP
VERTICAL|:}
W:= 4*(A.Width);
H:= A.Height-1;
for
y:= 0 to H do
begin
Pa:= A.ScanLine[y];
Pb:= B.ScanLine[H-y];
for
x:= 0 to W-1 do
Pb[x]:= Pa[x];
end;{endForY}
Image1.Canvas.CopyMode:= cmSrcCopy;
end;{end|V}
Ord('R'):
begin
UTGÅR på grund av 16;64-felet: ..................................................................................................................................... :
{ROTATE|R|RotCentrum=RektMitt:}
W:= A.Width -1;
H:= A.Height-1;
for y:=0 to H do
begin
Pa:= A.ScanLine[y];
y3:= 4*y;
for x:=0 to W do
begin
Pb:=
B.ScanLine[W-x];
Pb[y3+2]:=
Pa[4*x+2];
Pb[y3+1]:=
Pa[4*x+1];
Pb[y3+0]:=
Pa[4*x+0];
end;{endForX}
end;{endForY}
S:='ScanRotCompleted';
UTGÅR på grund av 16;64-felet: ..................................................................................................................................... .
end;{end|R}
end;{endCaseKey}
{ALLA|FlytbildsPreparering:}
BitmapToIm(B);
finally
A.free;
B.Free;
end;
end;
{Invert32BitTest}
Visst:
— Vi testar sedan en i taget av ovanstående.
BitMapToIm förbereder och
verkställer den slutliga resultatutläggningen på Im1 genom att avstämma
aktuella rektanglar och utföra korrekta kopieringar.
Procedure TForm1.BitMapToIm(B: TBitmap);
begin
Image2.Picture.Assign(B);
Image3.Picture.Assign(B);
Panel5.Caption:=IntToStr(Image2.Width)
+';'+IntToStr(Image2.Height);
{Anger bildmåttet, PanelLabeln överst i mitten.}
CRs:= Image2.ClientRect;
CRd:=CRs;
if S='ScanRotCompleted'
then
begin
{För 90°-rotationerna
(RoteraCentrerat):}
X0:= X0+(CRs.Bottom-CRs.Right)div 2;
Y0:= Y0+(CRs.Right-CRs.Bottom)div 2;
S:='';
end;
{PlaceLeftTopAtX0;Y0:}
OffsetRect(CRd,X0,Y0);
{VISA
RESULTAT:}
Image3.Canvas.CopyRect(CRs,
Image1.Canvas,CRd);
Image1.Canvas.CopyMode := cmSrcCopy;
Image1.Canvas.CopyRect(CRd,
Image2.Canvas,CRs);
end;{endBitmapToIm}
Elementär flytbildsteknik — grundexempel i DELPHI4
k
= (% · INT[1/%])·2 = superSamplingRatio
→ + Anti-Aliasing (AverageByPercent):
k/(2·INT) = %:
U =
2·INT:
Vi
delar upp hela bilden i en vertikal del och en horisontell del för att få
optimal bildändringsfunktion:
10Nov2014:
— Ännu en (galant) enklare lösning har visat
sig:
— Experiment med ovanstående visade strax
följande:
— Anti-Aliasing-tillskottet KAN UNDVARAS
HELT om man bara utför en SUPER SAMPLING-rutin med enhetsförstoringar,
mellanliggande normal %-justering, och efterföljande FF-förminskning enligt
följande algoritm:
1. utgå från en zF-enhetsförstorad
originalkopia (StrecthDraw);
— Ju större zF-värde, desto bättre, men vi
måste begränsa värdet eftersom datorn tar allt längre tid på sig att RENDERA
(beroende på inställningar): ett zF=10 har här satts som gräns, med
zF-autoJusatering till max3 för 23-tumsSkärmen bild: zF=3 betyder då att zoomen
arbetar på en 3^2=9ggr förstorad arbetskopia = ca 2Mb·9 =grovt 20Mb.
— Det tar TID (här INOM en sekund, vilket
har bestämt gränsen med dagens datorprestanda).
2. Justera FÖRMINSKNINGEN (förstoringar
innefattas inte här) regelrätt procentuellt (också via
StrechDraw igen, men nu på föregående storkopia) i resp x|y-led (X= zW; Y=zH):
3. HeltalsFörminska sedan slutligen
resultatet från 2 med zF i FF-metoden.
Resultatet i netto blir alldeles detsamma
som att från skala 1:1 minska originalbilden med respektive zW;zH:
(zF·W0·[zW/W0] ; zF·H0·[zH/H0])
=
(zF·W0·[zW/W0] ; zF·H0·[zH/H0])
=
(zF· [zW]
; zF·
[zH])
;
(zF· [zW]
; zF·
[zH])/zF
=
( [zW] ; [zH])
— Inget mer. Inget mindre.
— Helt enastående resultat.
— Genom att ändra zF kan vi direkt se hur
kvaliteten ändras med växande zF.
— Separat tillägg ger möjlighet att lägga
till Anti-Alias separat.
TANGENTER
Z ZoomOn|Off
F zF aktiverad: pilUppNer
stegar 1-10, display visar:
zF-värdet anger originalbildens förstoring som
arbetskopia: ju högre värde, desto högre kvalitet i förminskningar — och desto
längre TID för RENDERING: avgränsningar har här gjorts som begränsar
renderingstiden till MAX 1(/5) sekund — på bekostnad att zF autoavgränsas om
originalbilden är STOR [typ större än en 23 tums bildskärm, eller runt 2MByte
bildpixels i 32 bitarsSystem]: för 23-tumsbilden är zF max = 3 [=ca 18MB=2·3²].
A Average aktiverad:
pilUppNer stegar 0,1-1,0, display visar
R Range aktiverad: pilUppNer
stegar 1-20, display visar;
A|R reglerar Anti-Aliasing (grad av oskärpa):
Average reglerar styrkan: 1=inget, 0 max (standard = 0,6);
Range reglerar pixelomfattningen (R+1)^2=antalet pixels som Anti-Aliasingen
omfattar i bildpixelkvadraten, R=max20=400 pixels/pixel (standard = 1 = 4
pixels/pixel).
Ctrl+ PilHöger|Vänster, Ökar|Minskar
horisontellt
Ctrl+ PilUpp|Ner, Ökar|Minskar
vertikalt
Ctrl+ NumPad 1 2 3 4, sätter
steglängden 1 5 20 100 till ovan|nedan
Ctrl+ Shift+PilUpp|Ner, Ökar|Minskar proportionell zoom av originalet
PageUp Heltalsförstoring
PageDown Heltalsförminskning
Ctrl+ Numpad|+, entydigt PageUp
Ctrl+ Numpad|–, entydigt PageDown
Ctrl+ P, reverserar PageUp|Dn
Ctrl+ M, reverserar piltangenterna
Tangenterna kan hållas
nedtryckta, resultatet visar sig så snabbt datorn hinner med (max ca 1/5 sekund
per resultat [originalbild från 23 tums skärmbild] med datorstandard 2010).
— Speciellt för
PROCENTUELLA zoomningar: LÄS AV STATUSDISPLAYEN nederst på aktuellt värde: Håll
ner resp. tangenter tills önskat värde visar sig: Procentvärdena anges med tre
decimalers noggrannhet.
Ett avgörande argument:
— När vi arbetar (upprepat) med bilder vill
vi INTE hålla på att ställa in SAMMA zoomparametrar för varje gång vi tar in en
ny bild:
— Vi VILL att
senast använda ska gälla tills ändrat — för att snabbt kunna använda en viss
inställning på en serie bilder (i samband med typ fotografisk redigering, från
givna original typ Fotovisare (ny bild med typ PilHöger) eller annat
[PrintScreen]).
— Paint.NET, gratisprogram för privat bruk —
här till viss utomordentlig jämförelse — har en bra (högkvalitativ)
zoom-funktion, som dessvärre INTE kommer ihåg senaste inställningen. Det blir
jobbigt att ställa in samma om och om igen. ZoomProgrammet här minns senaste.
— Jämför även zoomfunktionen i Windows Paint
(Windows 7):
— Man undrar stillsamt vad exakt programmakarna
MENAR med den typen?
Rent ut sagt: rena rama skiten. Exempel:
Sedan man exakt samma markering dragit några gånger i Microsofts
ÄndraStorleksSnöre i Paint Windows 7, blir resultatet som närmast ovan,
originalet över.
— Ursäkta: vafan ska man HA Det till?
— Vad ska det användas för?
(Improviserad grafisk översättning från
Engelska till Arabiska).
Zoom — Z
Z
On|Off — Steglängd Ctrl+ NumPad
1
2 3 4 = 1 5 20 100 pixels;
Ctrl+
PilHö|Vä Öka|Minska HORISONTELLT; PilUp|Dn Öka|Minska VERTIKALT;
Ctrl+Shift+PilUp|Dn Öka|Minska PROPORTIONELL zoom; PageUp|Dn, HELTAL¦sför- Stora|Minska,
Ctrl+ P¦M
reverserar riktningen hos PageUp|Dn ¦ Piltang.
S aktiverar|avaktiverar R och A, nedan:
F R A + PilUp|Dn aktiverar och ändrar KVALITETSFAKTOR (F|1-10 stand. 3), Område (R|1-20 stand. 1),
Oskärpa (A|0,0-1,0 stand. 0,6)
———————————————————————————————————————————
STATUSRADEN NEDERST VISAR
AKTUELLA VÄRDEN
SLUTFORMEN: endast heltal för ZoomOut U:
Vertikalt
separat
via TMemoryStream|GeneralZoom:
Pa originalbilden
Pq förminskningen
Paint.NET — gratis fotoredigeringsprogram
för privata användare — har i BestQuality en zoomfunktion som nära ansluter
till »flygfotometoden» (min egen utformning från Delphi1 [1997]):
heltalsförminskningar 2 3 4 5 ... som tar kvadratmedelvärdet av 4 9 16 25 ...
pixels som sätts på resultatbildpixlarna 1 2 3 4 ...
Exempel, originalet vänster, förminskning
2ggr höger:
Det motsvarar (vad vi vet) den mesta möjliga
zoomOUTkvalitet som kan fås:
— inga egentliga bildförluster förekommer;
alla bildpixels är representerade.
NÄRA SAMMA kvalitet kan fås för alla
mellanliggande [mellan n och n+1] förminskningsgrader enligt följande algoritm:
originalbilden sträcks (med StrecthDraw) ut
så mycket som krävs för att sedan via en dubblerad förminskning via
»flygfotometoden» få den önskade förminskningen.
EXEMPEL, kvadratiskt:
— En bild önskas förminskad från 100% till
18%: Vi räknar ut en SuperSamplingRatio (StrecthDraw-värde) enligt
k
= (% · INT[1/%])·2 = superSamplingRatio
;
;
INT(1/0,18)
= 5 ;
0,18
· 5 = 0,9 ;
k/2
0,9
· 2 = 1,8 ;
SuperSamplingRatio
Originalbilden ska alltså sträckas ut 180%
(alltid mellan 100 till 200%),
därefter påföras lämplig Anti-Aliasing
(jämnar ut fula ojämnheter i slutresultatet),
och sedan förminskas via flygfoto-metoden
(FF) 5·2=10ggr; 1,8/10=0,18:
(Slutresultatet ovan innefattar »automatisk
avståndsuttoning»).
— Jämför kvaliteten direkt med 5ggr
FF-förminskning (till 20%):
Se även nedan i HastighetstestZoom.
Saken kompliceras (något) av att vi nu måste
dela upp ovanstående kvadratiska exempel för samtliga fall i en vertikal del
och en horisontell del, för bekvämligheten att få fram alla möjliga
plangeometriska bildändringar, inte enbart xy-ändringar med bevarad
originalproportion.
Strategi:
Zooma Kvadratiskt = originalets
xy-proportioner intakta:
1. Ren StretchDraw — gäller före nedan (2)
med Z>1 i vilket x&y-fall
2. FF-metoden — gäller Z<1:
a. direkt för heltal 1/z
b. med SuperSampling och Anti-Aliasing för
alla mellan
Zooma Rektangulärt = originalets
xy-proportioner ändrade:
1. Ren StretchDraw — gäller före nedan (2)
med Z>1 i vilket x|y-fall
2. FF-metoden — gäller Z<1:
a. direkt om Z<1 motsv heltalsdelning
b. gen. med SuperSampling och Anti-Aliasing
för alla mellan
Enklare:
Förstoras originalbilden (Z>1) i x|y
gäller i vilket fall StretchDraw i resp. x|y
(möjlighet finns att lägga till
Anti-Aliasing separat);
Övriga fall:
Förekommer någon förminskning (Z<1) i x|y
gäller FF-metoden för resp. x|y:
1. StretchDraw = SuperSampling [k = (% · INT[1/%])·2
= superSamplingRatio]
2. Anti-Aliasing (Range=1=2×2pixels; Average=0,6 [efter
särskild utprovning])
3. FF-metoden (Z=2·INT)
För att få reda på vad som gäller i vilket
fall, behöver vi endast undersöka originalbildens ÄNDRADE x|y-värden:
— Vi anställer DELS zoomningen via PageUp|Dn
med heltalszoomningar (1 2 3 ..), och DELS via diskreta ändringar i steg om 1
pixel (som vi kan ändra till steg om 5 eller 10 eller 50 pixels) för respektive
x och y via piltangenter Up|Dn för y och Hö|Vä för x — samt kanske en del med
möjlighet att ange procentuella ändringstal [in till 1/1000 — 23-tumsskärmen
typ];
Är x>x0 verkställs x(StretchDraw)
Är y>y0 verkställs y(StretchDraw)
Hela bildskärmen 23tum hastighetstest (4Nov2014) — exakt samma bildresultat:
Vertikal förminskning
U=2ggr med ScanLine-metoden Delphi4:
0,843 Se3kunder.
;
Vertikal förminskning
U=2ggr med TMemoryStream-metoden Delphi4:
0,063 Sekunder.
;
TMemoryStream-metoden är 843/63 = 14,05 ggr snabbare än ScanLine-metoden
Tidsvärden i ett
första enstaka testfall: tiderna varierar sedan något beroende på datorns olika
upptagenhet.
Kodblocken (centraldelarna) ned i VertSLtest och VertTMStest.
ScanLine Vertical
Programkoden, centralblocket, för
ScanLine-metoden
— BMP global bitmap håller flytbilden Image2
som ska förminskas, resultatet på lokal bitmap A, separata
rutiner:
...
Gtc:=
GetTickCount;
try
{MÅLBILDEN|Originalet
i skala 1:1¦: förstorade B(från A)överförs förminskad till A:}
BitmapRect(tR,A);
A.PixelFormat:= pf32bit;
A.Canvas.Brush.Color:= clWhite;
A.Canvas.FillRect(tR);
for y:=0
to
aH-1 do begin
Pa:= A.ScanLine[y+0]; //Målet|
for x:=
0 to
W-1 do begin
R:= 0;
G:= 0;
B:= 0;
for S:=
0 to
U-1 do begin
Pb:= BMP.ScanLine[U*y+S]; //Källan|
R:= R + Pb[4*x+2];
G:= G + Pb[4*x+1];
B:= B + Pb[4*x+0];
end;{endWithS}
Pa[4*x+2]:= R div U;
Pa[4*x+1]:= G div U;
Pa[4*x+0]:= B div
U;
end;{endForX}
end;{endForY}
Image1.Canvas.Draw(0,0,A);
finally
A.Free;
end;
Label1.Caption:=
IntToStr(GetTickCount - Gtc);
843mS
End VertSLtest.
TMemoryStream
Vertical
Programkoden, centralblocket, för
TMemoryStream-metoden
originalet: bA(bitmap), Pa(PChar)
förminskningen bQ(bitmap), Pq(PChar)
separata
rutiner
...
Gtc:=
GetTickCount;
try
{SpecialRutin, etablerar bitmap:ens dimensioner:}
BitmapRect(tA,bA);
BitmapRect(tQ,bQ);
{PREPARERA
MÅLBILDENS BITMAP FÖR BAKGRUNDSELIMINERING:}
bA.Canvas.Brush.Color:= clWhite;
bA.Canvas.FillRect(tA);
bQ.Canvas.Brush.Color:= clWhite;
bQ.Canvas.FillRect(tQ);
{Preparera|BehandlingsBitMaps:}
bA.PixelFormat:= pf32bit;
bQ.PixelFormat:= pf32bit;
{Källbilden|Im2¦Copy|bA¦:}
bA.Canvas.CopyRect(tA,Image2.Canvas,tA);
{SPARA TILL MemoryStreamen så att
vi kan göra ändringar därifrån:}
bA.SaveToStream(TMa); //Källbilden|FlytBildeIm2.
bQ.SaveToStream(TMq); //Målbilden|.
{TILLDELNING
MemoryStreamen tilldelas en AdressPekare = BörjaHärifrån:}
Pa:= TMa.Memory; //1:st
byte
Pq:= TMq.Memory; //1:st
byte
{Samma som hela
BMP-strukturen|Med BitMapInfoHeader: börjar från pos54:}
for
y:= 0 to Hq-1 do begin
{Målbildens
pixelposition i dataminnet:}
Q:= Pq + 54 + 4*((Hq
-(y ))*W);
for
x:= 0 to W-1 do begin
R:= 0;
G:= 0;
B:= 0;
for
S:= 0 to U-1 do begin
{Källbildens
pixelposition i dataminnet:}
A:= Pa + 54 +
4*((H-1-(y*U + S))*W);
R:= R + Byte((A + 4*x
+2)^);
G:= G + Byte((A + 4*x +1)^);
B:= B + Byte((A + 4*x
+0)^);
end;{endForS}
{TA UT MEDELVÄRDET I
y-gruppen = UtZoomade Bilden:}
Byte((Q + 4*x +2)^):= R div U;
Byte((Q + 4*x +1)^):= G div U;
Byte((Q + 4*x +0)^):= B div U;
end;{endForX}
end;{endForY}
{FINALIZING:}
{Förbered MemoryTillBitMap:}
{Börjar från
MinnesPekarensPosition - funkar inte om annat än från 0:}
TMq.Position:= 0;
{UPPDATERAR
ÄNDRINGARNA:}
bQ.LoadFromStream(TMq);
{FlytbildsPreparering|OK|Bilden
ritas ut:}
Image1.Canvas.Draw(0,0,bQ);
finally
bA.Free;
bQ.Free;
TMq.Free;
end;
Label1.Caption:=
IntToStr(GetTickCount - Gtc);
63mS
End VertTMStest.
Zoomfunktionerna i
P2
Inga särskilda komponenter behövs:
Ren programkod på befintlig bildyta:
21Sep2014|Unit1A P2¦Procedure
StretchDrawIm2(Key,Shift):
ZoomDISPLAYEN i P2 med
dess olika statusINFO (21Sep2014).
Esc ZoomOff | se även Ctrl+Z nedan
Z ZoomOn:
Z ZoomStretch OnOff:
Off=StretchDraw=BasicQuality ¦ ON=EnhancedQ
Med ZoomStretchON visas ovanstående mera sammansatta
statusdisplay:
Av¦Ra¦Z med efterföljande värden betyder Average¦Range¦qualityZoom:
Average 1-0
styr diffusheten (som minimerar skillnader i uttoningar),
Range styr
antalet kvadratpixels som Average arbetar på, 1¦3²=9; 2¦4²=16; 3¦5²=25; osv.
ända upp till 20²=400 (som ger typ skuggeffekter);
Z, se
NP 2 nedan.
Tangent A|R
kanaliserar och PilUppNer räknar; resultaten visas omedelbart.
—
STARTLÄGE: Eftersom ZoomStretchON helt saknar verkan med heltalsförstoringar
>1 (från 2 och uppåt), samt att OM ON-läget ändå är valt (Z) det bara tar
(mycket) längre tid för resultatet att visa sig, finns en AutoReglerare som
kopplar bort ZoomStretchON med ZoomUnit>1, och AutoÅterställer för övrigt OM
ZoomStretchON är valt. Därmed slipper vi ifrån de onödiga fördröjningarna om vi
vill ha speciellt STORA förstoringar [Tillagt 4Okt2014 via cZR Unit1A
ZoomGeneral].
S ZoomSquare OnOff: Off=ZoomRect,
On=ZoomSquare
NumPad 2 — växlar
mellan något olika kvaliteter på zoomningar i området förstoring 1 till 2 ggr
och från 1 och neråt:
lägre kvaliteten (displayvärde 2) med ett fördubblat specialpreparerat
original;
(något) högre kvaliteten med fyrdubbla dito (displayvärde 4).
Ctrl+M Pilvändare, reverserar piltangenternas
funktionsriktning
Ctrl+P PageIUpDnVändare, reverserar
UpDn-funktionsriktningen
PageUp Samma som S-funktionen men förstoring
enbart i heltal
PageDn Samma som S-funktionen men förminskning
enbart i reciproka heltal
Ctrl+NP ± Samma som PageUpDn men utan
pilreversering: + större — mindre;
Ingen övre zoomIN-gräns finns (datorns prestanda sätter gränsen):
ZoomStretchON
tar längre tid för stora bilder, medan Off-läget går betydligt snabbare: för
förstoringar från 2 och uppåt har ZoomStretchON i gengäld ingen egentlig
inverkan: den kan helt frånkopplas för dessa fall med en resulterande snabbare
(ögonblicklig) respons;
Undre zoomgränsen har här satts till en bild med bredden|höjden 1 pixel.
Ctrl+NP 1 2 3 = Stegintervall i pixelsteg 1 5 20
Ctrl+C Kopierar senaste zoombilden till Urklipp
Ctrl+ Z, samma som Ctrl+C men med samtidig
avslutning av zoomläget;
Läget före ZoomOn sparas alltid och man kommer tillbaka dit
efter Zoomningen, inkluderat ev. tidigare befintlig flytbild.
Pil- och PageREVERSERINGEN
— För att göra det maximalt bekvämt:
— BEROENDE PÅ VANA vill en del av oss ha BETYDELSERNA »UPP NER
FRAMÅT BAKÅT» stundtals omkastade, allt efter vana, behov, intryck,
bekvämlighet.
— Det görs här med två olika optioner:
— Ctrl+P växlar riktning för
PageUpDn-funktionerna i Zoom;
— Ctrl+M växlar riktning för
Pil-funktionerna i Zoom.
ZoomFunktionen tar källbilden direkt från
aktuell Flytbild (Im2) eller via separat streckrektangel;
— Under ZoomOperationerna sparas bildfönstret
med alla inställningar, och läggs sedan tillbaka efter Ctrl+Z nr2 = CloseZoom.
Resultaten visas i Statusraden nederst med
rektangelmått, procentuella värden, och valda sätt.
— SPECIELLT Z-tillvalet har nu (äntligen)
medgett en heltäckande »hyfsat allmän kvalitativ» zoomRepresentation
genomgående. Resultaten speciellt mellan skala 1:1 och 2:1 (dubblering) och
mellan 1:1 och 1:2 (halvering) innehåller de mest åtråvärda delarna i
datorzoomningar (som det har visat sig) — och som också avslöjar vilken
zoomteknik som används.
— Här har den (nästan) allra enklaste av alla
metoder används:
— Zoomningen för icke heltaliga värden
använder en kombination av det enkla snabba Windows API-stödda StretchDraw —
alla pixels bara rådras — och en medelvärdesbildande »flygfotozoomning».
Slutresultatet KAN bli bättre, men får tills vidare duga.
— Webben (2014) innehåller f.ö. en hel del
PDF-beskrivningar på Zooming Technique, väl utanför den här framställningens
ramar.
TypExempel — Vä: Källbild; Mitten: Halverad med StretchDraw; Hö: samma men med
Z-funktionen beskriven ovan:
S-funktionen med Ctrl+Pilar ökar eller minskar
Källbilden i pixelsteg som KVADRAT från källbildens största utsträckning. Dvs.,
S-funktionen verkställer en reguljär pixelbaserad förstoring/förminskning;
separat statusinfo visar motsvarande %-värden.
Beskrivning
Elementär flytbildsteknik — grundexempel i DELPHI4
DAGENS DATORPROGRAM har (min mening) en
(ytterst FUL OVANA att INTE utnyttja PILTANGENTER:
— Programmakarna vill tydligen att MUSEN ska
spela rollen av allt möjligt i underjorden: flytta bilder, välja verktyg, peka
och påta generellt.
ZOOMFUNKTIONER är ett bra exempel — till
exempel (WindowsStandard) i Paint.
— Enda sättet (min erfarenhet) att ha PRECIS
KOLL på zoomning är att zoomning KAN göras med piltangenter samt integrerat att
·
källbildens mått visas
·
den zoomade källbildens mått visas
·
zoomningens procentuella andelar visas
·
zoomningen via piltangenterna kan ställas in i stegintervall
(här 1 5 20 pixels med Ctrl+NumPad 1 2 3) för snabba eller exakta positioner
och värden
Paint
i Windows som jämförande exempel visar källbildens mått — som ändras när man
drar i streckrektangelns hörn eller kanter; procentuella värden kan skrivas in
via separat dialogruta (via högerklickspanel med tillval). Men som vanligt i
Paint finns inte piltangenterna med i bilden: dessa svarar inte, står
funktionslösa (om inte aktiverade på
omständligt sätt via HjälpCenter [som sedan måste ställas om tillbaka på samma
omständliga sätt]: HandikappHjälpmedel med enStegsPixelFunktion). En del
besitter speciell förmåga att döda datoranvändningen.
ZoomFunktionen i P2 har försökt avhjälpa alla
brister för att få fram snabba, exakta, resultat.
— Musen är inte mycket till hjälp här utom för
att dra upp en streckrektangel.
Jämför STRECKREKTANGELN som sådan MED musflyttningsfunktion:
Streckrektangeln (i [enklare] kommersiella ritprogram) måste
ALLTID avställas med någon separat
kommadoform (Esc eller Ctrl+R, MusVäKlick, eller något) — i Paint speciellt
DESSUTOM MED »tillbörlig distans» mellan Peken och StreckRektangeln om
avklickning ska ske med MusVä: Man kan i Paint t.ex. inte klicka med Peken mitt
i — vilket bara betyder ytterligare besvär.
— Här i P2 försvinner ALLTID streckrektangeln
MED den operation den avser att betjäna (Ctrl+C|D|X|Z ...) — eller om man
ångrar sig sedan märkrektangeln ritats, radera den med MusVäKJlick eller
ESCape.
I
den operativa hanteringen i P2 finns ALDRIG — eller ska inte finnas — rester
efter någon operation.
WriteText
Ctrl+T teckensnitten
i lista med storleksruta (Tab): fäll nerUpp listan med Alt+PilNer|Upp
Enter verkställer valt teckensnitt
Tab hoppar till teckensnittsstorleksrutan
Enter no2
(från teckenstorleksrutan) gömmer teckensnittspanelen och tar fram
inskrivningsboxen
Enter no3
lägger ut texten slutligt som flytbild vid PekPositionen [Ctrl+Pilar flyttar]
Fetstil,
Kursiverat, Stora, Små bokstäver ges i inskrivningsboxen med Alt+F|K|O|L
T Successiva
texter: Senaste
teckensnitt, storlek, färg och text nås direkt med T för successivt nya objekt;
verkställ med Enter
X | Insert Textfärg sätts före T|Ctrl+T med tangent X alt. Shift+T eller
Shift+Insert, eller vid textredigeringen direkt med INSERT som verkställer
FärgenUnderPeken (F4 tar fram en enklare RGB-palett som kan användas) — Alt+Pilar presicionsplacerar Peken i läge TextRed.
WriteText
Ctrl+T listar
teckensnitt, storleksruta (Tab): Alt+PilNer|Upp
Enter verkställer valt teckensnitt
Tab hoppar till teckensnittsstorleksrutan
Enter [no2]
gömmer tar fram inskrivningsboxen
Enter [no3]
lägger ut texten som flytbild vid PekPositionen
Alt+ L O E F K Liten
Stor FetKursiv Fet Kursiv
T Successiva
texter: Senaste
teckensnitt, storlek, färg och text
nås direkt med T för successivt nya objekt; verkställ med Enter
X | Insert Textfärg sätts före T|Ctrl+T med tangent X alt. Shift+T eller
Shift+Insert, eller direkt med
INSERT FärgenUnderPeken
Alt+Pilar precisionsplacerar
Peken för exakt färgval i läge TextRedigering
Elementär flytbildsteknik — grundexempel i DELPHI4
WriteText — Text
på bild
Komponenterna som krävs:
0. En PANEL (här
Panel36|från andra programutvecklingar, min bekvämlighet) att sätta alla
WriteText-komponenterna på för bekväm visning|gömning;
1. En ComboBox som
laddas med datorns alla teckensnitt vid uppstart (ComboBox1.Items:=
Screen.Fonts;);
— Alt+PilNer fäller ner
ComboBoxens MenyLista där alla teckensnittsnamnen står;
— För att t.ex. komma till Times New Roman,
tryck T och första T-förekomsten visas (rulla sedan neråt med PilNer).
— I startläget öppnas ComboBoxen lämpligast
med menyrullen nedfälld så att man ser listningen;
2. En EditBox (här
Edit16|från andra programutvecklingar, min bekvämlighet) för TeckenStorlek;
— Sedan man valt teckensnittet med ett
första Enter når man TeckenStorleksBoxen med en Tab (eller klicka för att flytta fokus till teckenstorleksrutan);
mata in värdet, sedan Enter igen och teckensnittspanelen försvinner, och själva
»SkrivInDinText-box»:en kommer fram — i fortsättningen för vidare behöver man
sedan bara trycka T för att få fram den delen med sist inmatade text:
utskriften hamnar i slutänden ALLTID där peken står, och den ges då som FLYTBILD.
3. En separat TextBox
(här Edit6|från andra programutvecklingar, min bekvämlighet):
— Man kan redigera texten under inmatning,
flytta position där texten ska stå — uppdateras för varje tangentnedtryckning —
och om så önskas återgår till annat teckensnitt och|eller storlek med Ctrl+T
och Enter|Tab|Enter:
— Alt+ Tangenterna L O E F K N styr teckensnittet:
L liten
bokstav för alla markerade
O stor
bokstav för alla markerade
E växlar
fet kursiv | normal
F växlar
fet | normal
K växlar
kursiv | normal
N normal tvingar alltid normal
— Textfärg [FärgDisplay]
Notera att
DESIGNEN på de olika komponenterna i P2-projektet — här — ÄNDRAR UTSEENDE
allteftersom jag själv begåvas med olika uppslag under utvecklingsarbetet för
att pröva olika sätt och försöka känna efter vad som verkar mest lämpligt =
MINST STÖRANDE för helhetens användning: FÄRGER är jättekul — men har en
tendens att dra till sig mer uppmärksamhet än föremålet för arbetet. Gråskalor
med vissa smärre färginslag ger bästa intrycket — lugnhet, fokus på arbetsytan.
— färgpanelerna ovan med startvärde förgrund fgCol=clBlack(lilla
svarta mittrutanÖverst ¦BackGroundColor)
bakgrund
bgCol=clWhite(omgivande vitrutanÖverst¦ForeGroundColor) teckenfärg (färgen på T:et
nedre höger ) — kan
sättas efter önskemål enligt tangenterna
textfärg (T): Shift+T | Shift+INSERT | X — färgen under peken antas då och visas i T:et | svart
från start
bakgrundsfärg till text | vitt från start | Tangent B — färgen under peken
förgrundsfärg, fristående från text | vitt från start | Tanget N — färgen under peken
—Bakgrund(B)Förgrund(N) kopplar direkt till
EditColors (NumPad5): sist aktiverade färg och område gäller för
färgredigeringen [se EditColors-panelen].
— För TEXT har endast T:färgen (X|Shift+T|Insert) och bakgrunden (B) betydelse.
(Funktionern
med Förgrundsfärgen har ännu så länge ingen direkt tillämpning i P2 | 2Okt2014
— frånsett separat Färganalys med NumPad 5 [EditColors] då man vill veta ordningen RGB|HSB.
Förgrundsfärgen ska normalt koppla till olika rit- och färgfyllnadsuppgifter.
Men de verktygen finns ännu inte i P2|2Okt2014).
4. En Label (här Label58|från andra programutvecklingar, min
bekvämlighet) som rubricerar FontSize — vit text som är transparent
(Object Inspector, Transparent = True);
5. En Label (här
Label57|från andra programutvecklingar, min bekvämlighet)
»VisaTeckensnittet med Färg och Storlek» som visar det valda teckensnittet som
det kommer att se ut,
så att man också bekvämt kan undersöka de
olika teckensnittens utseenden.
— VERKSTÄLLANDE tangentkommando i P2 är
alltid Enter för att få ut
texten.
Sista Enter.kommandot avslutar EditBoxen och
lägger ut texten slutligt där markören står på bildytan.
— DÄREFTER FUNGERAR TEXTEN SOM EN ORDINÄR FLYTBILD:
kan vändas, roteras, inverteras, dupliceras, kopieras — men inte åter
redigeras.
— För »återredigering», tryck bara T igen
och EditBoxen kommer åter med senast använda text och teckensnitt, färg och
storlek.
— Mycket bekväm funktion för att t.ex.
skriva etiketter i upprepade uppställningar (med bestämda intervall) med VISSA
varierande data.
Se
en del exempel på hur (Icke TrueType) text kan manipuleras för att sättas över
godtyckliga bakgrunder i BakgrundsOberoende flytbild i Exempel.
TextIN
TextIn är ett programutformat specialverktyg
för att få TrueTypeText — »vanlig större text» — att passa ihop tillsammans med
godtyckliga bakgrunder med bevarad teckenskärpa.
Övergångarna mellan textkropparnas raka och
vinklade delar innefattar i TrueType-teckensnitten uttoningspixels.
Programkoden i TextIn [CentralKoden] anpassar dessa till
varje typ av aktuell bakgrund.
I P2 kan TextIn kombineras med EditColor
(NumPad 5) för direkt färgval för senast inskrivna text och position.
Tangent X aktiverar särskilt färgval för TextFärg,
med direktkoppling till EditColors för tidsanalog färgredigering.
Dvs., man kan precisionsjustera och bestämma
TextIn-färg kontinuerligt mot en aktuell (fotografisk) bakgrund: varje ändring
i EditColorsPanelen uppdateras omgående i aktuell text.
Tangent SPACE
togglar TextIn|OnOff
Programfönsterdumpen ovan (7Okt2014) visar
ett exempel i P2 under pågående EditColor TextIn-redigering på ett
underliggande fotoobjekt.
TextIn
Gäller
ENDAST direkt efter TrueType WriteText ¦ Ctrl+T, se särskild Info
Texten som flytbild har f.n. begränsad
behörighet. Normala bildfunktioner [rotera, invertera, vänd, duplicera, importera,
exportera] avställer TextIn
automatiskt. Om fortfarande tillgängligt, återuppta med en Space igen.
Space Aktiverar|Avaktiverar TextInsmältning för senast inskriven
text. Texten som flytbild kan flyttas godtyckligt med Ctrl+Pilar. Men
TextInsmältningen avställs automatiskt om andra funktioner aktiveras. Återuppta
TextIn efter dessa med Space så länge flytobjektet är senast inskriven
TrueTypeText.
— Speciellt för VIT TEXT: MoveCopySkipWhite;
— alternerande Space får texten att försvinna|visa sig. TextInVitText
ej reguljär flytbild.
— Med MoveCopyWhite visas bara den vita tomma textrektangeln.
— För kopior av VitText med TextIn, kör upprepade T Enter Space.
Programsvårigheter TextIn
Programmässig
utformning med alla texter enhetligt presentabla från svart till vitt mot
godtyckliga bakgrunder kräver att man enhetligt för varje enskilt fall anger
bakgrundsfärg (Canvas.Brush.Color) och förgrundsfärg (Canvas. Font.Color).
— Med den ordningen
kan alla textfärger med alla bakgrunder fås överförbara »transparent» på alla
andra bakgrunder med SkipBackGround (»Tangent W» i upp- eller »ramläge» = SkipWhite).
— PROBLEMET med TextIn
— textsammansmältning med bakgrunden — BLIR i det sammanhanget VIT text:
— Med den (enkla)
algoritm som har använts till textIn-blocket i DELPHI4 visar det sig att OM man
konsekvent använder ovanstående FörgrundBakgrund-ordning (alla TextInObjekt
hamnar som flytbildsobjekt enhetligt på Image2), kvaliteten på speciellt VIT
text i vissa bakgrundsfall INTE blir bra: ser bra ut i en viss del av
ett underliggande foto, medan rester lämnas om texten går in i en ljusare eller
helt vit del. Det ville vi inte ha.
— Försök med att välja
svart bakgrund för den vita texten ger i stort sett samma mindre
tillfredsställande resultat som att välja en ljusare bakgrund: vissa tydliga
taggigheter visar sig, och beroende på tillfällig bakgrund.
— Alternativet —
vilket jag har valt tills något bättre kommer fram — är att SPECIELLT för vit
TrueTypeText skippa anspråken på DIREKT analog flytbild — vilket betyder att VitTexten
INTE kan dupliceras, roteras, vändas, inverteras, kopieras med
flytbildsverktygen. I P2 används därför (f.n.) bara en »rak grundtext».
— Vill man ha kopior
av senaste VitTextTextIn, är det bara att ta om med T, Enter och Space.
— Man kan felaktigt tro att man NÅGOT skulle kunna KRINGGÅ
VITTEXTSVÅRIGHETEN genom att välja en maximalt ljus textfärg typ
RGB(254,255,255).
— Gör man det, alternativet överst, väljer man också
ALGORITMENS minimalt separerande uttoningspixels förmåga att harmoniera med
godtyckliga bakgrunder, och resultatet blir TAGGIGT: VitTexten kräver (liksom
»svarttexten») en maximal uttoningsskala som kan matchas upp mot en godtycklig
bakgrund, alternativet
nederst ovan. Annars blir resultatet reducerad kvalitet.
— »Taggighetsfelet»
(övre alternativet) blir mindre ju mörkare textfärg som används, medan den helt
vita texten alltid ger max skärpa:
— Redan vid gråskalan
243 [textfärg RGB(243,243,243)], ovan, är taggighetsfelet i princip
obefintligt. Samma text som ovan RGB(243,243,243) men mot svart bakgrund:
samt nedan till
jämförelse mot tonad bakgrund:
Vi är glada om det blir så snyggt.
UPPENBARLIGEN finns någon mera avancerad
algoritm i grunden. Men den är ännu här t.v. inte närmare känd. Tills dess får
vi (i P2) finna oss i att VitTexten inte kan dupliceras på annat sätt än via
upprepade T Enter.
— Programkoden är
f.n. utformad för att (säkert) skydda mot avbrott typ AccessViolation i fallen
VitTextTextIn — om man händelsevis råkar försöka med R(otera) V|H(vänd
vertikalt|horisontellt): dessa operationer ger bara en tom textrektangel i
fallet VitTextTextIn. Så: det ska vara helt riskfritt att använda|initiera alla
kommandon.
TextIn — inledning
— Hur gör man för att också få med typen
TrueType-teckensnitt i den samlingen?
— Alltså (vänsterbilden ovan): att kunna
skriva in godtycklig TrueTypeText över godtycklig bakgrund och få den jämna
fina teckensnittskonturen, utan fula taggigheter (högerbilden ovan)?
ORDBEHANDLARNA (Word2000, OpenOffice) har den typen integrerad: lägger
man in bilder som bakgrund under text, anpassas den överliggande texten
(vänsterbilden ovan) så att den smälter in mjukt och »exakt» med bakgrunden.
Om vi förstorar upp foten på ett
TrueType-teckensnitt T (ovan här Times New Roman) och tittar efter, ser vi att »hela
hemligheten» ligger i en mindre samlig UttoningsPixels i rundkanterna på en
»rak» enfärgad TextKropp. KODEN i DELPHI4 för att räkna optimalt med »alla
möjliga fall» — bilden ovan vänster i resultat — ser ut så här [TextIn
Unit1T|2Okt2014][alla utom VitText, denna har
en special; ... J:=255; I:=255-GrayS, sedan lika som nedan med aR=aG=aB=255]:
...
J:= 255-GrayC;
I:= GrayS-GrayC;
if (I>0) and (I<=Round(J*1/10)) then g:= 1-0.05 else
if (I>Round(J*1/10)) and (I<=Round(J*2/10)) then g:=
1-0.10 else
if (I>Round(J*2/10)) and (I<=Round(J*3/10)) then g:=
1-0.20 else
if (I>Round(J*3/10)) and (I<=Round(J*4/10)) then g:=
1-0.30 else
if (I>Round(J*4/10)) and (I<=Round(J*5/10)) then g:=
1-0.40 else
if (I>Round(J*5/10)) and (I<=Round(J*6/10)) then g:=
1-0.50 else
if (I>Round(J*6/10)) and (I<=Round(J*7/10)) then g:=
1-0.60 else
if (I>Round(J*7/10)) and (I<=Round(J*8/10)) then g:=
1-0.70 else
if (I>Round(J*8/10)) and (I<=Round(J*9/10)) then g:=
1-0.80 else
if (I>Round(J*9/10)) then g:= 1-0.90;
{ORIGINALVERSIONEN|Project1|
använde endast tre intervall. Efter flera mer
eller mindre misslyckade försök
att hitta alternativa ALGORITMER visade sig
ovanstånde utmärkta resultat.}
p:= 0.2;
{MED
TONINGSIDENTITET|p| — uttoningspixlarna sammansmälter med bakgrundens pixlar:}
Pc[4*x+2]:= Round(
p*g*(Pa[4*x+2]) + (1-p)*g*aR + (1-g)*(Pb[4*x+2]) ) ;
Pc[4*x+1]:= Round(
p*g*(Pa[4*x+1]) + (1-p)*g*aG + (1-g)*(Pb[4*x+1]) ) ;
Pc[4*x+0]:= Round(
p*g*(Pa[4*x+0]) + (1-p)*g*aB + (1-g)*(Pb[4*x+0]) ) ;
I Programmeringsarbetet:
— Man behöver bara kolla upp gråtonsvärden
för aktuella uttoningspixels (allt övrigt skippas), fastställa ett
toningsintervall för dessa (här i 10 jämna steg), och sedan verkställa
procentuella respektive RGB-andelar från Textdel(Pa) och Bakgrundsdel(Pb), samt
tillfoga ett »TextFärgIdentitetsVärde» (p — här visuellt optimalt observerat
resultat efter viss utprovning) som ger uttoningen mot bakgrunden textfärgens
karaktär (annars framträder »fula rester»).
— Enkel ProgramÖvningsUppgift?
— Definitivt INTE. Grym utmaning om man inte
vet något från början. Att brottas med dylika algoritmer — INNAN MAN HITTAR
STILEN — kan HELT ta knäcken på en. För min egen del, flera gånger nära att
bara ge upp (kasta ut datorn). Många DELEXEMPEL finns — mer eller mindre
komplicerad matematik som man kan ställa upp till prövning — som ger JÄTTEFINA
delresultat, som det ser ut. För att sedan, när man drar resultatet som helhet
över en hel gråskala mellan vitt-svart förvandlas till rena mardrömmen.
Dramatiken är, eller kan vara, milt sagt oerhörd — inte minst när lösningen
seglar upp och sprider Ljuset. Ovanstående ger galanta resultat genomgående,
samtliga fall.
Ramtoning
Antingen singulära bildavsnitt som kan tonas
ut i ändarna, eller överUnder,
Tillämpningsområdena
är ändlösa . . .
eller en förening av två olika bilder som
kan tonas in i varandra — med olika (avgränsande) styrka:
FrameTone
Ctrl+F Aktiverar|Avaktiverar
RamToning (FrameTone)
Pilar Upp|Ner|Höger|Vänster
väljer uttoningsgräns
NumPad± väljer
uttoningsstyrka
Space +
NumPad± väljer uttoningsgrad (uttoningsstyrkans
förstärkning)
Ctrl+C kopierar
resultatet till Urklipp
2BildsFörening MoveCopyWhite :
FlytKopia Övre över Undre, kopiera Ctrl+C, kör Ctrl+F, resultat Ctrl+C, avsluta
Ctrl+F, resultat in Ctrl+V [förena Ctrl+Pilar]
Genom att kombinera olika lämpliga bilder
kan (ytterst) finstämda (helt sagolika, normalt helt omöjliga)
bildkompositioner framställas på det ytterst enkla sättet via FrameTone
[»RamToning»].
(Fotografen är MEDVETET ute i buskarna och LETAR efter
»kombinationsobjekt». Sedan i hemmets lugna vrå utbryter rena jublet när
arbetet sammanställs. Ytterst stimulerande verksamhet — och ibland litet krävande):
Foto: 20Aug2013 E25
Bild41 · 3Jul2012 E12
Bild299 · Nikon D90 — Naturen
Vänligen ge rättelse:
— EUROPA 2014 — en
nazistisk region som kallar sig och uppfattar sig DEMOKRATISK: ett
rättsutövande system som garderat — friskrivit — sig MOT mänskliga rättigheter
(ingen får tvingas tillhöra en sammanslutning)
genom upphöjandet av tillhyggesinrättningar (friskrivningsklausuler)
som existentiell bestämmande auktoritet, och därmed systematiska dödspsykningar
mot och utdrivningar av våldsvägrare från samhällena — med följd i hejdlöst
stegrat allmänt våld och respektlöshet: en totalt havererad rättsordning som
driver omkring som ett sönderbrutet skepp i takt med att vattnet strömmar in
och sänker skutan och naturvandaliseringen sprider sig som en löpeld genom
mänskligheten: en återvändsgränd av fundamental övergripande existensförnekelse
som påtvingas mänskligheten av, från och via samhällets bevarande
propagandaorgan: all media utan undantag.
— Enda sättet att påvisa
förödelsen: genom matematik och fysik, fullkomligt politiskt oberoende,
självbärande relaterbar och minutiöst förklarbar naturlogik, att SÅ påvisa den
Europeiska Intelligensens Grundläggande Misslyckande i Naturvetenskapen.
— Finns det ingen sådan
»reserverad naturkraft» är det kört.
— NAZISMEN INFÖRDES MED
OBLIGATORISK ALLMÄN FOLKLIG LYDNAD UNDER TILLGYGGESAUKTORITETER från mitten av
1800-talet.
— Efter andra
världskriget förbjöds den preussiska staten av de allierade — men man behöll
det centralt nazistiskt införda överhetssystemet med tillhyggesinrättningar som
individmönstrande auktoritet: verksamheten från polis, åklagare och domare
(från 1870 i hela Europa utom England) att påtvinga våldsvägrare våldsbegrepp,
krigsman, för tillfället att få anklaga, misskreditera, driva ut, skymfa och
skända den fredliga människans existensrätt och FÖRENINGSOBEROENDE mot
tillhyggesinrättningar.
— Det och inget annat är
grundvalen till våldets spridning, bristen på allmän trygghet, sundhet ordning
och skick.
— In till den sekund då
rättssystemet ställs till ansvar för sitt vedervärdiga uppträde, kommer icke en
prick att ändras till det bättre i pågående allmänna samhällsutveckling:
kunskapen är fridsamhetsgrundad, och konsekvensen att förakta den naturgrunden
kan ingen kraft omintetgöra: våld föder våld, hat föder hat, och kärlek föder
kärlek. Det är en evig lag.
Ursäkta (känsliga ombeds hoppa över
följande):
— Jag förstår inte riktigt det här [Svar]:
— Naturkryddan bakom fotografierna från
naturområdena som har inspirerat till de ytterst fina sammansättningarna som i
exemplet ovan, verkar också vara allmänt föremål för följande statliga
kommunala intressesfärer:
Från ca 2010:
— Kommunerna uppvisar verksamhet med omfattande,
upprörande, naturingrepp — utan att någon som helst information lämnas till
berörda närboende. Koll på webben för att hitta kopplingar resulterar i noll.
nersågning,
borttagning av den naturliga sköna och lummiga växtligheten, efterlämnade spår
av fulhet, vanvård, tydlig missaktning.
— Vi kommer garanterat aldrig att få något
svar av de ansvariga för vandaliseringen, och som skulle medföra en förändring
till det bättre. Så: Varifrån ska hjälpen komma? UtellMe.
— Överallt liknar allt, mer och mer, ett
veritabelt kalhygge. Noll naturkunskap. Max EgenMaktsProfiteringsBehov.
·
Människor som sågar ner Granen/Tallen DÄRFÖR ATT DEN BARRAR JU.
·
Människor som sågar ned Björken DÄRFÖR ATT DEN LÖVAR JU.
— Vad är det? Uppenbarligen INTE
naturkärlek:
·
Vi ÄLSKAR träden DÄRFÖR att de ÄR träd MED Barr och Löv.
EGENkroppsHAT? NaturÄndamålsFörakt?
Sanningshat? Generellt?
— Högljuddhet, högmodighet, världsvanhet,
noll bekymmer — stark upprördhet när Sanningen visar sig.
— Men det kan ju gömma
sig nån bakom!
— Det är uppenbarligen
inget naturproblem utan ett samhällsproblem.
— Om det finns
människor som verkligen tror att man löser samhällsproblem genom att börja ge
sig på naturen, eller som ens tror att ett naturingrepp skulle kunna
sammanhänga med någon resultatbild i samhällsproblemets lösning — kolla
historien: visa exempel — är det tydligt att de människorna i så fall har tagit
sig vatten över huvudet: naturvandalisering. Våldets slutliga eskalering.
Naturföraktets slutliga ansikte. Problemgrundens slutliga avtäckande: problemet
ligger i samhällets rättsutövande värderingar som har grundlagt våld och
oskick.
— Jag skulle vilja gå
så långt som till hit:
— OM det finns någon
ENDA människa på Jorden 2014 som anser ATT lösningen av samhällsproblem kan
gynnas av naturingrepp, på något som helst enda sätt och vis, var i så fall vänlig
att berätta för mig, om ingen annan, VARIFRÅN den uppfattningen kommer och vad
den grundas på. Ge ett exempel. Jag vill mena det: finns inget sådant exempel.
Men visa gärna.
— Varför då?
— Blommor i StadsCentrum? Står dessa också i
tur att sågas? Är det läge snart att också uppvisa och stoltsera med samma
nerskräpningsNit där som i den övriga milsvida NaturParksHanteringen?
Jag tycker mig se en Strömning som verkar ha satt sig i sinnet att
KNÄCKA Naturen, förstöra och utarma så mycket som möjligt genom att HÄVDA SIG
SJÄLV ÖVERLÄGSEN, att försöka sätta något Nytt i Naturens urgamla ställe, och
också tro sig om att vara mäktig att kunna genomföra det Programmet. Det är det
verkligt intressanta. DNA-genierna, Herrefolket, är tydligen på frammarsch.
Det är definitivt något som inte är som det
ska — sedan runt 2010 enligt observationer.
Det finns ingenting kvar av ovanstående nu
(2014).
— Bara för 4 år sedan fanns typen ovan i
stort sett att SE kring alla möjliga närliggande farleder — hela sommarhalvåret.
— Säg den plats i närområdena man nu
idag 2014 hittar något liknande. Finns inte.
— Kommunerna|Staten röjer ner och förstör
och tar bort allt som en gång fanns kring i stort sett alla farleder — 10 meter
ut på alla vägsidor: stympar, sliter sönder, lämnar efter sig intryck av stark
vanvård och vanskötsel: Det ser ut som en KRAFT som försöker etablera begreppet
KALKYGGE — statlig skogsvård — som något
acceptabelt — dvs., i klartext: skogsbrandsupprinningsområden
i stor mängd etableras löpande: öppna platser i stor mängd med mängder av
död växtlighet: torrt och varmt på ytan, kvavt, hett och fuktigt inunder,
perfekt för kemisk självantändning, eller bara perfekt bränsle om en eld
uppkommer.
Ovanstående enskilda sommarvyer, en gång i stor mängd på många platser i
närområden, i sig urfina, finns inte längre (2014). Runt vägar och farleder,
vattendrag och övrigt, drar en Statlig Kraft omkring med avverkningsmaskiner
och sänker naturvärdena konstant, kontinuerligt. Det verkligt intressanta med
den verksamheten är att vi redan VET att den INTE kommer att bli framgångsrik i
Natursamvaron. Människan är inte skapt så. Så, i takt med att Vettlösheten
sprider sig, visar sig konsekvenserna.
Svar, se även AntecknatNatur
Foto: 27Aug2014 E18
Bild146
InverteraKontrast30
¦ normal:TonaUpp70 ¦ Kontrast 30 — Skies. PerfectAssembly. Project1
DELPHI4Test2011+.
Svar — till
prövning
Förståndslösheten manifesterad.
— Det finns garanterat ingen som helst
rationell, logisk, förståndsgrund på vars fundament någon alls DIALOG med den
ansvariga beslutsfattande instansen kan iordningställas.
— HUR kan jag påstå det?
— Har du sett några Poliser som är ute och
jagar Gärningsmännen?
Nej.
Polisen, hela rättssystemet, ingår i — ÄR — besättningen.
— Har du sett eller läst någon
Tidningsartikel som berättar om förödelsen?
Nej.
Journalistkårerna är en del av verksamheten.
— Har du över huvud taget hört talas om
eller sett något MEDIA alls som ens omnämner de omfattande, tydligt vanställda,
naturingreppen? Jag ser ingen. Verksamheten bara fortsätter, utvidgas.
Vad visar sammanhanget?
Alldeles tydligt: En med anspråk ERÖVRANDE KRAFT är på väg IN i
Naturen för att uppenbarligen försöka agera Existentiell Myndighet:
»VäxtGUDEN».
DET var det intressanta.
— Och varför skulle DET vara det
intressanta?
— Därför att ALLA VET REDAN att när det
kommer till NATURKUNSKAPERNA på Planeten Jorden året 2014, är det enda som
finns från Statligt och Kommunalt håll det som är grundat på det här: militär
exercis och plågsamma djurförsök under 150 år — tillsammans med systematiska
dödspsykningar mot våldsvägrare: polis, åklagare, domare: allmänhet. Inget
annat.
Vanföreställningar om Natur, Moral och Etik tävlar.
Med andra ord, och förutsatt välgrundat:
— Det finns ingen RATIONELL argumentgrund.
Handlingen grundas alldeles avgjort tydligt på erövringsprinciper — noll
information till den berörda allmänheten — en föreställning som grundas på
Överhet, Myndighet med Vapenmakten — yxa — som enda historisk referensgrund.
— Vi använder TIDEN bättre genom att åka ut
till vägkanten, sätta oss ner och börja Prata med de avslitna Ungstammarna.
Naturligt Engagemang.
DEN ANSVARIGA BESLUTSINSTANSEN (Kalle och
Stina på HuvudKontoret) TROR helt säkert, att EFFEKTEN av avslitningarna,
stympningarna och förödelsen ska FRÄMJA EN MINSKNING I DEN ALLMÄNT ÖKANDE
RESPEKTLÖSHETEN — kamouflerad av »allmän trafiksäkerhet» med NOLL
natursamverkan (»naturliga flyktvägar»).
— Det är, således, hög tid för Kalle och
Stina på Huvudkontoret att börja leta efter de borttappade glasögonen som man
inte hittar, genom att känna efter på näsan: de sitter redan på.
Inte förrän de fredliga människornas rätt
ställs fram, den som man våldfört sig på under 150 år och som bär ansvaret för
våldets utbredning, hela Europa, hela Världen, kommer en ändring.
KONSEKVENSERNA AV VETTLÖSHETER har aldrig
försökt smita ifrån vardagen. Vår tids Speciella Övningar innebär inget
undantag.
Hej.
Foto: 27Aug2014 E18
Bild147
InverteraKontrast30
¦ normal:TonaUpp70 ¦ Kontrast 30. PerfectAssembly. Project1 DELPHI4Test2011+.
Är det här den nya modellen för planteringar
i Stadskärnorna?
— Därför att OM man inte hyser större
respekt för Naturskönheten på Övriga Domäner, vadan den Speciella Vurmen?
För den som inte riktigt förstår andemeningen bakom finns en snabbare
kortform: FYA.
Vi — människan — kan inte framgångsrikt börja favorisera vissa
naturområden framför andra, eftersom alla naturområden är likaberättigade
(höger framben har inget företräde för vänster, osv.). Med ovanstående
förnämligt exemplifierade flora av kommunala och statliga företagsamheter, blir
effekten följaktligen denna [OBS, GÄLLER INTE DE SOM SPENDERAR TIDEN I NATUREN
BAKOM BILDÖRRARNA DÄR FÖGA AV OVANSTÅEN DE SYNS]: upprördhet, pressande stress,
upplevd sänkt trivsel, associerad vanmakt. Det finns bara en Kraft som gynnas
av den typen: våld: ohälsa.
26Okt2014
Unit1CD ¦ Ctrl+Shift+C
Procedure TForm1Edit6Change;
Procedure ComPan;
Procedure Commander(var Key: Word; Shift: TShiftState; Code: Integer = 0);
Integrerade rutiner på Im1mouseMove.
KeyDown|KeyPreview
VK_INSERT
VK_ESCAPE
Delad resurs för
Palett(F4), Flytbild(Ctrl+Pilar) och Markörflyttning(Pilar)
Image1MouseMove
Edit6KeyUp|Dn
Edit6Change
Särskilda variabler
(omskrivna från utvecklingsprogrammet T2014):
Status[12] = C =
CommanderDoit: Bool;
Status[13] = 1 =
PenLasso: Bool;
Status[14] = 1 =
LineConnected: Bool;
Status[15] = 0-7 =
ComDoTool: Char;
Status[18] = 1 =
SetColorCD ¦ Pen | Line | SelectColor |
: Bool;
Special på Unit1FormKeyDown för att hindra InsertFlag vid
färgval:
VK_INSERT,VK_DELETE:begin {CurFlag:}
if CommanderDoit then exit;
Special också på Unit1 MouseUp för PenLasso.:
(Trixiga)Ändringar T2014 Unit5 CommanderDoit|PenLasso:
if (Pos('CRL',S)=1)or(Pos('EPS',S)=1)then
begin
{ONLY Status15=|5|7¦(Se KEYS):}
if S[Length(S)] in ['C','F'] then
begin
OK 29Okt2014.
Unit1 KeyDown:
{MoveCOPY|AND|10Sep2014:}
Ord('C'): begin
if CommanderDoit then exit;
Till vilken nytta?
När vi nu (9Sep2014) har hunnit så här långt
— flytbildsfunktionen insatt i elementärt bildhanteringsprogram — kan vi fråga
oss:
— Vilka verktyg bör NU ett sådan ELEMENTÄRT datorstött bildhanteringsprogram ha för att vara till
verklig NYTTA i det allmänna arbetet med bilder?
Jättekul fråga.
Säg nämligen den funktion i bildämnet man INTE vill ha med. Snälla.
— Vi vill ha ALLT. Enkelt. Snabbt.
Vad skulle till exempel P2-programmet som
det nu ser ut kunna användas till?
— Först och främst som en
mellanVERKSTÄLLANDE BILDSTORLEKSMASK:
— RamBildsMask:
Tillämpning, [F5]
— Man vill ha en viss (liten) bildstorlek,
för att kunna sätt lika stora bilder i rader och kolumner:
— PERFEKT läge är det då att ha en P2-hjälp
MED EXAKTA FLYTBILDSEGENSKAPER:
— Man kan precis och exakt ta ut det avsnitt
man vill se, och sedan bara kopiera den bildrutan med Ctrl+I: endast bildrutans
del kopieras till urklipp.
— Sedan kan ett annat öppet P2 ta in den
preparerade bildkopian och snyggt och prydligt — på bestämda exakta
flytbildssteg — och bekvämt (med förutbestämda intervall) ordna samlingen i
rader och kolumner.
— SIST kan HELA den sammanställningen
exporteras via Ctrl+I till t.ex. Paint (jag
gör det ALLTID — arbetsrytmen är: sammanställ i typ P2, exportera till Paint
via urklipp med Ctrl+I, Ctrl+V; spara dessa upprepat nya exporterade ändringar
i Paint på samma plats med Ctrl+S: enkelt, säkert, garanterat viss distans
mellan kopieringar som gör det svårt att fibbla bort original: missar man
något, finns alltid MINST ett sparat tidigare original kvar), och
därifrån sparas på lämpligt format (PNG, för
att bevara alla RGB-färgerna, om det är önskemålet).
JÄMFÖR TILL EXEMPEL FLYTBILDSVERKTYGEN I
PAINT:
— Rena
mardrömmen. Min mening.
— Det GÅR i Paint att flytta ett intaget
objekt med pilar — men bara ett pixelsteg i taget:
— Vi får hålla på tills nästa julafton innan
något blir gjort.
— Man kan VISST klicka på intaget och FLYTTA
MED MUSKNAPPEN NEDTRYCKT, och KOMBINERA med »slutlig precisionspixelposition» i
enstaka pixelsteg — men med den förträffliga bekväma arbetssegern att då
tvingas lämna tangentbordet med de redan parkerade superinstrumenten VänsterFingrar
vid Ctrl och HögerFingrar vid Piltangenterna och NummerBordet.
— I P2-programmet ovan
finns ingen musbaserad bildflyttning, inte alls över huvud taget.
— NÄR jag kommer
över rit- och bildprogram som HAR sådana funktioner — flytta bild med mus —
reagerar jag alltid på samma sätt: gud så TRÄAKTIGT, KLUMPIGT, LÅNGSAMT: omständligt. Rena fängelset.
— Jag vet inte
riktigt varför. Jo. Kanske: Tangentbordet är SNABBT ÅTKOMLIGT, speciellt nämnda
tangentgrupper vänster-höger hand: man kan hela tiden HÅLLA EN tankeTRÅDobruten
I ARBETET utan att behöva tänka på att »lämna området och börja LETA efter
muskroppen vid sidan om». Det är KONTINUITETEN. FLYTET. Glädjen att INTE
TVINGAS BLI AVBRUTEN. Att få använda de enklaste av alla medel, betyder att
DESTO MERA UTRYMME GES FÖR FOKUS PÅ ANNAT. Timme in, timme ut.
— Men jag kanske överdriver.
— I DELPHI4 har vi hur som helst möjligheter
att testa hur våra egna önskemål fungerar i praktiken.
Elementär flytbildsteknik — grundexempel i DELPHI4
EditColorsUnit1C, ecU1C
EditColors
Kodblocken med
variabler till procedurerna i Unit1C|P2|18Sep2014
Hela Unit1C¦P2|19Sep2014
unit
Unit1C;
{Unit1C
— EditColorsUnit|17Sep2014}
interface
uses
Windows,
Messages, SysUtils, WinTypes, WinProcs,
Classes,
Graphics, Forms, Dialogs, StdCtrls,
FileCtrl,ExtCtrls,
Controls, ShellAPI,
Math,
Clipbrd, ComCtrls;
{GlobalVARIABLES|Constants
.......................................:}
type
TecTimer = class(TTimer)
Procedure
OnEditColors(Sender: TObject);
end;
var
ecTimerON:
Bool; {Status37=1=On|0=off}
ecTimer:
TecTimer; {TypeDeclaration som ovan|ecTimer.Create|Free Unit1FormCreate}
ecPanON:
Bool;
eCol:
TColor; {HandlingColor|FB}
fgC21,bgC21: TColor; {TransferColors}
FBflag:
Char; {ForegroundBackgroundColorFlag}
S:
string; {Används på Alt+NumPad 0..9}
KeyNP09:
Bool; {Status38=1 if anyNP|0-9}
{GlobalVARIABLES|Constants
........................................}
{GlobalPROCEDURES
& Functions - GlobalDeclarations ...............:}
Procedure vRGBtoHSB(var C1,C2,C3: Integer);
Procedure vHSBtoRGB(var
C1,C2,C3: Integer);
Procedure
EditColors(var Key: Word; Shift:
TShiftState);
{GlobalPROCEDURES
& Functions - GlobalDeclarations ................}
implementation
uses
Unit1;
{MOTSVARANDE
"uses Unit1C" måste tillfogas på Unit1 antingen
1.
i |uses| direkt efter |interface| LÄNGST UPP - om detaljer som står
explicit
under Unit1:s Interface används, eller
2.
som närmast ovan i Unit1-makens Implementation|Uses.
-
Se dessa detaljer utförligt i DELPHI4help,
Circular
unit references: regeln är att Unit:s inte får referera
varandra
i samma uses-block|Delphi vägrar kompilera då.}
{LocalVARIABLES|Constants
........................................:}
var
C7:
Integer;
RHR:
array [1..2] of array [1..3] of Char;
vRGB,vHSB: array
[1..3] of Integer;
rRH,sRH:
Integer;
kC,ecStep: Integer;
ecT:
TPoint;
ColFG:
TColor;
{LocalVARIABLES|Constants
.........................................}
{ActualPROCEDURES
& Functions - - - - - - - - - - - - - - - - - - :}
{StartIDLE(100mS)|EditColorsPan12|SHOOTleftMB(10mS)|Stop|CloseEditColors:}
{Procedure
TForm1ecTimerTimer(Sender: TObject)|Unit5|T2014|ecTimer|Unit1:}
Procedure TecTimer.OnEditColors(Sender: TObject);
var
W: Word;
begin with Form1 do begin
if not Panel12.Visible
then exit;
if GetKeyState(VK_LBUTTON)<=-127
then
begin
ecTimer.Interval:= 10;
W:= Ord(#2);
EditColors(W,[]);
exit;
end
else
begin
{STANDby:}
ecTimerON:=False;
ecTimer.Interval:= 100;
{RENSA
Alt+NumPad0..9 Input om Ångra före 3 inslag:}
if (GetKeyState(VK_MENU)>-127)
and(Length(S)<3)
and(KeyNP09)
then
begin
S:= '';
KeyNP09:=False;
Label1.Caption:= 'Clear';
end;{endIfÅngraInslagFöre3}
end;{endEcTimerStandBy}
end;{endWithForm1}
end;{endTForm1ecTimerTimer|14Jul2014 Uni5 T2014|17Sep2014|Uni1C|P2}
{ANVÄNDS
till RGB|HSB|ScrollRows istf.MouseMove.}
{Från
RGB till HSB|Formelsamligar finns i bl.a. Wikipedia|2014:}
Procedure vRGBtoHSB(var C1,C2,C3: Integer);
var
R,G,B: Byte;
H,S,L: Integer;
rH,rL,D: Real;
MinRGB,MaxRGB: Real;
begin
R:= C1;
G:= C2;
B:= C3;
{HUE|H:}
rH:=
arctan2(sqrt(3)*(G-B),2*R-G-B)*180/pi;
if
rH<0 then rH:= 360 + rH;
H:= Round(255*rH/360);
{BRIGHTNESS|L:}
MinRGB:= MinValue([R,G,B])/255;
MaxRGB:= MaxValue([R,G,B])/255;
rL:= (MaxRGB + MinRGB)/2;
L:= Round(255*rL);
{SATURATION|S:}
D:= (MaxRGB - MinRGB);
{if (R+G+B)>=765 then S:= 255
else|VITTingenFärgMättnad:S=0=Vitt|Svart:}
if D=0 then S:=0 else
S:= Round(255*(D/(1 - Abs(2*rL -
1))));
if
S>255 then S:= 255;
C1:= H;
C2:= S;
C3:= L;
end;{endValueRGBtoHSB}
{WIKIPEDIA
m.fl. webben ger uppslag. Ovanstående utvecklat efter dessa, samt testat
med
olika testalgoritmer och jämförelser. Notera att speciellt HUE-parametern
ALLTID
kommer
att ge vissa förluster beroende på dess utomordentliga omfattning. Enligt
delvis
systematiska
test (Juli2014) är maximala avvikelsen i RGB-enheter HÄR max 8 — mycket
sällsynt,
medan 4, 3 och 1 är vanligare men fortfarande bara syns sporadiskt i grovtest:
—
Testprogrammet: räkna tillbaka till RGB från HSB och läs av differensen:}
{Från
HSB till RGB:}
Vi har hela tiden koll på RGB och HSB i
det färdiga programmet via EditColorsPanelen
(NumPad 5).
P2-dumpen ovan 19Sep2014 efter en viss
omstuvning av komponenterna och tillägg av en övre extra Statuspanel — enbart
en i botten blir i snålaste laget.
— Senast valda färg (B
bakgrund, N förgrund ¦ visas övre statuspanelen) kommer upp för Redigering med
NumPad 5; efter redigering kan den nya färgen väljas med Enter (eller O) eller
Ångra med Esc (eller C), eller ta om från början med Reset.
— Varje ändring i någon av
R G B H S B återspeglas omedelbart i alla övriga. Full SpektralKoll.
Procedure vHSBtoRGB(var C1,C2,C3: Integer);
var
Col:
TColor;
I,K,D,M,X: Real;
H,S,L,J,A: Integer;
bD,bX,b0:
Byte;
begin
{HSBtoRGB;}
H:= C1;
S:= C2;
L:= C3;
Col:= 0;
I:= 6*H/255;
//I:= 6*(H+0.001)/255;
{Originalet|I:= 6*H/255|+0.001¦annars RGB=0 vid
H=0=clRed|5.9=any<6|:}
if I>=6 then I:=5.9;
{|=6|missar H=255 som då ger
RGB=0 vid H=255|>=6|löser saken|13Jul2014.}
J:= Floor(I);
D:= (1 - Abs(2*L/255 -
1))*S/255;
A:= Round(H/255*360);
K:= Floor(A/60) mod 2 + A/60 -
Floor(A/60);
X:= D*(1 - Abs(K - 1));
M:= (L/255 - D/2);
bD:= Round(255*(D+M));
bX:= Round(255*(X+M));
b0:= Round(255*(0+M));
{if H=0 then Col:=RGB(b0,b0,b0)
else|UtgårMedOvanstående|+0.001|if.}
{Med|I=6H/255|J=Floor(I)|blir|J=0|med|H=0|: ovanstående
»UtvecklingsRest».}
begin
case
J of
0: Col:= RGB(bD,bX,b0);
1: Col:= RGB(bX,bD,b0);
2: Col:= RGB(b0,bD,bX);
3: Col:= RGB(b0,bX,bD);
4: Col:= RGB(bX,b0,bD);
5: Col:= RGB(bD,b0,bX);
end;
end;
C1:= GetRValue(Col);
C2:= GetGValue(Col);
C3:= GetBValue(Col);
end;{endValueHSBtoRGB|12Jul2014.}
{AllKeys|Shift|12Jul2014|ExecuteColor=Colr:}
{:Alla
Nästade Procedurer:
Procedure
EditColors(var Key: Word; Shift: TShiftState)
Procedure Pan60SetUp(Colr: TColor; N:
Integer = 0)
Procedure SwitchSide(A: Integer)
Procedure SelRow(I,A: Integer)
Procedure SetRow(A: Integer; N: Integer = 0)
Procedure CheckEcTimer
:}
Procedure EditColors(var Key: Word; Shift:
TShiftState);
var
Col: TColor;
A,A1,A2,A3: Integer;
Procedure ParIN;
begin
RHR[1][1]:= 'R';
RHR[1][2]:= 'G';
RHR[1][3]:= 'B';
RHR[2][1]:= 'H';
RHR[2][2]:= 'S';
RHR[2][3]:= 'B';
kC:= 0;
rRH:= 1;
sRH:= 1;
{kC=0|RGBside: kC=1|HSBside:
rRH|123|Rows.}
{kC alterneras med Caps: rRH med UpDn.}
end;
{INITIALIZE EditColorsPanel:}
Procedure Pan60SetUp(Colr:
TColor; N: Integer = 0);
var
B: TBitMap;
S:
string;
tR,tB: TRect;
C,I: Integer;
label
EditNew;
begin with Form1 do begin
if Abs(N)=1 then goto EditNew;
with Panel12
do
begin
Width := 557;
Height:= 138;
if Width+10 > Form1.Width then
Form1.Width:= Width+10+50;
Top:= Form1.Height - Height -
Panel2.Height - 23;
if C7=0 then begin
Left:=
Form1.Width - Width -10;
Anchors:=
[akRight,akBottom];
end;
if C7=1 then begin
Left := 20;
Anchors:=
[akLeft,akBottom];
end;
BringToFront;
Show;
end;{endWithPan12}
S:= '';
fgC21:= fgCol;
bgC21:= bgCol;
if not (FBflag
in ['B','N']) then
FBflag:= 'N';
{SELECT EDITING COLOR:}
if FBflag='N'
then
Colr:= fgC21 else Colr:=
bgC21;
ColFG:= Colr;
with
Image5.Canvas do begin
Brush.Color:= clWhite;
FillRect(ClientRect);
end;{endWithIm5Canvas}
{=======}
EditNew:
{=======}
S:=
ExtractFilePath(Application.ExeName) + 'EC21.bmp';
if
FileExists(S) then
begin
{Im5¦AutoSize=False|AlClient|Visible:}
Image5.Picture.LoadFromFile(S);
{SHOW COLOR|Colr=RedigeringsFärgRektangeln
på Im5|fg|bgCol|senaste:}
tR:= Rect(256,45,299,100);
with
Image5.Canvas do begin
Brush.Color:= Colr;
eCol:= Colr;
{Colr medsänds här i denna Procedure
Pan60SetUp(Colr: TColor; N: Integer = 0):
— Den används också vid den upprepade
redigeringen: Image5 läses in upprepat.
— eCol är slutfärgen som ska överföras,
om alls.}
{EditedACTUALforUse:}
FillRect(tR);
B:= TBitMap.Create;
try
{SET|RGB|BarOffset=19;42|yStep=20:}
C:= 0;
for
I:= 1 to 3 do
begin
case I
of
1: begin C:= GetRValue(Colr); A1:= C; vRGB[1]:=A1; end;
2: begin C:= GetGValue(Colr); A2:= C; vRGB[2]:=A2; end;
3: begin C:= GetBValue(Colr); A3:= C; vRGB[3]:=A3; end;
end;{endCase}
tB:= Bounds(147,42 +
(I-1)*20,73,19);
tR:= BitMapRect(tB,B);
with
B.Canvas do begin
Font.Name:= 'Microsoft Sans
Serif';
Font.Size:= 7;
Font.Style:= [fsBold];
Font.Color:= 0;
Brush.Color:= clWhite;
FillRect(tR);
{R|G|B|Value:}
B.Transparent:= True;
B.TransparentColor:= clWhite;
TextOut(0,0,IntToStr(C));
Image5.Canvas.Draw(227,45 +
(I-1)*20,B);
{OBS|FillRectFÖRST — med TYP TransparentColor. AnnarsIngenFunktion.}
end;{endWithB}
{R|G|B|Slide|Set:}
{CopyMode:= cmSrcAnd;
CopyRect(Bounds(227,45,tR.Right,tR.Bottom),B.Canvas,tR);
{SammaNetto|SomDrawViaTransparent.}
C:= C div 2 + 19;
B.Transparent:= False;
B.Canvas.CopyRect(tR,Image5.Canvas,tB);
Brush.Color:= clWhite;
OffsetRect(tR,C,0);
FillRect(tB);
Draw(C,42 + (I-1)*20,B);
end;{endFor}
{endSET|RGB| ......................}
{SET|HSB|BarOffset=336;42|yStep=20:}
{HSBtoRGBmode:}
if
kC=1 then
begin
A1:= vHSB[1];
A2:= vHSB[2];
A3:= vHSB[3];
end
else
{RGBtoHSBmode:}
begin
vRGBtoHSB(A1,A2,A3);
vHSB[1]:= A1;
vHSB[2]:= A2;
vHSB[3]:= A3;
end;
{value|side|row| RGB|HSB.}
for
I:= 1 to 3 do
begin
case I
of
1: C:= A1;
2: C:= A2;
3: C:= A3;
end;{endCase}
{R|G|B|Slide|Value:}
tB:= Bounds(464,42 +
(I-1)*20,73,19);
tR:= BitMapRect(tB,B);
with
B.Canvas do begin
Font.Name:= 'Microsoft Sans
Serif';
Font.Size:= 7;
Font.Style:= [fsBold];
Font.Color:= 0;
Brush.Color:= clWhite;
FillRect(tR);
B.Transparent:= True;
B.TransparentColor:= clWhite;
TextOut(0,0,IntToStr(C));
Image5.Canvas.Draw(311,45 +
(I-1)*20,B);
{OBS|FillRectFÖRST — med TYP
TransparentColor. AnnarsIngenFunktion.}
end;{endWithB}
{H|S|B|Value:}
C:= C div 2 + 336;
B.Transparent:= False;
B.Canvas.CopyRect(tR,Image5.Canvas,tB);
Brush.Color:= clWhite;
OffsetRect(tR,C,0);
FillRect(tB);
Draw(C,42 + (I-1)*20,B);
end;{endFor}
finally
B.Free;
end;
{RGB|HSB|vertACTIVELabel:}
Font.Name:= 'Times New Roman';
Font.Size:= 9;
Font.Style:= [fsBold];
Font.Color:= clWhite;
Brush.Color:= RGB(0,127,255);
TextOut(4 + kC*534,44 +
(rRH-1)*20,' '+ RHR[kC+1][rRH] +' ');
{Start¦kC=0|rRH=1.}
end;{endWithIm22Canvas}
end;{endIfFileExists}
end;{endWithForm1}
end;{endPan60SetUp}
Procedure
SwitchSide(A: Integer);
begin with Form1.Image5.Canvas
do
begin
Col:= RGB(0,127,255);
Font.Name:= 'Times New Roman';
Font.Size:= 9;
Font.Style:= [fsBold];
{A=0=RGBside|A=1=HSBside ¦ A=0:
RGBsideToHSBside ¦ A=1: HSBsideToRGBside:}
{RestorePrevious:}
Font.Color:= 0;
Brush.Color:= clWhite;
TextOut( 4 +
A*534,44 + (rRH-1)*20,' '+ RHR[A+1][rRH] +' ');
{DrawNew:}
Font.Color:= clWhite;
Brush.Color:= Col;
TextOut(538 - A*534,44 +
(rRH-1)*20,' '+ RHR[A+1][rRH] +' ');
sRH:= A+1;
end;{endWithForm1Im22}
end;{SwitchSide|13Jul2014.}
Procedure SelRow(I,A:
Integer);
begin with Form1.Image5.Canvas
do
begin
{I=-1UP|+1DOWN ¦ A=kC =
0=RGBside|1=HSBside:}
Col:= RGB(0,127,255);
Font.Name:= 'Times New Roman';
Font.Size:= 9;
Font.Style:= [fsBold];
Font.Color:= 0;
Brush.Color:= clWhite;
{CLEAR:}
TextOut(4 + A*534,44 +
(rRH-1)*20,' '+ RHR[A+1][rRH] +' ');
rRH:= rRH + I;
if
rRH=4 then rRH:=1;
if
rRH=0 then rRH:=3;
{RGB|HSB|vertACTIVELabel:}
Font.Color:= clWhite;
Brush.Color:= Col;
{SHOWSelected:}
TextOut(4 + A*534,44 +
(rRH-1)*20,' '+ RHR[A+1][rRH] +' ');
end;{endWithForm1Im22}
end;{endSelRow}
{SetRow(0,N>0) för nytt RGB|HSB-värde:}
Procedure SetRow(A:
Integer; N: Integer = 0);
begin
Col:=
Form1.Image5.Canvas.Pixels[256,46];
if
kC=0 then
begin
if
(A=0)and(N>0) then vRGB[rRH]:= N;
{EDIT:}
vRGB[rRH]:= vRGB[rRH] + A*ecStep;
{SafeLimits:}
if
vRGB[rRH]>=256 then vRGB[rRH]:=255;
if
vRGB[rRH]<= -1 then vRGB[rRH]:=0;
{SHOWresult:}
Col:= RGB(vRGB[1],vRGB[2],vRGB[3]);
Pan60SetUp(Col,-1);
exit;
end;{endIfkC=0}
if
kC=1 then
begin
if (A=0)and(N>0) then vHSB[rRH]:= N;
{EDIT:}
vHSB[rRH]:= vHSB[rRH] + A*ecStep;
{SafeLimits:}
if
vHSB[rRH]>=256 then vHSB[rRH]:=255;
if
vHSB[rRH]<= -1 then vHSB[rRH]:=0;
{Transfer:}
A1:= vHSB[1];
A2:= vHSB[2];
A3:= vHSB[3];
vHSBtoRGB(A1,A2,A3);
vRGB[1]:= A1;
vRGB[2]:= A2;
vRGB[3]:= A3;
{SHOWresult:}
Col:= RGB(vRGB[1],vRGB[2],vRGB[3]);
Pan60SetUp(Col,-1);
exit;
end;{endIfkC=1}
end;{endSetRow}
Procedure CheckEcTimer;
var
D,T: TPoint;
I,J,I1,J1: Integer;
tB: TRect;
begin
if ecTimerON=False
then
begin
ecTimerON:=True;
GetCursorPos(ecT);
exit;
end;
GetCursorPos(T);
{EXECUTE MOUSE MOVE|FindSlides:}
//Form1.Label1.Caption:= IntToStr(T.X -
ecT.X);
{FindFocusRect|:}
{tB:= Bounds(RGB|019¦147,42 +
(I-1)*20,73,19):
tB:= Bounds(HSB|336¦464,42 +
(I-1)*20,73,19): 336=317+19:
SlidPanelerna befinner sig|I=|1|2|3|:
tB:= Bounds(RGB¦vRGB[I] div 2 + 19,42 + (I-1)*20,73,19):
tB:= Bounds(HSB¦vHSB[I] div 2 + 336,42 +
(I-1)*20,73,19):
Ovan skissen till det färdiga:}
I1:=0; J1:=0;
D:= Form1.Image5.ScreenToClient(T);
for I:=
1 to
2 do
begin
for
J:= 1 to 3 do
begin
if
I=1 then
tB:= Bounds(vRGB[J] div 2 + 19,42 +
(J-1)*20,73,19) else
tB:= Bounds(vHSB[J] div 2 + 336,42 + (J-1)*20,73,19);
if
PtInRect(tB,D) then begin
I1:= I; J1:= J;
Break;
exit;
end;
end;
end;
{EXECUTE MOUSE
MOVE|DrawSlides|RGBtoHSBtoRGB:}
if
ecTimerON then
begin
kC:= I1-1;
rRH:= J1;
I:= (T.X - ecT.X)*2;
J:= ecStep;
ecStep:=2;
SetRow(I);
ecTimerON:=False;
ecStep:=J;
end;
Form1.Label1.Caption:= IntToStr(T.X -
ecT.X) + ' |: ' +
IntToStr(I1) +';'+ IntToStr(J1);
end;{endCheckEcTimer|StartUnit1|LButton}
label
Final;
begin with Form1 do begin {Procedure
EditColors|Panel12|Im22:}
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
{HitFrån|ecTimer|Via|MouseLeft|EditColorsPan|ON:}
{Säkra
FormKeyDownHIT ·························:}
SExit:= True;
{Säkra
FormKeyDownHIT ·························.}
{#2
från ecTimer:}
if(Key=Ord(#2))then
begin
CheckEcTimer;
exit;
end;
{INITIALIZE|EditColors|Panel12|#1FrånZoomPlus|KeyADD:}
if(Shift=[])and(Key=VK_NUMPAD5) then
begin
if
ecPanON then goto Final;
{SpecialModuleIDENTIFIER|ToUnit1
KeyDown:}
ecPanON:= True;
Key:= Ord(#1);
{LADDAR
PARAMETRAR:}
ParIN;
{VISA|Panel10=fgCol¦Panel9=bgCol:}
if
FBflag='N' then
Pan60SetUp(fgC21) else
Pan60SetUp(bgC21);
{FBflag=N för Förgrund, B för
Bakgrund, sätts via Tangent N|B|Unit1.}
{STEGLÄNGD|Starta
»MouseMoveTimer»:}
ecStep:=5;
ecTimer.Enabled:= True;
S:= '';
{Unit1|Distrib.Nav|Reserverar
alla KeyDownHit:}
exit;
end;{endIfKey#1|StartUp}
{SET RGB|HSB — BYa3digitNumber|0..255:}
if
(Shift=[ssAlt])then
begin
if KeyNP09=False
then S:='';
if(Key
in
[VK_NUMPAD0..VK_NUMPAD9])then
begin
KeyNP09:=True;
{NumPad0..9 = 0..9|C h r Eller C h a r
OK|vilketsom:}
if not(Chr(Ord(Key)
- 48) in ['0'..'9'])then
begin
//Label1.Caption:= 'ErrorInputChar|0..9|';
exit;
end;
S:= S + Chr(Ord(Key) - 48);
A:= StrToInt(S);
if
A>=255 then A:=255;
Label1.Caption:= IntToStr(A);
{EXECUTEnewValue:}
if
Length(S)=3 then
begin
S:= '';
SetRoW(0,A);
KeyNP09:=False;
end;
exit;
end else exit;
end;{endIfAlt}
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
{SETecSTEP|SlideSteps|Ctrl+NumPad|1|2|3|:}
if (Shift=[ssCtrl])and(Key in [VK_NUMPAD1..VK_NUMPAD3]) then
begin
{ 1
2 3 }
{NumPad|1|2|3|=|97|98|99| — | 1|
5|20|:}
case
Key of
Ord(97): ecStep:= 1;
Ord(98): ecStep:= 5;
Ord(99): ecStep:= 20;
end;
exit;
end;
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
if
Shift=[] then
begin
case Key
of
Ord('R'): begin
Pan60SetUp(ColFG);
exit;
end;
end;{endCaseKey}
{SWITCH|RGBside|HSBside:}
if Key=VK_CAPITAL then
{kC=0|1 ¦ 0=RGBside |
1=HSBside:}
begin
SwitchSide(kC);
kC:= Abs(kC-1);
{UPDATE|AnnarsFöregåendeKolumnsBokstav:}
SelRow(0,kC);
exit;
end;{endIfCAP}
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
{SelectROW|RGB|HSB:}
if
Key in [VK_UP,VK_DOWN] then
begin
if Key = VK_UP then A:= -1 else A:= 1;
SelRow(A,kC);
exit;
end;{endIfUpDown}
{EditRow|RGB|HSB:}
if
Key in [VK_LEFT,VK_RIGHT] then
begin
if (Key = VK_LEFT) then A:=-1 else A:=+1;
SetRow(A);
exit;
end;{endIfLeftRight}
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
{FINALIZE|Status36=1|Pan60|EditColors|ZoomPlusInitiate:}
if (Key
in
[Ord('C'),Ord('O'),VK_ESCAPE,VK_RETURN])and(ecPanON)then
begin
{========}
Final:
{========}
{Hit om NumPad5 igen = Escape:}
ecPanON:=False;
Panel12.Hide;
ecTimer.Enabled:= False;
if(Key in [VK_ESCAPE,Ord('C')])then exit;
{Key=Enter|O|SetSelectedColor|N=Förgrund Pan10|B=bakgrund Pan9:}
if FBflag='N' then begin
Panel10.Color:= eCol;
fgCol:= eCol;
end
else begin
Panel9.Color:= eCol;
bgCol:= eCol;
end;
end;{endIfEscEnter}
end;{endIfNoShift}
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
{Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·Oo°.·}
end;{endWithForm1}
end;{endEditColors|Från T2014 17Sep2014}
{ActualPROCEDURES
& Functions - - - - - - - - - - - - - - - - - - -}
end.
ecU1C, END.
PhotoHSB, HueSaturationBrightness
26Sep2014-09-26
Ctrl+F2 — vi använder inte den delen Unit1A
PhotoHSB från nu.
Insättningen av HSB-panelen med test på
FOTOBILDER blev en STOR besvikelse:
1. Fruktansvärt långsam: 23-tumsskärmen på
över två sekunder — för varje ändring i de 12 olika parametervärdena VmH|HSB|%;
2. AVGRÄNSNINGARNA i de olika HSB-regionerna
MOTSVARAR INTE FÖRVÄNTNINGEN att kunna redigera FOTOBILDER på något ENHETLIGT
TILLFREDSSTÄLLANDE sätt:
— PANORERINGSGränserna V|H åstadkommer
delvis FULA FÄRGFÄLT som delvis demolerar HELHETEN:
— Hela METODFORMEN är tydligen INTE
tillägnad någon översvallande FOTOGRAFISK FÄRGredigering.
Nedslående. Vi hade hoppas (mycket) på HSB-panelen. Men den försvann i
en dimma av mörker och dödande långsamhet.
3. YTTERST KOMPLICERAD KOMBINATORIK mellan
de 12 olika parameterställena — trots enkel manövrering via tangenter
VHMP|Pilar NP|1235: ytterst svåröverskådligt OCH MED MAGRA RESULTAT ÖVERLAG.
Bu. Bu. Bu. Dåligt. Dåligt. Dåligt.
Zoom- och HSB-redigering verkar vara
datorområdets allra svåraste detaljer att hantera — MED ACCEPTABELT
TILLFREDSSTÄLLANDE RESULTAT (resultat som garanterat ligger på FRAMSIDAN om det
man inte blir irriterad på).
AntecknatNatur, RamToning
2014-09-22
Det enda som behövs är det här:
— »VI ANSER INTE ATT VÅR VERKSAMHET MEDFÖR
NÅGON ALLMÄN FÖRSTÖRING AV NATURVÄRDEN».
Foto: 27Aug2014 E18
Bild94 — Jesustrakasserier — ekande hånflabb — noll
naturvett — StadsKärnansNyaPlanteringar — avhuggningar,
sönderslitningar, öppna blödande natursår
TYDLIGEN: Den enda som vinner på verksamheten: våldet, våldets
vidare utbredning, förebilderna för omdömet, omsorgen, omvårdnaden,
föreställningen om sundhet och skick.
— Nämn NAMNET på den ETABLERADE ERKÄNDA NATURKRAFT som MOTSÄTTER
SIG DEN UTVECKLINGEN: inte ett knäpp. Inte ett knyst. Inte ett ord. Ingen säger
något.
Säg det. I klartext.
— »VI ANSER INTE ATT VÅR VERKSAMHET
EFTERLÄMNAR INTRYCK AV VANVÅRD, OMDÖMESLÖSHET, OSKICK OCH OSUNDHET».
Där ögat tidigare möttes av naturfröjd,
glädje, upprymdhet och vilsamhet, återstår bara en vy av bedrövelse, vanvård,
missaktning och tydligt utövat djupt naturförakt. Kilometer efter kilometer.
Mil efter mil. Varenda trafikled, vare sig asfalterad eller inte. JävlaNoga.
Jag tänker inte cykla omkring i den starkt deprimerande miljön längre. Jag
vägrar.
Jag vill mena det:
— Det existerar inget HÅLLBART STATLIGT
ARGUMENT för ovanstående — men jag är övertygad om att ALLA STATLIGT ANSVARIGA
KOMMER ATT FÖRSÖKA INBILLA EN SÅDANA. OM jag skulle vara den enda återstående
överlevande naturvännen, är det i så fall en fajt jag måste ta med mina
motståndare: Staten. Kommunen. Då kanske vi också för första gången får veta
beslutsunderlaget för den uppenbara vandaliseringen i svart på vitt. Inget
prat. Inget »å då ska du prata med den och den». Lärbart. Inget munväder. Ingen
Privat LokalHerre som kör med GeniKontoret i PrivatFickan.
Inledning:
— DEMOKRATI är fria val under mänskliga
rättigheter. Inte under tillhyggesinrättningar. Det är grundläggande för
naturvettet. Och vad jag vet, står det OREPRESENTERAT i landsänden: Sveriges
dödspsykningar mot våldsvägrare under 150 år: polis, åklagare, domare, och på
senare tid även allmänheten får vara med i festligheterna att trakassera och
misshandla noll hotbild. Eftersom Naturen är min Läromästare, har jag ingen
annan rationell och logisk grund att hänvisa till i min uppenbara, starkt,
avvikande uppfattning mot allmänheten och dess allmänna våldsvägrarhat. Det är
precis vad hela saken handlar om, min mening.
UR HÄLSOSYNPUNKT ÄR MOTSTÄLLNINGEN REDAN
AVGJORD — min egen högst personliga erfarenhet: läromästare Naturen (medfött
tjejvett): man gör inte så här. Det finns inget försvar för SÄTTET och
VERKSAMHETEN — och heller ingen information i samband med ingreppens
omfattning. Visa mig gärna motargumenten. Visa att jag har FEL, så ska jag
alldeles tveklöst absolut ÄNDRA MIN INSTÄLLNING: Det vore jädrans KUL att få
höra samma mening från motståndarlägret. Därför nämligen: jag tror inte ett
ögonblick på att det är DEN föresatsen Man har: Hela saken gäller en ÖVERHETENS
MAKTANSPRÅK. Inget annat. Noll ansvar. Noll information. DET vore upplyftande
att få se närmare: DU HAR FEL.
Staten/kommunernas
pågående naturvandalisering
— 2010-2014-
Det är uppenbart att de ansvariga i stat och
kommun som numera — sedan runt 2010 — anställer omfattande systematiska
naturavverkningar utan minsta försök att KOMPENSERA FÖR DEN UTEBLIVNA UTSIKTEN
inte förstår vad det är man här håller på med. Låt mig försöka förklara den
ståndpunkten på följande bekanta sätt.
Hur vet man, och på vilket sätt kan man
förstå att stat och kommun här begår brott mot mänskligheten (A18: ”Var och en har rätt till frihet i
tanke,
samvete och religion ...”: tankefriheten är uppenbarligen att förstå som
fullkomligt värdelös om dess uppbärande naturgrunder — naturansiktets naturligt
orörda form som grund för uppfattningen om hälsa och välbefinnande — vanställs
systematiskt; ”... att uppenbara
sin religion eller tro i
undervisning, utövande, andakt och iakttagande”;
A19
”Var och en har rätt till frihet i mening och uttryck
...”; A20.1:
”Var och en har rätt till oberoende fredlig samvaro och tanke.”;
A20.2
”Ingen får tvingas tillhöra en sammanslutning.”;
A22:
”Var och en, som en medlem av samhället,
har rätt till ... och
är berättigad att
tillerkännas, genom nationella insatser och
internationellt samarbete och i enlighet med organisation och resurser i varje
Stat, de ... kulturella
rätter som är oundgängliga för hans värdighet och den fria utvecklingen av hans
personlighet”; A24: ”Var och en har rätt till vila och fritid”;
I VAD exakt DÅ FÖR NÅGOT?;)?
Man kan veta det och förstå det på följande
ytterst enkla grund: medfött tjejvett. Nämligen
med TJEJERNA SOM FÖREBILD — universums
snyggaste och mest välformade, attraktiva och tilldragande varelser:
Naturen — skönheten, sundheten, friskheten,
njutbarheten — har utvecklats på ORÖRD natur:
— NaturVärdet och NaturVården, med tjejernas
formexistens som främsta konkreta exempel på det mest berikande,
hälsobefrämjande, rekreationsgynnande, freds- och fridsamhetsbevarande — ligger
tveklöst just i ORÖRD NATUR: där stat och kommun garanterat INTE har varit och
sågat:
— att låta naturen få växa IFRED:
— att INTE TA BORT något:
Och?
TAR MAN BORT NÅGOT — t.ex. för bebyggelse —
STRÄVAR MAN ATT FÖRSÖKA KOMPENSERA BORTTAGET GENOM ATT INRÄTTA — planera och
plantera — MOTSVARANDE HARMONIERANDE INSLAG. Då fungerar det: Man
strävar att GE tillbaka lika mycket som man TAR. Medfött tjejvett. Omsorg.
Omvårdnad.
MEDFÖTT TJEVETT GÅR INTE UT I BUSKARNA, SÅGAR NER
LEVANDE, OCH LÅTER RESTERNA LIGGA KVAR.
Medan det förra tillhör begreppet KULTUR och
VETTIG CIVILISATION tillhör det senare alldeles tydligt, klart och
omisskänneligt naturvandalisering: vandaliseringen SKAPAR INTRYCK AV TYNGD,
OFRIHET, OHÄLSA, OTILLFREDSSTÄLLELSE, KRAFTLÖSHET, FÖREBILD FÖR ANSVARSLÖSHET,
NATURFÖRAKT OCH ALLMÄN BRIST PÅ OMDÖME: sjukdom. Visa att jag har
fel. DET samhället är på väg NERÅT i exakt samma takt. Medfött tjejvett
befinner sig på kollisionskurs med Det samhället: våldet ökar. otryggheten
ökar, vantrivseln ökar I EXAKT SAMMA TAKT SOM — orörd natur: medfött tjejvett —
FÖREBILDEN FÖR SUNDHET, ORDNING OCH SKICK VANDALISERAS.
Så:
Säg den Internationella, Europeiska eller
LokalStatiga eller Kommunala Instans som INTE instämmer.
Därför, att OM det finns en sådan instans,
är det tydligen krigstillstånd som gäller: mänskligheten befinner sig under
intrång och ockupation från naturföraktande, hälsoförstörande krafter och
därmed direkt sjukdomsbefrämjande: otryggheten ökar.
GENERAL IMAGE HANDLING IN Delphi4Test2022
D4T — Delphi4Test2022
ImportExport
Import:
SCREEN
Directly from whole screen:
•
PrtScn — PrintScreen — copies to ClipBoard
Directly from active window:
•
Alt+PrtScn — copies to ClipBoard
CLIPBOARD
From ClipBoard:
•
Ctrl+V
— Applies to both text (into an input
text box) and image (directly into Delphi4Test2022):
— If ClipBoard has text only, and
Image1 has focus on a Ctrl+V command
— as is normal in D4T
— a Ctrl+V results in a message box
with information:
Export:
D4T has no save function — and no
regret function (except Delphi4 text boxes).
•
Perfect for memory training — and training »elimination of crappy
decisions».
Works done in D4T are preferentially
saved in Windows standard Paint — allowing its different manifold of file image
formats.
•
Preferably in general (for archive purposes) the PNG-format is the most
memory saving alternative — if we wish to save and return to exact bitmap
representations:
•
The PNG format is the same as the RGB (24bit) image color format.
The only difference is that true RGB saves one 24bit for each image
pixel, the entire screen, while PNG collects only the number of used colors on
the same principal RGB basis: PNG saves memory space.
•
The JPG format is »reduced PNG color format»:
— JPG saves even more memory space — by
reducing the number of (adjacent) image colors.
Meaning:
•
JPG is (mostly) good for photo images: the JPG reduction in PNG colors
is (mostly) not visually recognizable — but can sometimes bee disturbing (if
special colored text parts are included: these may lose some originality).
FormatPaint:
Keys
•
Alt+F,E 1 TAB 1 Enter
sets the Paint image format to 1×1
pixel:
•
The moment Paint receives a picture import from ClipBoard, Paint
automatically adopts that picture’s metrics Width-Height.
Exporting images to Paint on equal or larger size, Paint
always adopts automatically to the largest. Resizing (Alt+F,E
1 TAB 1 Enter) is
only necessary if a smaller Paint copy is wanted.
•
Repeatedly saving an image format from D4T by Ctrl+i, then becomes a
simple importing procedure to Paint by keys
•
Ctrl+i from D4T exports the whole present D4T image area picture to
ClipBoard,
•
Shift Windows focus (Alt+TAB) to Paint,
•
Ctrl+V imports the picture to Paint.
SaveToPaint:
On first save, Paint want to know where
— and on what image format. With these selected once, any repeated call to
Paint for repeated savings on the D4T image workings will follow the simple key
routine:
•
Ctrl+i, Alt+TAB, Ctrl+V,S — and Alt+TAB back to D4T to continue the
work.
Windows Paint is (hence) used as a
(safe) image work copy backup — provided we are sufficiently observant to make
a saveToPaint before we make some changes in D4T’s image area. IF we don’t,
we’re smoked: D4T has no memory backup during our work — except Paint, or
directly to ClipBoard with a Ctrl+i (whole image area) or a Ctrl+C to ClipBoard
on a Mouse-drawn marked area.
RecalFromPaint:
Recall (last work) from Paint by
clicking its left top icon area:
Paint opens the image area on all last
saved selections.
— Or open the picture from (a
personally reserved) picture archive folder with Paint.
•
When Paint opens the picture, it has the metrics Width-Height last
saved.
ImportingThePaintPicture:
With the Paint Window focused:
•
Ctrl+A,C — then Alt+TAB to D4T and import the Paint picture with Ctrl+V.
— Ctrl+A selects ALL in Paint, C (with
Alt-key still pressed) copies to Clip.
•
Option in D4T is (Window size adoption)
•
Key
F5:
•
The D4T Image area is always adopted to the last Clip imported image
xy-size
on function key F5 [general UpDateFunction in some programs]
— with a few pixels addition on Width
and Height for a minor margin (we sometimes add dates [D4T text-Function, Key
(Ctrl+) T] in D4T-works to the Paint imported and others — right/above/below).
Exact adoption
without additional margins have representation in the D4T
Co-working Windows API developed programs BaseTextZ and PlainTextIm
(BasicTextIm).
•
With a minor adjustment on Windows size (Alt+Space), its precise pixel
settings function (Ctrl+Arrows), this D4T key F5 option is useful in cases when
we wish to repeatedly construct and present images on one and a same xy-size.
http://www.universumshistoria.se/zGMR2022.htm#ResNat1
For the sake of arguments:
— See also
DELPHI4Test2011
ämnesrubriker
innehåll
Föregående:
DELPHI4Test2011.htm — huvuddokument — HJÄLPDOKUMENT FÖR
DELPHI4Test2011
DelphiBegin
— Swedish archive edition 2011
F5 — Fönsteranpassning
ArrowSwap — MoveMore
MultiWin — flera öppna fönster
BGOF —
BakgrundsOberoendeFlytbild
TBMIH — TBitMapInfoHeader
FH — FlipHorizontal
Unit1A —UnitRUBRIKERNA
kPD — PROGRAMDIVERGENS
HIMRV — vändHV roteraR
inverteraI
ComDo — CommanderDoit
ecU1C — EditColors P2
DelphiKoden
referenser
Senast uppdaterade version: 2022-09-10.
*END.
Stavningskontrollerat 2011-06-08 (väl illa i så fall ..). Bättre 8Feb2022 (Från 1664-felet till hit — en timme senare: hela [jag måtte ha sovit vid första kollen 2011 ..]).
*
DELPHI4Test2014MANUAL ·
√
τ π ħ ε UNICODE — ofta använda tecken i
matematiskt-tekniskt-naturvetenskapliga beskrivningar
σ
ρ ν ν π τ γ λ η ≠ √ ħ
ω → ∞ ≡
Ω
Φ Ψ Σ Π Ξ Λ Θ Δ
α
β γ δ ε λ θ κ π ρ τ φ
ϕ σ ω ϖ ∏ √ ∑ ∂ ∆ ∫
≤ ≈ ≥ ˂ ˃ ˂ ˃ ← ↑
→ ∞ ↓
ϑ
ζ ξ
Pilsymboler, direkt via tangentbordet: Alt+24 ↑; Alt+25
↓; Alt+26 →; Alt+27 ←; Alt+22 ▬
Alt+23
↨ — även Alt+18 ↕; Alt+29 ↔
Alt+1 →:
☺☻♥♦♣♠•◘○◙♂♀♫☼►◄↕‼¶
-20:
§▬↨↑↓→←∟↔▲▼
!”#$%&’( -40:
DELPHI4Test2011.htm
Senast uppdaterade version: 10 september
2022 | 14:49:20 | 2022-09-10. [GMT+1]Solar[GMT+2]Industry
Vidareutvecklat Från DELPHI 4 Test 2011 —
DELPHI4Test2011ref.htm#AnvändningSupportInstallation
T2014Reg — HUVUDDELEN AV
VERKTYGEN MAN BEHÖVER FÖR AVANCERAD DATORANVÄNDNING I TEXT OCH BILD ¦ Jan2022
*