Difference between revisions of "W1505 Images"

From Coder Merlin
m (Merlin moved page Project-1505 to W1505 Images: Improved navigation)
 
(25 intermediate revisions by the same user not shown)
Line 1: Line 1:
= Prerequisites =
[[File:The Sun by the Atmospheric Imaging Assembly of NASA's Solar Dynamics Observatory - 20100819.jpg|thumb|link=|The Sun]]
* [[Project-1504|1504 First Steps on a Path]]
== Prerequisites ==
* [[W1504 First Steps on a Path]]


= Research =
== Research ==
* Read [[https://en.wikipedia.org/wiki/Bitmap Bitmaps]]
* Read [https://en.wikipedia.org/wiki/Bitmap Bitmaps]
* Read [[https://en.wikipedia.org/wiki/Raster_graphics Raster Graphics]]
* Read [https://en.wikipedia.org/wiki/Raster_graphics Raster Graphics]


= Experiment =
== Prepare ==
{{ScenesShellPrepare|W1505}}
== Experiment ==
{{StopProgram|Stop the running program.
Return to the ''console'' and press {{SpecialKey|CONTROL|C}}
}}
=== Basic Images ===
{{SwiftClass|Image}}s enable us to render precomposed graphics from a specified URL.  There are three required steps to rendering an image:
# The {{SwiftClass|Image}} must be initialized in {{SwiftIdentifier|init()}}
# The {{SwiftClass|Image}} must be setup in {{SwiftIdentifier|setup()}}
# Then, if the {{SwiftClass|Image}} is ready, we render it in {{SwiftIdentifier|render()}}
{{Observe|: Section 1|
# What do you think it means for an {{SwiftClass|Image}} to be "ready"?
# Why didn't we need to wait for a {{SwiftClass|Path}} or an {{SwiftClass|Ellipse}} to be ready?
}}


== Get Ready ==
Begin a '''new project''':


Create an Igis shell project within your "project" directory.  
Open the file {{Pathname|Background.swift}} in emacs.
<syntaxhighlight lang="bash">
cd ~/projects
git clone https://github.com/TangoGolfDigital/IgisShell IgisShell-Images
</syntaxhighlight>


Enter into the Sources directory of the new project.
We need to include the {{SwiftLibrary|Foundation}} library (because we're using {{SwiftClass|URL}}s.  Add it at the top of the file:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="swift" highlight="1">
cd IgisShell-Images/Sources/IgisShell/
import Foundation
import Scenes
import Igis
</syntaxhighlight>
</syntaxhighlight>


Build the project. (This may take some time.)
<syntaxhighlight lang="bash">
swift build
</syntaxhighlight>


Open a browser (or use a new tab on an already-open browser).
Add a new property to the {{SwiftIdentifier|Background}} class:
Go to the URL: http://www.codermerlin.com/users/user-name/dyn/index.html
<syntaxhighlight lang="swift" highlight="3">
class Background : RenderableEntity {


NOTE: You MUST change '''user-name''' to your actual user name.  For example, http://www.codermerlin.com/users/john-williams/dyn/index.html
    let whitehouse : Image


You'll know your successful if you see the title bar change to "Coder Merlin: IGIS".
    init() {
        // Using a meaningful name can be helpful for debugging
        super.init(name:"Background")
    }
}
</syntaxhighlight>


== Basic Images ==
We'll first declare the image as a property of our Painter object.  Then, we'll initialize it in the setup method.


Open main.swift in emacs.
Update {{SwiftIdentifier|init()}} to create both the {{SwiftClass|URL}} and then use that {{SwiftClass|URL}} to create the {{SwiftClass|Image}}:
<syntaxhighlight lang="bash">
emacs main.swift
</syntaxhighlight>


We'll need to include the Foundation library, so let's import that at the top of the file (above "import Igis").  Edit so that the top of the file appears as follows:
<syntaxhighlight lang="swift" highlight="9-12">
<syntaxhighlight lang="swift">
class Background : RenderableEntity {
import Foundation
import Igis
</syntaxhighlight>
 
Find the definition of the Painter object and edit it so it appears as follows:
<syntaxhighlight lang="swift">
class Painter : PainterBase {


     let whitehouse : Image
     let whitehouse : Image


     required init() {
     init() {
         guard let whitehouseURL = URL(string:"https://upload.wikimedia.org/wikipedia/commons/thumb/5/5e/US-WhiteHouse-Logo.svg/2000px-US-WhiteHouse-Logo.svg.png") else {
         guard let whitehouseURL = URL(string:"https://upload.wikimedia.org/wikipedia/commons/thumb/5/5e/US-WhiteHouse-Logo.svg/2000px-US-WhiteHouse-Logo.svg.png") else {
             fatalError("Failed to create URL for whitehouse")
             fatalError("Failed to create URL for whitehouse")
         }
         }
         whitehouse = Image(sourceURL:whitehouseURL)
         whitehouse = Image(sourceURL:whitehouseURL)
        // Using a meaningful name can be helpful for debugging
        super.init(name:"Background")
     }
     }
}
</syntaxhighlight>
</syntaxhighlight>


At this point, we've created the image object and specified the URL, but we haven't yet informed the browser to load the image.  We do that in the '''setup''' method.  Edit that method so it appears as follows:


At this point, we've created the image object and specified the URL, but we haven't yet informed the browser to load the image.  We do that in the {{SwiftIdentifier|setup()}} method. Add a new method (below {{SwiftIdentifier|init}}) as follows:
<syntaxhighlight lang="swift">
<syntaxhighlight lang="swift">
     override func setup(canvas:Canvas) {
     override func setup(canvasSize:Size, canvas:Canvas) {
         canvas.setup(whitehouse)
         canvas.setup(whitehouse)
     }
     }
</syntaxhighlight>
</syntaxhighlight>


After setup has executed, the browser will be informed to load the image.  But we haven't yet told the browser to display the image.  We do that in the '''update''' method.  Add that method and edit so that it appears as follows:
{{SwiftIdentifier|setup()}} will inform the browser '''load''' the image.  But we haven't yet told the browser to '''display''' the image.  We do that in {{SwiftIdentifier|render()}} method.  Add that method (below {{SwiftIdentifier|setup()}} and edit so that it appears as follows:
 
<syntaxhighlight lang="swift">
<syntaxhighlight lang="swift">
     override func update(canvas:Canvas) {
     override func render(canvas:Canvas) {
         if whitehouse.isReady {
         if whitehouse.isReady {
             canvas.paint(whitehouse)
             canvas.render(whitehouse)
         }
         }
     }
     }
</syntaxhighlight>
</syntaxhighlight>
The conditional ensures that the image is ready for display prior to issuing the request to the browser to display it.


The conditional ensures that the image is ready for display prior to issuing the request to the browser to display it.


Now, run the program and view in a browser before continuing.
Remember to save the file, then suspend emacs.
 
{{RunProgram|Run the program and view in a browser before continuing.}}
 
 
{{Observe|: Section 2|
# What do you observe?
# What do you think determines the location of the image?
# What do you think determines the size of the image?
}}
 
== Positioning the Image ==
{{StopProgram|Stop the running program.
Return to the ''console'' and press {{SpecialKey|CONTROL|C}}
}}
 


We can position the image by specifying a different topLeft.  Let's move the image to (x:100, y:200).  Edit the update method as follows:
We can position the {{SwiftClass|Image}} by specifying a different {{SwiftIdentifier|topLeft}}.  Let's move the {{SwiftClass|Image}} to (x:100, y:200).  Edit the render method as follows:


<syntaxhighlight lang="swift">
<syntaxhighlight lang="swift" highlight="3">
     override func update(canvas:Canvas) {
     override func render(canvas:Canvas) {
         if whitehouse.isReady {
         if whitehouse.isReady {
             whitehouse.renderMode = .destinationPoint(Point(x:100, y:200))
             whitehouse.renderMode = .destinationPoint(Point(x:100, y:200))
             canvas.paint(whitehouse)
             canvas.render(whitehouse)
         }
         }
     }
     }
</syntaxhighlight>
</syntaxhighlight>


Now, run the program and view in a browser before continuing.
{{RunProgram|Run the program and view in a browser before continuing.}}
 
 
{{Observe|: Section 3|
# What do you observe?
}}
 
=== Resizing the Image ===
{{StopProgram|Stop the running program.
Return to the ''console'' and press {{SpecialKey|CONTROL|C}}
}}


The image is rather large.  We can resize the image by displaying it in a rect, which will include both the position and size.  Edit the update method as follows:
The image is rather large.  We can resize the image by displaying it in a rect, which will include both the position and size.  Edit the render method as follows:


<syntaxhighlight lang="swift">
<syntaxhighlight lang="swift" highlight="3">
     override func update(canvas:Canvas) {
     override func render(canvas:Canvas) {
         if whitehouse.isReady {
         if whitehouse.isReady {
             whitehouse.renderMode = .destinationRect(Rect(topLeft:Point(x:100, y:200), size:Size(width:300, height:200)))
             whitehouse.renderMode = .destinationRect(Rect(topLeft:Point(x:100, y:200), size:Size(width:300, height:200)))
             canvas.paint(whitehouse)
             canvas.render(whitehouse)
         }
         }
     }
     }
</syntaxhighlight>
</syntaxhighlight>


Now, run the program and view in a browser before continuing.
{{RunProgram|Run the program and view in a browser before continuing.}}
=== Displaying a Portion of an Image ===
{{StopProgram|Stop the running program.
Return to the ''console'' and press {{SpecialKey|CONTROL|C}}
}}
 


Finally, rather than display the entire image, we can opt to display just a portion, as specified by a source rect.  The image from the source rect will be scaled and displayed in the destination rect.  Edit the update method as follows:
Finally, rather than display the entire image, we can opt to display just a portion, as specified by a source rect.  The image from the source rect will be scaled and displayed in the destination rect.  Edit the render method as follows:


<syntaxhighlight lang="swift">
<syntaxhighlight lang="swift" highlight="3-5">
     override func update(canvas:Canvas) {
     override func render(canvas:Canvas) {
         if whitehouse.isReady {
         if whitehouse.isReady {
             let sourceRect = Rect(topLeft:Point(x:740, y:400), size:Size(width:532, height:495))
             let sourceRect = Rect(topLeft:Point(x:740, y:400), size:Size(width:532, height:495))
             let destinationRect = Rect(topLeft:Point(x:100, y:200), size:Size(width:266, height:247))
             let destinationRect = Rect(topLeft:Point(x:100, y:200), size:Size(width:266, height:247))
             whitehouse.renderMode = .sourceAndDestination(sourceRect:sourceRect, destinationRect:destinationRect)
             whitehouse.renderMode = .sourceAndDestination(sourceRect:sourceRect, destinationRect:destinationRect)
             canvas.paint(whitehouse)
             canvas.render(whitehouse)
         }
         }
     }
     }
</syntaxhighlight>
</syntaxhighlight>


Now, run the program and view in a browser before continuing.
{{RunProgram|Run the program and view in a browser before continuing.}}
 
 
{{Observe|: Section 4|
# What do you observe?
# What happens if the sourceRect is ''smaller'' than the destinationRect?
# What happens if the sourceRect is ''larger'' than the destinationRect?
}}
 


= Exercises =
{{Caution|Be careful to ensure that any URL you plan to use is truly a '''reference''' to a resource and not embedded data. It's very easy to determine which is which.  A reference (in this case) will begin with either "http" or "https".  A URL that begins with "data" actually contains '''inline data''', not a reference to the source.  In the case of some images this may be a ''very'', ''very'' large amount of data.  '''Attempting to paste this into a shell may cause the shell to hang.'''  So it's very important to be sure that the URL begins with "http" or "https" BEFORE you paste.}}
{{notice|[[File:Warning icon.svg|frameless|30px]]|Warning:  Be careful to ensure that any URL you plan to use is truly a '''reference''' to a resource and not embedded data. It's very easy to determine which is which.  A reference (in this case) will begin with either "http" or "https".  A URL that begins with "data" actually contains '''inline data''', not a reference to the source.  In the case of some images this may be a ''very'', ''very'' large amount of data.  '''Attempting to paste this into a shell may cause the shell to hang.'''  So it's very important to be sure that the URL begins with "http" or "https" BEFORE you paste.}}


Continuing with this project:
== Serving Images from the Merlin Server ==
{{GoingDeeper|
It's sometimes useful to be able to display images from a GitHub project.  (You'll learn more about this later.). In order to do so:
1. Create a link from your GitHub project to your www directory:
{{ConsoleLine|john-williams@codermerlin:~/www$|ln -s /home/john-williams/Experiences/FavoriteProject/Images favorite-project-images}}
2. Set the permissions for each directory leading to your images:
{{ConsoleLine|john-williams@codermerlin:~$|chmod a+rx Experiences}}
{{ConsoleLine|john-williams@codermerlin:~$|chmod a+rx Experiences/FavoriteProject}}
3. Set the permissions for the image directory and all images:
{{ConsoleLine|john-williams@codermerlin:~$|chmod -R a+rX Experiences/FavoriteProject/Images}}
}}
== Exercises ==
{{Exercises|
* {{Assignment|J1505}} Create a journal and answer all questions.  Be sure to include all sections of the journal, properly formatted.
# Think of a theme for your composition.  Add at least four different images to your canvas following your chosen theme.  (You may remove the White House.)  Remember to only use images that are licensed appropriately.  The images may not overlap.
# Think of a theme for your composition.  Add at least four different images to your canvas following your chosen theme.  (You may remove the White House.)  Remember to only use images that are licensed appropriately.  The images may not overlap.
# At least one of the images must be scaled up (i.e. it must be larger than the original source).
# At least one of the images must be scaled up (i.e. it must be larger than the original source).
Line 134: Line 189:
# At least one of the images must be only partially displayed (i.e. the source rectangle does not include the entire image).
# At least one of the images must be only partially displayed (i.e. the source rectangle does not include the entire image).
# Draw a rectangular frame around each image.  Each frame must be a different color.
# Draw a rectangular frame around each image.  Each frame must be a different color.
* {{MMMAssignment|M1505-28}}
}}


= Extended Exercises =
[[Category:Coder_Merlin_standards_assistant-1505.010_Display_images]]
# Add at least thirty eyelashes per eye by ''calculating'' the correct position and angle of each eyelash.
[[Category:IGIS]]

Latest revision as of 20:32, 19 February 2022

Within these castle walls be forged Mavens of Computer Science ...
— Merlin, The Coder
The Sun

Prerequisites[edit]

Research[edit]

Prepare[edit]

Create a new Scenes shell project within your Experiences directory:

ty-cam@codermerlin:~$  cd ~/Experiences

ty-cam@codermerlin:~/Experiences$  git clone https://github.com/TheCoderMerlin/ScenesShellBasic W1505


Enter the Sources/ScenesShell directory of the new project:

ty-cam@codermerlin:~/Experiences$  cd W1505/Sources/ScenesShell/


Start button green arrow
Run the program.

ty-cam@codermerlin:~/Experiences/W1505/Sources/ScenesShell$  run


Ensure that you are logged on to the wiki. Then, click on the Tools menu followed by right-clicking on IGIS and selecting the menu item Open in New Window or Open in New Tab.

You'll know you're successful if you see the title bar change to "Coder Merlin: IGIS". (The browser window will be blank because we haven't added any graphics yet.)

Hint.pngHelpful Hint
It's useful to bookmark this page in your browser.

Experiment[edit]

Stop button red ex
Stop the running program.

Return to the console and press CONTROL-C

Basic Images[edit]

Images enable us to render precomposed graphics from a specified URL. There are three required steps to rendering an image:

  1. The Image must be initialized in init()
  2. The Image must be setup in setup()
  3. Then, if the Image is ready, we render it in render()
ObserveObserveIcon.png
Observe, Ponder, and Journal: : Section 1
  1. What do you think it means for an Image to be "ready"?
  2. Why didn't we need to wait for a Path or an Ellipse to be ready?


Open the file Background.swift in emacs.

We need to include the Foundation library (because we're using URLs. Add it at the top of the file:

import Foundation
import Scenes
import Igis


Add a new property to the Background class:

class Background : RenderableEntity {

    let whitehouse : Image

    init() {
        // Using a meaningful name can be helpful for debugging
        super.init(name:"Background")
    }
}


Update init() to create both the URL and then use that URL to create the Image:

class Background : RenderableEntity {

    let whitehouse : Image

    init() {
        guard let whitehouseURL = URL(string:"https://upload.wikimedia.org/wikipedia/commons/thumb/5/5e/US-WhiteHouse-Logo.svg/2000px-US-WhiteHouse-Logo.svg.png") else {
            fatalError("Failed to create URL for whitehouse")
        }
        whitehouse = Image(sourceURL:whitehouseURL)

        // Using a meaningful name can be helpful for debugging
        super.init(name:"Background")
    }
}


At this point, we've created the image object and specified the URL, but we haven't yet informed the browser to load the image. We do that in the setup() method. Add a new method (below init) as follows:

    override func setup(canvasSize:Size, canvas:Canvas) {
        canvas.setup(whitehouse)
    }

setup() will inform the browser load the image. But we haven't yet told the browser to display the image. We do that in render() method. Add that method (below setup() and edit so that it appears as follows:

    override func render(canvas:Canvas) {
        if whitehouse.isReady {
            canvas.render(whitehouse)
        }
    }

The conditional ensures that the image is ready for display prior to issuing the request to the browser to display it.


Remember to save the file, then suspend emacs.

Start button green arrow
Run the program and view in a browser before continuing.


ObserveObserveIcon.png
Observe, Ponder, and Journal: : Section 2
  1. What do you observe?
  2. What do you think determines the location of the image?
  3. What do you think determines the size of the image?

Positioning the Image[edit]

Stop button red ex
Stop the running program.

Return to the console and press CONTROL-C


We can position the Image by specifying a different topLeft. Let's move the Image to (x:100, y:200). Edit the render method as follows:

    override func render(canvas:Canvas) {
        if whitehouse.isReady {
            whitehouse.renderMode = .destinationPoint(Point(x:100, y:200))
            canvas.render(whitehouse)
        }
    }
Start button green arrow
Run the program and view in a browser before continuing.


ObserveObserveIcon.png
Observe, Ponder, and Journal: : Section 3
  1. What do you observe?

Resizing the Image[edit]

Stop button red ex
Stop the running program.

Return to the console and press CONTROL-C

The image is rather large. We can resize the image by displaying it in a rect, which will include both the position and size. Edit the render method as follows:

    override func render(canvas:Canvas) {
        if whitehouse.isReady {
            whitehouse.renderMode = .destinationRect(Rect(topLeft:Point(x:100, y:200), size:Size(width:300, height:200)))
            canvas.render(whitehouse)
        }
    }
Start button green arrow
Run the program and view in a browser before continuing.

Displaying a Portion of an Image[edit]

Stop button red ex
Stop the running program.

Return to the console and press CONTROL-C


Finally, rather than display the entire image, we can opt to display just a portion, as specified by a source rect. The image from the source rect will be scaled and displayed in the destination rect. Edit the render method as follows:

    override func render(canvas:Canvas) {
        if whitehouse.isReady {
            let sourceRect = Rect(topLeft:Point(x:740, y:400), size:Size(width:532, height:495))
            let destinationRect = Rect(topLeft:Point(x:100, y:200), size:Size(width:266, height:247))
            whitehouse.renderMode = .sourceAndDestination(sourceRect:sourceRect, destinationRect:destinationRect)
            canvas.render(whitehouse)
        }
    }
Start button green arrow
Run the program and view in a browser before continuing.


ObserveObserveIcon.png
Observe, Ponder, and Journal: : Section 4
  1. What do you observe?
  2. What happens if the sourceRect is smaller than the destinationRect?
  3. What happens if the sourceRect is larger than the destinationRect?


CautionWarnIcon.png
Be careful to ensure that any URL you plan to use is truly a reference to a resource and not embedded data. It's very easy to determine which is which. A reference (in this case) will begin with either "http" or "https". A URL that begins with "data" actually contains inline data, not a reference to the source. In the case of some images this may be a very, very large amount of data. Attempting to paste this into a shell may cause the shell to hang. So it's very important to be sure that the URL begins with "http" or "https" BEFORE you paste.

Serving Images from the Merlin Server[edit]

Going DeeperGoingDeeperIcon.png

It's sometimes useful to be able to display images from a GitHub project. (You'll learn more about this later.). In order to do so: 1. Create a link from your GitHub project to your www directory:

john-williams@codermerlin:~/www$ ln -s /home/john-williams/Experiences/FavoriteProject/Images favorite-project-images

2. Set the permissions for each directory leading to your images:

john-williams@codermerlin:~$ chmod a+rx Experiences

john-williams@codermerlin:~$ chmod a+rx Experiences/FavoriteProject

3. Set the permissions for the image directory and all images:

john-williams@codermerlin:~$ chmod -R a+rX Experiences/FavoriteProject/Images

Exercises[edit]

ExercisesExercisesIcon.png
  •  J1505  Create a journal and answer all questions. Be sure to include all sections of the journal, properly formatted.
  1. Think of a theme for your composition. Add at least four different images to your canvas following your chosen theme. (You may remove the White House.) Remember to only use images that are licensed appropriately. The images may not overlap.
  2. At least one of the images must be scaled up (i.e. it must be larger than the original source).
  3. At least one of the images must be scaled down (i.e. it must be smaller than the original source).
  4. At least one of the images must be only partially displayed (i.e. the source rectangle does not include the entire image).
  5. Draw a rectangular frame around each image. Each frame must be a different color.
  •  M1505-28  Complete  Merlin Mission Manager  Mission M1505-28.