B4A Library ScaleImageView - Pan and zoom large images

My main reason to restart using B4A was to implement on a mobile device my mapping program which covers the entire UK at various scales and requires the ability to display large map images at a specified zoom level and centered on a specified coordinate and then allow the user to drag and zoom the map.

For some strange reason if you set targetSdkVersion="xx" to more than 13 in the manifest it dramatically reduces the largest Bitmap that can be created from a file so most of my map images then no longer open in TouchImageView, jsTouchImageView and even ImageView. These all rely on opening a full resolution bitmap to display an image. It seems to be a Canvas size limitation. Also I failed to get TouchImageView to reliably pre-zoom and pre-position an image so I struggled on with jsTouchImageView and targetSdkVersion="13" and got an acceptable working version but pre-zooming and pre-positioning at an exact point was a bit problematic and not entirely accurate but usually close enough after a few heuristics. It also still used very large amounts of memory for the decoded bitmap.

Having got the app working I then started looking to try to finally solve the image viewing problems and found some source code on GitHub that was written for just this purpose. Instead of loading the entire image at once it only fully decodes from the image file the areas needed for display. As a bonus the pre-zooming and centering is very accurate and works a treat. So after a bit of difficulty getting it to compile I wrapped it, slightly enhanced to draw a centered point indication and am now extremely happy with my mapping program that can now display huge images and target SDK version 26 and later without using a vast amount of memory.

There is a ScaleImageView.htm file in the attached archive that documents the extremely simple API posted below. As always do what readme.txt says.

I can't put a large image file in the archive as it becomes too big to upload here, so find your own large image and do as Readme.txt says.
ScaleImageView
This is a custom image view designed for displaying huge images.
It includes all the standard gestures for zooming and panning images
and provides some extra useful features for animating the image position and scale.
The aim of this library is to solve some of the common problems when displaying large images in Android.
This view extends View and so inherits all the normal View methods.
This view doesn't extend ImageView and isn't intended as a general purpose replacement for it.
It is specialised for the display of photos and other large images, not the display of 9-patches,
shapes and the other types of drawable that ImageView supports.
Supported gestures are:
One finger drag to pan, Two finger pinch to zoom and double tap to zoom in and out.
Pan while zooming, seamless switch between pan and zoom and fling momentum after panning.
Quick scale (one finger zoom - quick double tap then drag)
Events Click and LongClick are provided whose co-ordinates may be accessed in the event code.
ClickViewX, ClickViewY return the position of the Click or LongClick on the view.
ClickImageX and ClickImageY return the position of the Click or LongClick on the source image.
The OnDraw event provides a Canvas that can be used to draw on the view whenever it is redrawn.
The view can draw a circle at a defined position on the original image.
The circle can either have a fixed size that is a fraction of the screen width
or a variable size that always covers the same area of the original size as it is zoomed.
The associated file, ScaleImage.jar, must be located in the Additional Libraries folder.
The line '#AdditionalJar: ScaleImage' must be added to the Main module.
This library uses code from
That code and this library are licensed under the Apache License 2.0
Copyright [2015] [Dave Morrissey]
Copyright [2018] [Andrew Graham]
Licensed under the Apache License, Version 2.0 (the "License")
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Author: Andrew Graham
Version: 2.3
  • ScaleImageView
    • Events:
      • Click 'The user has tapped on the view. Use ClickImage or ClickView for the coordinates.
      • LongClick 'The user has long pressed the view. Use ClickImage or ClickView for the coordinates.
      • OnDraw (viewcanvas As Canvas) 'The view is being redrawn. Use viewcanvas to draw on it.
    • Functions:
      • BringToFront
      • DesignerCreateView (base As Panel, lw As Label, props As Map)
      • Initialize (arg1 As String)
      • Invalidate
      • Invalidate2 (arg0 As android.graphics.Rect)
      • Invalidate3 (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
      • IsInitialized As Boolean
      • Recycle
        Releases all resources the view is using and resets the state, nulling any fields that use significant memory.
        After you have called this method, the view can be re-used by setting a new image.
        Settings are remembered but state (scale and center) is forgotten.
      • RemoveView
      • RequestFocus As Boolean
      • ResetScaleAndCenter
        Zooms the image out to minimum scale and centers it on the screen according to the view's settings.
      • SendToBack
      • SetBackgroundImage (arg0 As android.graphics.Bitmap) As BitmapDrawable
      • SetColorAnimated (arg0 As Int, arg1 As Int, arg2 As Int)
      • SetLayout (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
      • SetLayoutAnimated (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int, arg4 As Int)
      • SetScaleAndCenter (scale As Float, x As Float, y As Float, duration As Int)
        Set the zoom of the displayed image and center it on the point (x,y).
        x and y are width and height factor values of the full image size between 0 and 1.
        PanLimit should be set to PAN_LIMIT_CENTER if any point is to be centered.
        Duration sets the duration of the transition in milliseconds.
        Returns False if the image is not ready and the transition was not made otherwise True.
      • SetScaleAndCenterPixels (scale As Float, x As Int, y As Int, duration As Int) As Boolean
        Set the zoom of the displayed image and center it on the point (x,y).
        x and y are full image size x and y pixel values.
        PanLimit should be set to PAN_LIMIT_CENTER if any point is to be centered.
        Duration sets the duration of the transition in milliseconds.
        Returns False if the image is not ready and the transition was not made otherwise True.
      • SetVisibleAnimated (arg0 As Int, arg1 As Boolean)
      • SourceXYtoViewXY (sourcex As Int, sourcey As Int) As Float()
        Returns a Float array containing the X and Y pixel position on the view of the specified point of the full size image.
        If the image coordinates are currently off screen, the view coordinates will also be outside the view
        Index 0 of the array contains the X coordinate and index 1 the Y coordinate.
      • ViewXYtoSourceXY (viewx As Int, viewy As Int) As Float()
        Returns a Float array containing the X and Y pixel position on the full size image of the specified point of the view.
        Index 0 of the array contains the X coordinate and index 1 the Y coordinate.
    • Properties:
      • Background As android.graphics.drawable.Drawable
      • CenterX As Float [read only]
        Gets the X pixel value of the full image point which is at the centre of the view.
        Can only be set programatically by SetScaleAndCenter or SetScaleAndCenterPixels
      • CenterY As Float [read only]
        Gets the Y pixel value of the full image point which is at the centre of the view.
        Can only be set programmatically by SetScaleAndCenter or SetScaleAndCenterPixels
      • CircleColor As Int
        Gets or sets the colour of the inner ring of the circle.
        The default is 0xff20b2aa - LightSeaGreen.
      • CircleDrawnRadius As Float [read only]
        Gets the radius of the circle in pixels as last drawn regardless of the state of EnableCircleScale.
        This can be used to position other drawn items relative to the circle.
      • CircleMinimumRadius As Float
        Gets or sets the minimum radius of the circle as a factor between 0 and 1 of the width of the view.
        This prevents the circle being drawn vanishingly small when zoomed out if EnableCircleScale is True.
        The default is 0.02.
      • CircleRadius As Float
        Gets or sets the radius of the circle as a factor between 0 and 1 of the width of the view or of the full image.
        If EnableCircleScale is True the factor is that of the full size image width.
        If EnableCircleScale is False the factor is that of the width of the view.
        The default is 0.002 which is appropriate if EnableCircleScale is True.
      • CircleWidth As Float
        Gets or sets the width of stroke used to draw the circle (not the radius).
        The value is a factor between 0 and 1 of the radius of the circle as drawn. The default is 0.2.
      • CircleX As Float
        Gets or sets the X position factor of the point on the full image at which to draw the circle.
        The default is 0.5, the centre of the image.
      • CircleXPixels As Float
        Gets or sets the X position in pixels of the point on the full image at which to draw the circle.
        The default is the centre of the image.
      • CircleY As Float
        Gets or sets the Y position factor of the point on the full image at which to draw the circle.
        The default is 0.5, the centre of the image.
      • CircleYPixels As Float
        Gets or sets the Y position in pixels of the point on the full image at which to draw the circle.
        The default is the centre of the image.
      • ClickImageX As Float [read only]
        When accessed in a Click or LongClick event gets the X pixel position on the full size image of the point clicked.
      • ClickImageY As Float [read only]
        When accessed in a Click or LongClick event gets the Y pixel position on the full size image of the point clicked.
      • ClickViewX As Float [read only]
        When accessed in a Click or LongClick event gets the X pixel position on the view of the point clicked.
      • ClickViewY As Float [read only]
        When accessed in a Click or LongClick event gets the Y pixel position on the view of the point clicked.
      • Color As Int [write only]
      • DoubleTapZoomDuration As Int [write only]
        Sets the duration of a double tap zoom animation, in milliseconds. The default is 500ms.
      • EnableCircle As Boolean
        Gets or sets whether a circle will be drawn at the image coordinates specified by CircleX and CircleY.
        The default is False.
      • EnableCircleScale As Boolean
        Gets or sets whether the size of the circle will increase and decrease when the image is zoomed.
        If True the circle will resize to bound the same features on the image whatever the zoom.
        If False the circle will maintain a fixed size on the screen of the device.
        The default is True.
      • Enabled As Boolean
      • Height As Int
      • Image As android.graphics.Bitmap [write]
        Load an existing Bitmap into the view.
        This is unsuitable for large images because it bypasses subsampling and may cause OutOfMemoryErrors.
        This is an easy way to add pan and zoom functionality to an image already in memory
      • Image As android.graphics.Bitmap [read]
        Returns a Bitmap containing the image presently displayed in the ScaleImageView
      • ImageFile As String [write only]
        Load an image from a file saved on the device file system into the view.
        This method can display JPG and PNG images of any size.
        In order to support huge images without running out of memory, a sub-sampled base layer is first loaded.
        Higher resolution tiles are loaded for the visible area as the user zooms in.
      • IsReady As Boolean [read only]
        Gets whether the view is initialised, has dimensions and will display an image.
        Returns True if the view is ready to display an image and accept touch gestures.
      • Left As Int
      • MaxZoom As Float
        Gets or set the maximum permitted zoom level of the displayed image. The default is 2.0.
        The minimum zoom level is set automatically to fit the entire image to the view.
      • Orientation As Int
        Gets or set the orientation of the image relative to the source file.
        Valid values for orientation are 0, 90, 180, 270 and -1 or one of the ORIENTATION values.
      • ORIENTATION_0 As Int [read only]
        Display the image file in its native orientation. Value is 0.
      • ORIENTATION_180 As Int [read only]
        Rotate the image 180 degrees. Value is 180.
      • ORIENTATION_270 As Int [read only]
        Rotate the image 270 degrees clockwise. Value is 270.
      • ORIENTATION_90 As Int [read only]
        Rotate the image 90 degrees clockwise. Value is 90.
      • ORIENTATION_USE_EXIF As Int [read only]
        Attempt to use EXIF information on the image to rotate it. Value is -1.
      • Padding As Int()
      • PAN_LIMIT_CENTER As Int [read only]
        Allow the image to be panned until a corner reaches the center of the screen but no further.
        Useful when you need to pan any spot on the image to the exact center of the screen.
      • PAN_LIMIT_INSIDE As Int [read only]
        Don't allow the image to be panned off screen.
        As much of the image as possible is always displayed, centered in the view when it is smaller.
      • PAN_LIMIT_OUTSIDE As Int [read only]
        Allow the image to be panned until it is just off screen, but no further.
        The edge of the image will stop when it is flush with the screen edge.
      • PanLimit As Int [write only]
        Sets the image pan limit to one of the PAN_LIMIT values.
        The default is 3 = PAN_LIMIT_CENTER.
      • Parent As Object [read only]
      • Scale As Float [read only]
        Get the current scale of the image as set by the user.
        Can only be set programmatically by SetScaleAndCenter or SetScaleAndCenterPixels.
      • SrcHeight As Int [read only]
        Get the height of the current full size image in pixels.
        Note that this does not take the applied rotation into account.
      • SrcWidth As Int [read only]
        Get the width of the current full size image in pixels.
        Note that this does not take the applied rotation into account.
      • Tag As Object
      • TileBackgroundColor As Int [write only]
        Default none. Renders a background color behind tiles. Useful when rendering a transparent PNG.
        Note: transparent PNGs require double the memory of PNGs with no alpha layer, and may cause out of memory errors.
        The default is none.
      • Top As Int
      • Visible As Boolean
      • Width As Int


EDIT: Version 2.00 now posted. ScaleImageView is now a Custom View. The API above has been updated. See Post #3 below for more details.
EDIT: Version 2.20 now posted. The API above has been updated. See Post #36 below for more details.
EDIT: Version 2.30 now posted. A readable Image property has been added to get the image presently displayed by ScaleImageView. See post #37.
 

Attachments

  • ScaleImageView_v2.30.zip
    11.4 KB · Views: 901
  • ScaleImageView_v2.20.zip
    84 KB · Views: 809
Last edited:

agraham

Expert
Licensed User
Longtime User
Version 2.00 is a significant upgrade to ScaleImageView.

ScaleImageView is now a Custom View and can be added from the Designer. The intrinsic circle drawing API has been refined.

Being inherited from the View class ScaleImageView always supported Click and LongClick events but now has the annotations in the library for B4A to recognise this. As Click and LongClick events do not support parameters, and the other gesture events are used internally by ScaleImageView, the ClickImage and ClickView properties can be used within event code to locate the coordinates of either event.

As the image in ScaleImageView is not decoded into a Bitmap (that is the whole raison d'etre for its existence) it is not possible to draw on a large image to annotate it. Now an OnDraw event has been added which supplies a Canvas that allows drawing onto the ScaleImageView. Methods and properties are provided to synchronise drawing on the view with the displayed image. Although the drawn annotations cannot be saved as a new image it is feasible to save and recall annotations to a file that can be associated with the large image file so making it appear as though the annotations were added to the actual image.
 
Last edited:

agraham

Expert
Licensed User
Longtime User
A thought about annotating an image. ScaleImageView can display a conventional Bitmap by assigning it to the Image property. I haven't tried this but it should be possible to draw on this Bitmap and save it as a new image with the annotations. However such annotations will scale with the image when displayed. Maintaining the annotations separately and drawing them directly on the view allows them to be scaled independently of the image.
 

Rainer@B4A

Member
Licensed User
Longtime User
I start testing this lib, but got the following compiler error message:

B4A Version: 7.30
Parse den Code. (0.00s)
Kompiliere den Code. (0.05s)
Kompiliere Layoutcode. (0.00s)
Organisiere Libraries. (0.00s)
Generiere R Datei. (0.03s)
Kompiliere Debugger-Code (0.69s)
Kompiliere generierten Java Code. Error
B4A line: 54
Activity.AddView(ScaleImageView1, 0%y, 1%y, 100%x
javac 1.8.0_151
src\b4a\example\main.java:394: error: cannot access SubsamplingScaleImageView
mostCurrent._activity.AddView((android.view.View)(mostCurrent._scaleimageview1.getObject()),anywheresoftware.b4a.keywords.Common.PerYToCurrent((float) (0),mostCurrent.activityBA),anywheresoftware.b4a.keywords.Common.PerYToCurrent((float) (1),mostCurrent.activityBA),anywheresoftware.b4a.keywords.Common.PerXToCurrent((float) (100),mostCurrent.activityBA),anywheresoftware.b4a.keywords.Common.PerYToCurrent((float) (98),mostCurrent.activityBA));
^
class file for com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView not found
 

Rainer@B4A

Member
Licensed User
Longtime User
I did not recognized "#AdditionalJar: ScaleImage" in your example.
Now it seems to work perfect.
Many Thanks
 

Johnson Samuel

Member
Licensed User
Longtime User
I was trying scale image view, Its Works Nice. The Only Problem I am facing is A text "Some Text" appears in the middle of the image. How to get rid of that text.?
 

js486dog

Active Member
Licensed User
Longtime User
My main reason to restart using B4A was to implement on a mobile device my mapping program which covers the entire UK at various scales and requires the ability to display large map images at a specified zoom level and centered on a specified coordinate and then allow the user to drag and zoom the map.

For some strange reason if you set targetSdkVersion="xx" to more than 13 in the manifest it dramatically reduces the largest Bitmap that can be created from a file so most of my map images then no longer open in TouchImageView, jsTouchImageView and even ImageView. These all rely on opening a full resolution bitmap to display an image. It seems to be a Canvas size limitation. Also I failed to get TouchImageView to reliably pre-zoom and pre-position an image so I struggled on with jsTouchImageView and targetSdkVersion="13" and got an acceptable working version but pre-zooming and pre-positioning at an exact point was a bit problematic and not entirely accurate but usually close enough after a few heuristics. It also still used very large amounts of memory for the decoded bitmap.

Having got the app working I then started looking to try to finally solve the image viewing problems and found some source code on GitHub that was written for just this purpose. Instead of loading the entire image at once it only fully decodes from the image file the areas needed for display. As a bonus the pre-zooming and centering is very accurate and works a treat. So after a bit of difficulty getting it to compile I wrapped it, slightly enhanced to draw a centered point indication and am now extremely happy with my mapping program that can now display huge images and target SDK version 26 and later without using a vast amount of memory.

There is a ScaleImageView.htm file in the attached archive that documents the extremely simple API posted below. As always do what readme.txt says.

I can't put a large image file in the archive as it becomes too big to upload here, so find your own large image and do as Readme.txt says.

ScaleImageView
This is a custom image view designed for displaying huge images.
It includes all the standard gestures for zooming and panning images
and provides some extra useful features for animating the image position and scale.
The aim of this library is to solve some of the common problems when displaying large images in Android.
This view extends View and so inherits all the normal View methods.
This view doesn't extend ImageView and isn't intended as a general purpose replacement for it.
It is specialised for the display of photos and other large images, not the display of 9-patches,
shapes and the other types of drawable that ImageView supports.
Supported gestures are:
One finger drag to pan, Two finger pinch to zoom and double tap to zoom in and out.
Pan while zooming, seamless switch between pan and zoom and fling momentum after panning.
Quick scale (one finger zoom - quick double tap then drag)
Events Click and LongClick are provided whose co-ordinates may be accessed in the event code.
ClickViewX, ClickViewY return the position of the Click or LongClick on the view.
ClickImageX and ClickImageY return the position of the Click or LongClick on the source image.
The OnDraw event provides a Canvas that can be used to draw on the view whenever it is redrawn.
The view can draw a circle at a defined position on the original image.
The circle can either have a fixed size that is a fraction of the screen width
or a variable size that always covers the same area of the original size as it is zoomed.
The associated file, ScaleImage.jar, must be located in the Additional Libraries folder.
The line '#AdditionalJar: ScaleImage' must be added to the Main module.
This library uses code from
https://github.com/davemorrissey/subsampling-scale-image-view
That code and this library are licensed under the Apache License 2.0
Copyright [2015] [Dave Morrissey]
Copyright [2018] [Andrew Graham]
Licensed under the Apache License, Version 2.0 (the "License")
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Author: Andrew Graham
Version: 2.0
  • ScaleImageView
    • Events:
      • Click 'The user has tapped on the view. Use ClickImage or ClickView for the coordinates.
      • LongClick 'The user has long pressed the view. Use ClickImage or ClickView for the coordinates.
      • OnDraw (viewcanvas As Canvas) 'The view is being redrawn. Use viewcanvas to draw on it.
    • Functions:
      • BringToFront
      • DesignerCreateView (base As Panel, lw As Label, props As Map)
      • Initialize (arg1 As String)
      • Invalidate
      • Invalidate2 (arg0 As android.graphics.Rect)
      • Invalidate3 (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
      • IsInitialized As Boolean
      • RemoveView
      • RequestFocus As Boolean
      • SendToBack
      • SetBackgroundImage (arg0 As android.graphics.Bitmap) As BitmapDrawable
      • SetColorAnimated (arg0 As Int, arg1 As Int, arg2 As Int)
      • SetLayout (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
      • SetLayoutAnimated (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int, arg4 As Int)
      • setMaxZoom As Float
        Gets or set the maximum permitted zoom level of the displayed image. The default is 2.0.
        The minimum zoom level is set automatically to fit the entire image to the view.
      • SetScaleAndCenter (scale As Float, x As Float, y As Float, duration As Int)
        Set the zoom of the displayed image and center it on the point (x,y).
        x and y are width and height factor values of the full image size between 0 and 1.
        PanLimit should be set to PAN_LIMIT_CENTER if any point is to be centered.
        Duration sets the duration of the transition in milliseconds.
        Returns False if the image is not ready and the transition was not made otherwise True.
      • SetScaleAndCenterPixels (scale As Float, x As Int, y As Int, duration As Int) As Boolean
        Set the zoom of the displayed image and center it on the point (x,y).
        x and y are full image size x and y pixel values.
        PanLimit should be set to PAN_LIMIT_CENTER if any point is to be centered.
        Duration sets the duration of the transition in milliseconds.
        Returns False if the image is not ready and the transition was not made otherwise True.
      • SetVisibleAnimated (arg0 As Int, arg1 As Boolean)
      • SourceXYtoViewXY (sourcex As Int, sourcey As Int) As Float()
        Returns a Float array containing the X and Y pixel position on the view of the specified point of the full size image.
        If the image coordinates are currently off screen, the view coordinates will also be outside the view
        Index 0 of the array contains the X coordinate and index 1 the Y coordinate.
      • ViewXYtoSourceXY (viewx As Int, viewy As Int) As Float()
        Returns a Float array containing the X and Y pixel position on the full size image of the specified point of the view.
        Index 0 of the array contains the X coordinate and index 1 the Y coordinate.
    • Properties:
      • Background As android.graphics.drawable.Drawable
      • CenterX As Float [read only]
        Gets the X pixel value of the full image point which is at the centre of the view.
        Can only be set programatically by SetScaleAndCenter or SetScaleAndCenterPixels
      • CenterY As Float [read only]
        Gets the Y pixel value of the full image point which is at the centre of the view.
        Can only be set programmatically by SetScaleAndCenter or SetScaleAndCenterPixels
      • CircleColor As Int
        Gets or sets the colour of the inner ring of the circle.
        The default is 0xff20b2aa - LightSeaGreen.
      • CircleDrawnRadius As Float [read only]
        Gets the radius of the circle in pixels as last drawn regardless of the state of EnableCircleScale.
        This can be used to position other drawn items relative to the circle.
      • CircleMinimumRadius As Float
        Gets or sets the minimum radius of the circle as a factor between 0 and 1 of the width of the view.
        This prevents the circle being drawn vanishingly small when zoomed out if EnableCircleScale is True.
        The default is 0.02.
      • CircleRadius As Float
        Gets or sets the radius of the circle as a factor between 0 and 1 of the width of the view or of the full image.
        If EnableCircleScale is True the factor is that of the full size image width.
        If EnableCircleScale is False the factor is that of the width of the view.
        The default is 0.002 which is appropriate if EnableCircleScale is True.
      • CircleWidth As Float
        Gets or sets the width of stroke used to draw the circle (not the radius).
        The value is a factor between 0 and 1 of the radius of the circle as drawn. The default is 0.2.
      • CircleX As Float
        Gets or sets the X position factor of the point on the full image at which to draw the circle.
        The default is 0.5, the centre of the image.
      • CircleXPixels As Float
        Gets or sets the X position in pixels of the point on the full image at which to draw the circle.
        The default is the centre of the image.
      • CircleY As Float
        Gets or sets the Y position factor of the point on the full image at which to draw the circle.
        The default is 0.5, the centre of the image.
      • CircleYPixels As Float
        Gets or sets the Y position in pixels of the point on the full image at which to draw the circle.
        The default is the centre of the image.
      • ClickImageX As Float [read only]
        When accessed in a Click or Longclickevent gets the X pixel position on the full size image of the point clicked.
      • ClickImageY As Float [read only]
        When accessed in a Click or LongClick event gets the Y pixel position on the full size image of the point clicked.
      • ClickViewX As Float [read only]
        When accessed in a Click or LongClick event gets the X pixel position on the view of the point clicked.
      • ClickViewY As Float [read only]
        When accessed in a Click or LongClick event gets the Y pixel position on the view of the point clicked.
      • Color As Int [write only]
      • EnableCircle As Boolean
        Gets or sets whether a circle will be drawn at the image coordinates specified by CircleX and CircleY.
        The default is False.
      • EnableCircleScale As Boolean
        Gets or sets whether the size of the circle will increase and decrease when the image is zoomed.
        If True the circle will resize to bound the same features on the image whatever the zoom.
        If False the circle will maintain a fixed size on the screen of the device.
        The default is True.
      • Enabled As Boolean
      • Height As Int
      • Image As android.graphics.Bitmap [write only]
        Load an existing Bitmap into the view.
        This is unsuitable for large images because it bypasses subsampling and may cause OutOfMemoryErrors.
        This is an easy way to add pan and zoom functionality to an image already in memory.
      • ImageFile As String [write only]
        Load an image from a file saved on the device file system into the view.
        This method can display JPG and PNG images of any size.
        In order to support huge images without running out of memory, a sub-sampled base layer is first loaded.
        Higher resolution tiles are loaded for the visible area as the user zooms in.
      • IsReady As Boolean [read only]
        Gets whether the view is initialised, has dimensions and will display an image.
        Returns True if the view is ready to display an image and accept touch gestures.
      • Left As Int
      • MaxZoom As Float [write only]
      • Padding As Int()
      • PAN_LIMIT_CENTER As Int [read only]
        Allow the image to be panned until a corner reaches the center of the screen but no further.
        Useful when you need to pan any spot on the image to the exact center of the screen.
      • PAN_LIMIT_INSIDE As Int [read only]
        Don't allow the image to be panned off screen.
        As much of the image as possible is always displayed, centered in the view when it is smaller.
      • PAN_LIMIT_OUTSIDE As Int [read only]
        Allow the image to be panned until it is just off screen, but no further.
        The edge of the image will stop when it is flush with the screen edge.
      • PanLimit As Int [write only]
        Sets the image pan limit to one of the PAN_LIMIT values.
        The default is 3 = PAN_LIMIT_CENTER.
      • Parent As Object [read only]
      • Scale As Float [read only]
        Get the current scale of the image as set by the user.
        Can only be set programmatically by SetScaleAndCenter or SetScaleAndCenterPixels.
      • SrcHeight As Int [read only]
        Get the height of the current full size image in pixels.
      • SrcWidth As Int [read only]
        Get the width of the current full size image in pixels.
      • Tag As Object
      • Top As Int
      • Visible As Boolean
      • Width As Int


    • EDIT: Version 2.00 now posted. ScaleImageView is now a Custom View. The API above has been updated. See Post #3 below for more details.
"agraham", thank you very much for ScaleImageView.

PROS:
* Usable for mapping apps also with GPS.
* Possibility to use raster Map World File (jpg-jgw). Stupid map tiles are not needed.
* This is very valuable library for mapping apps.

Please is it something similar also for B4J ?
 

agraham

Expert
Licensed User
Longtime User
Please is it something similar also for B4J ?
I am afraid not. I do have a desktop version of my mapping program which uses the same maps and data as the Android version but it is written in Basic4ppc and C# and uses the Windows Forms PictureBox to display the maps which is of no use to you :(
 

js486dog

Active Member
Licensed User
Longtime User
I am afraid not. I do have a desktop version of my mapping program which uses the same maps and data as the Android version but it is written in Basic4ppc and C# and uses the Windows Forms PictureBox to display the maps which is of no use to you :(
Thank you very much for response. Also I have done desktop mapping program with my old VB6 and MapWinGis OCX (still works on Win10).
Thank you very much for ScaleImageView for B4A. It is great Library.
 

Caps64

Member
It is a fantastic object, thank you for sharing it.
Is there a way to detect a swipe gesture on this object ? I would like to implement a left/right swipe to change the current picture to the previous/next one present in a folder.
 

agraham

Expert
Licensed User
Longtime User
I haven't actually tried this but I think it would work. You could implement the OnDraw event and check the if the value of CenterX was near or at the edge of the image. PanLimit would need to be set to either PAN_LIMIT_CENTER or PAN_LIMIT_INSIDE for this to work.
 

Caps64

Member
Thank you Agraham for your answer. I tried this:
B4X:
Sub SCALEIMAGE_OnDraw(viewcanvas As Canvas)
    Dim siv As ScaleImageView = Sender
    Log("SIV_OnDraw: " & siv.CenterX)
End Sub
And it gives always the result (any swipe I try, left/right, long/short):
B4X:
SIV_OnDraw: 480
It gives such response not one but tens/hundreds of times for each gesture.
I tried with both the PanLimit suggested. What do you think ?
 
Last edited:

agraham

Expert
Licensed User
Longtime User
it gives such response not one but tens/hundreds of times for each gesture.
It will - don't worry

I changed the demo ScaleImageView1_OnDraw event to your event code and it works fine for me with PanLimit left at the default of PAN_LIMIT_CENTER.

Swiping right
B4X:
SIV_OnDraw: 1080.63671875
SIV_OnDraw: 979.0734252929688
SIV_OnDraw: 875.5053100585938
SIV_OnDraw: 763.0328369140625
SIV_OnDraw: 646.30517578125
SIV_OnDraw: 526.4202880859375
SIV_OnDraw: 405.5987548828125
SIV_OnDraw: 286.86932373046875
SIV_OnDraw: 174.7533416748047
SIV_OnDraw: 55.511817932128906
SIV_OnDraw: 0
SIV_OnDraw: 0
 

Caps64

Member
I confirm the above output in your demo, but I found that if you don't load a designer layout but create the SIV by code:
B4X:
    ScaleImageView1.Initialize("ScaleImageView1")
    Activity.AddView(ScaleImageView1,0,0,100%x,100%y)
the behaviour is different:
1. the sample image that I load does not move on the screen (that is what I want), while the same image moves when the SIV is created on the designer layout;
2. the SIV_OnDraw return always:
B4X:
SIV_OnDraw=340
In my project the value is always 480, then I think the returned value is the half of the X resolution of the picture loaded. Maybe this can suggest to you something.
 

agraham

Expert
Licensed User
Longtime User
It still works for me if created by code. If I change the demo Viewer.Activity_Create as follows
B4X:
Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Viewer")
    ScaleImageView1.Initialize("ScaleImageView1")
    Activity.AddView(ScaleImageView1,0,0,100%x,100%y)
    ScaleImageView1.PanLimit = ScaleImageView1.PAN_LIMIT_CENTER
    'gestures.SetOnGestureListener(Panel1, "Panel1")
End Sub
I need to set PanLimit explicitly in this case.


Swipe right
B4X:
SIV_OnDraw: 329.9976806640625
SIV_OnDraw: 285.2685852050781
SIV_OnDraw: 245.01065063476562
SIV_OnDraw: 204.19178771972656
SIV_OnDraw: 165.38705444335938
SIV_OnDraw: 130.70529174804688
SIV_OnDraw: 95.8104019165039
SIV_OnDraw: 62.930233001708984
SIV_OnDraw: 33.824066162109375
SIV_OnDraw: 4.8539276123046875
SIV_OnDraw: 0
SIV_OnDraw: 0

You could also use a Timer instead of the OnDraw event which might be simpler as you will need to set and check some flags in the OnDraw event to ignore things while the new image is loaded.
 
Top