Skip to content

Commit 7893a08

Browse files
committed
[[ Canvas ]] Add ability to get density property of canvas images
This patch adds two new properties to canvas image values, `density` and `metadata`. The density property returns the image density in dots-per-inch, allowing images to be scaled for display. The metadata returns data associated with the image in the form of an array.
1 parent eea9e33 commit 7893a08

File tree

6 files changed

+173
-66
lines changed

6 files changed

+173
-66
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# LiveCode Builder Host Library
2+
## Canvas library
3+
4+
New syntax has been added to enable getting image metadata and density
5+
information.
6+
7+
The image 'metadata' property returns data associated with the image in the
8+
form of an array.
9+
10+
The image 'density' property returns an images density in dots per inch (DPI).
11+
This allows widgets to scale images appropriately for display.

engine/src/canvas.lcb

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2186,8 +2186,8 @@ end syntax
21862186

21872187
public foreign handler MCCanvasImageGetWidth(in pImage as Image, out rWidth as UInt32) returns nothing binds to "<builtin>"
21882188
public foreign handler MCCanvasImageGetHeight(in pImage as Image, out rHeight as UInt32) returns nothing binds to "<builtin>"
2189-
// TODO - add support for metadata
2190-
//public foreign handler MCCanvasImageGetMetadata(in pImage as Image, out rMetadata as Array) returns nothing binds to "<builtin>"
2189+
public foreign handler MCCanvasImageGetMetadata(in pImage as Image, out rMetadata as Array) returns nothing binds to "<builtin>"
2190+
public foreign handler MCCanvasImageGetDensity(in pImage as Image, out rDensity as CDouble) returns nothing binds to "<builtin>"
21912191
public foreign handler MCCanvasImageGetPixels(in pImage as Image, out rPixels as Data) returns nothing binds to "<builtin>"
21922192
// TODO - add image frame index property?
21932193

@@ -2245,11 +2245,65 @@ end syntax
22452245

22462246
//////////
22472247

2248-
//syntax ImageMetadataProperty is prefix operator with property precedence
2249-
// "the" "metadata" "of" <mImage: Expression>
2250-
//begin
2251-
// MCCanvasImageGetMetadata(mImage, output)
2252-
//end syntax
2248+
/**
2249+
Summary: the metadata associated with an image.
2250+
2251+
mImage: An expression which evaluates to an image.
2252+
2253+
Description: An array containing metadata associated with an image.
2254+
2255+
Example:
2256+
// Load an image from a file
2257+
variable tImage as Image
2258+
put image from file "images/logo.png" into tImage
2259+
2260+
// get the image metadata
2261+
variable tMetadata as Array
2262+
put the metadata of tImage into tMetadata
2263+
2264+
// get image density in DPI from the image metadata
2265+
variable tDPI as Number
2266+
if "density" is among the keys of tMetadata then
2267+
put tMetadata["density"] into tDPI
2268+
else
2269+
put 72 into tDPI
2270+
end if
2271+
2272+
Tags: canvas
2273+
*/
2274+
syntax ImageMetadataProperty is prefix operator with property precedence
2275+
"the" "metadata" "of" <mImage: Expression>
2276+
begin
2277+
MCCanvasImageGetMetadata(mImage, output)
2278+
end syntax
2279+
2280+
//////////
2281+
2282+
/**
2283+
Summary: The density of an image.
2284+
2285+
mImage: An expression which evaluates to an image.
2286+
2287+
Description: The image density in DPI (dots per inch)
2288+
2289+
Example:
2290+
// Load an image from a file
2291+
variable tImage as Image
2292+
put image from file "images/logo.png" into tImage
2293+
2294+
// scale down image based on standard DPI of 72.
2295+
variable tScale as Number
2296+
put (72 / the density of tImage) into tScale
2297+
scale this canvas by [tScale, tScale]
2298+
draw tImage into rectangle [0,0,the width of tImage,the height of tImage] of this canvas
2299+
2300+
Tags: canvas
2301+
*/
2302+
syntax ImageDensityProperty is prefix operator with property precedence
2303+
"the" "density" "of" <mImage: Expression>
2304+
begin
2305+
MCCanvasImageGetDensity(mImage, output)
2306+
end syntax
22532307

22542308
//////////
22552309

engine/src/exec-interface-image.cpp

Lines changed: 32 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
4040

4141
#include "exec-interface.h"
4242
#include "graphics_util.h"
43+
#include "module-canvas.h"
4344

4445
//////////
4546

@@ -843,56 +844,35 @@ void MCImage::SetVisible(MCExecContext& ctxt, uinteger_t part, bool setting)
843844
// MERG-2015-02-11: [[ ImageMetadata ]] Refactored image metadata property
844845
void MCImage::GetMetadataProperty(MCExecContext& ctxt, MCNameRef p_prop, MCExecValue& r_value)
845846
{
846-
// AL-2015-07-22: [[ Bug 15620 ]] If image rep is nil, don't try to fetch metadata
847-
bool t_stat;
848-
t_stat = m_rep != nil;
849-
850-
MCImageMetadata t_metadata;
851-
if (t_stat)
852-
{
853-
m_rep->GetMetadata(t_metadata);
854-
t_stat = t_metadata.has_density;
855-
}
856-
857-
MCExecValue t_density;
858-
if (t_stat)
859-
{
860-
t_density . double_value = t_metadata . density;
861-
t_density . type = kMCExecValueTypeDouble;
862-
}
863-
864-
if (t_stat)
865-
{
866-
if (p_prop == nil || MCNameIsEmpty(p_prop))
867-
{
868-
MCAutoArrayRef v;
869-
t_stat = MCArrayCreateMutable(&v);
870-
871-
MCValueRef t_prop_value;
872-
873-
if (t_stat)
874-
{
875-
MCExecTypeConvertAndReleaseAlways(ctxt, t_density . type, &t_density , kMCExecValueTypeValueRef, &t_prop_value);
876-
t_stat = !ctxt . HasError();
877-
}
878-
879-
if (t_stat)
880-
t_stat = MCArrayStoreValue(*v, false, MCNAME("density"), t_prop_value);
881-
882-
if (t_stat)
883-
{
884-
r_value . arrayref_value = MCValueRetain(*v);
885-
r_value . type = kMCExecValueTypeArrayRef;
886-
}
887-
}
888-
else
889-
r_value = t_density;
890-
}
891-
892-
if (!t_stat)
893-
{
894-
r_value . arrayref_value = MCValueRetain(kMCEmptyArray);
895-
r_value . type = kMCExecValueTypeArrayRef;
896-
}
897-
847+
// AL-2015-07-22: [[ Bug 15620 ]] If image rep is nil, don't try to fetch metadata
848+
bool t_stat;
849+
t_stat = m_rep != nil;
850+
851+
MCAutoArrayRef t_metadata;
852+
if (t_stat)
853+
t_stat = MCImageRepGetMetadata(m_rep, &t_metadata);
854+
855+
if (t_stat)
856+
{
857+
if (p_prop == nil || MCNameIsEmpty(p_prop))
858+
{
859+
r_value . arrayref_value = MCValueRetain(*t_metadata);
860+
r_value . type = kMCExecValueTypeArrayRef;
861+
}
862+
else
863+
{
864+
t_stat = MCArrayFetchValue(*t_metadata, true, p_prop, r_value.valueref_value);
865+
if (t_stat)
866+
{
867+
MCValueRetain(r_value.valueref_value);
868+
r_value.type = kMCExecValueTypeValueRef;
869+
}
870+
}
871+
}
872+
873+
if (!t_stat)
874+
{
875+
r_value . arrayref_value = MCValueRetain(kMCEmptyArray);
876+
r_value . type = kMCExecValueTypeArrayRef;
877+
}
898878
}

engine/src/image_rep.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,42 @@ bool MCImageRepGetFrameDuration(MCImageRep *p_image_rep, uint32_t p_frame, uint3
893893
return p_image_rep->GetFrameDuration(p_frame, r_duration);
894894
}
895895

896+
bool MCImageRepGetMetadata(MCImageRep *p_image_rep, MCArrayRef &r_metadata)
897+
{
898+
MCImageMetadata t_metadata;
899+
if (!p_image_rep->GetMetadata(t_metadata))
900+
return false;
901+
902+
MCAutoArrayRef t_metadata_array;
903+
if (!MCArrayCreateMutable(&t_metadata_array))
904+
return false;
905+
906+
if (t_metadata.has_density)
907+
{
908+
MCAutoNumberRef t_density;
909+
if (!MCNumberCreateWithReal(t_metadata.density, &t_density))
910+
return false;
911+
if (!MCArrayStoreValue(*t_metadata_array, false, MCNAME("density"), *t_density))
912+
return false;
913+
}
914+
/* TODO - support other metadata fields */
915+
916+
return MCArrayCopy(*t_metadata_array, r_metadata);
917+
}
918+
919+
bool MCImageRepGetDensity(MCImageRep *p_image_rep, double &r_density)
920+
{
921+
MCImageMetadata t_metadata;
922+
if (!p_image_rep->GetMetadata(t_metadata) || !t_metadata.has_density)
923+
{
924+
r_density = 72.0;
925+
return true;
926+
}
927+
928+
r_density = t_metadata.density;
929+
return true;
930+
}
931+
896932
bool MCImageRepLock(MCImageRep *p_image_rep, uint32_t p_index, MCGFloat p_density, MCGImageFrame &r_frame)
897933
{
898934
return p_image_rep->LockImageFrame(p_index, p_density, r_frame);

engine/src/module-canvas.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@ MC_DLLEXPORT_DEF MCTypeInfoRef kMCCanvasImageRepReferencedErrorTypeInfo;
488488
MC_DLLEXPORT_DEF MCTypeInfoRef kMCCanvasImageRepDataErrorTypeInfo;
489489
MC_DLLEXPORT_DEF MCTypeInfoRef kMCCanvasImageRepPixelsErrorTypeInfo;
490490
MC_DLLEXPORT_DEF MCTypeInfoRef kMCCanvasImageRepGetGeometryErrorTypeInfo;
491+
MC_DLLEXPORT_DEF MCTypeInfoRef kMCCanvasImageRepGetMetadataErrorTypeInfo;
492+
MC_DLLEXPORT_DEF MCTypeInfoRef kMCCanvasImageRepGetDensityErrorTypeInfo;
491493
MC_DLLEXPORT_DEF MCTypeInfoRef kMCCanvasImageRepLockErrorTypeInfo;
492494

493495
MC_DLLEXPORT_DEF MCTypeInfoRef kMCCanvasGradientInvalidRampErrorTypeInfo;
@@ -1969,6 +1971,20 @@ void MCCanvasImageGetHeight(MCCanvasImageRef p_image, uint32_t &r_height)
19691971
r_height = t_height;
19701972
}
19711973

1974+
MC_DLLEXPORT_DEF
1975+
void MCCanvasImageGetMetadata(MCCanvasImageRef p_image, MCArrayRef &r_metadata)
1976+
{
1977+
if (!MCImageRepGetMetadata(MCCanvasImageGetImageRep(p_image), r_metadata))
1978+
MCCanvasThrowError(kMCCanvasImageRepGetMetadataErrorTypeInfo);
1979+
}
1980+
1981+
MC_DLLEXPORT_DEF
1982+
void MCCanvasImageGetDensity(MCCanvasImageRef p_image, double &r_density)
1983+
{
1984+
if (!MCImageRepGetDensity(MCCanvasImageGetImageRep(p_image), r_density))
1985+
MCCanvasThrowError(kMCCanvasImageRepGetDensityErrorTypeInfo);
1986+
}
1987+
19721988
MC_DLLEXPORT_DEF
19731989
void MCCanvasImageGetPixels(MCCanvasImageRef p_image, MCDataRef &r_pixels)
19741990
{
@@ -2015,11 +2031,6 @@ void MCCanvasImageGetPixels(MCCanvasImageRef p_image, MCDataRef &r_pixels)
20152031
MCImageRepUnlockRaster(t_image_rep, 0, t_raster);
20162032
}
20172033

2018-
void MCCanvasImageGetMetadata(MCCanvasImageRef p_image, MCArrayRef &r_metadata)
2019-
{
2020-
// TODO - implement image metadata
2021-
}
2022-
20232034
////////////////////////////////////////////////////////////////////////////////
20242035

20252036
// Solid Paint
@@ -6388,6 +6399,14 @@ bool MCCanvasErrorsInitialize()
63886399
if (!MCNamedErrorTypeInfoCreate(MCNAME("com.livecode.canvas.ImageRepGetGeometryError"), MCNAME("canvas"), MCSTR("Unable to get image geometry."), kMCCanvasImageRepGetGeometryErrorTypeInfo))
63896400
return false;
63906401

6402+
kMCCanvasImageRepGetMetadataErrorTypeInfo = nil;
6403+
if (!MCNamedErrorTypeInfoCreate(MCNAME("com.livecode.canvas.ImageRepGetMetadataError"), MCNAME("canvas"), MCSTR("Unable to get image metadata."), kMCCanvasImageRepGetMetadataErrorTypeInfo))
6404+
return false;
6405+
6406+
kMCCanvasImageRepGetDensityErrorTypeInfo = nil;
6407+
if (!MCNamedErrorTypeInfoCreate(MCNAME("com.livecode.canvas.ImageRepGetDensityError"), MCNAME("canvas"), MCSTR("Unable to get image density."), kMCCanvasImageRepGetDensityErrorTypeInfo))
6408+
return false;
6409+
63916410
kMCCanvasImageRepLockErrorTypeInfo = nil;
63926411
if (!MCNamedErrorTypeInfoCreate(MCNAME("com.livecode.canvas.ImageRepLockError"), MCNAME("canvas"), MCSTR("Unable to lock image pixels."), kMCCanvasImageRepLockErrorTypeInfo))
63936412
return false;
@@ -6452,6 +6471,8 @@ void MCCanvasErrorsFinalize()
64526471
MCValueRelease(kMCCanvasImageRepDataErrorTypeInfo);
64536472
MCValueRelease(kMCCanvasImageRepPixelsErrorTypeInfo);
64546473
MCValueRelease(kMCCanvasImageRepGetGeometryErrorTypeInfo);
6474+
MCValueRelease(kMCCanvasImageRepGetMetadataErrorTypeInfo);
6475+
MCValueRelease(kMCCanvasImageRepGetDensityErrorTypeInfo);
64556476
MCValueRelease(kMCCanvasImageRepLockErrorTypeInfo);
64566477

64576478
MCValueRelease(kMCCanvasGradientStopRangeErrorTypeInfo);

engine/src/module-canvas.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ bool MCImageRepCreateWithPath(MCStringRef p_path, MCImageRep *&r_image_rep);
5656
bool MCImageRepCreateWithData(MCDataRef p_data, MCImageRep *&r_image_rep);
5757
bool MCImageRepCreateWithPixels(MCDataRef p_pixels, uint32_t p_width, uint32_t p_height, MCGPixelFormat p_format, bool p_premultiplied, MCImageRep *&r_image_rep);
5858
bool MCImageRepGetGeometry(MCImageRep *p_image_rep, uint32_t &r_width, uint32_t &r_height);
59+
bool MCImageRepGetMetadata(MCImageRep *p_image_rep, MCArrayRef &r_metadata);
60+
bool MCImageRepGetDensity(MCImageRep *p_image_rep, double &r_density);
5961
bool MCImageRepGetFrameDuration(MCImageRep *p_image_rep, uint32_t p_frame, uint32_t &r_duration);
62+
bool MCImageRepGetMetadata(MCImageRep *p_image_rep, MCArrayRef &r_metadata);
6063

6164
bool MCImageRepLock(MCImageRep *p_image_rep, uint32_t p_index, MCGFloat p_density, MCGImageFrame &r_frame);
6265
void MCImageRepUnlock(MCImageRep *p_image_rep, uint32_t p_index, MCGImageFrame &p_frame);
@@ -152,6 +155,8 @@ extern MC_DLLEXPORT MCTypeInfoRef kMCCanvasImageRepReferencedErrorTypeInfo;
152155
extern MC_DLLEXPORT MCTypeInfoRef kMCCanvasImageRepDataErrorTypeInfo;
153156
extern MC_DLLEXPORT MCTypeInfoRef kMCCanvasImageRepPixelsErrorTypeInfo;
154157
extern MC_DLLEXPORT MCTypeInfoRef kMCCanvasImageRepGetGeometryErrorTypeInfo;
158+
extern MC_DLLEXPORT MCTypeInfoRef kMCCanvasImageRepGetMetadataErrorTypeInfo;
159+
extern MC_DLLEXPORT MCTypeInfoRef kMCCanvasImageRepGetDensityErrorTypeInfo;
155160
extern MC_DLLEXPORT MCTypeInfoRef kMCCanvasImageRepLockErrorTypeInfo;
156161

157162
extern MC_DLLEXPORT MCTypeInfoRef kMCCanvasGradientStopRangeErrorTypeInfo;
@@ -308,9 +313,9 @@ extern "C" MC_DLLEXPORT void MCCanvasImageMakeWithResourceFile(MCStringRef p_res
308313
// Properties
309314
extern "C" MC_DLLEXPORT void MCCanvasImageGetWidth(MCCanvasImageRef p_image, uint32_t &r_width);
310315
extern "C" MC_DLLEXPORT void MCCanvasImageGetHeight(MCCanvasImageRef p_image, uint32_t &r_height);
316+
extern "C" MC_DLLEXPORT void MCCanvasImageGetMetadata(MCCanvasImageRef p_image, MCArrayRef &r_metadata);
317+
extern "C" MC_DLLEXPORT void MCCanvasImageGetDensity(MCCanvasImageRef p_image, double &r_density);
311318
extern "C" MC_DLLEXPORT void MCCanvasImageGetPixels(MCCanvasImageRef p_image, MCDataRef &r_pixels);
312-
// TODO - Add support for image metadata
313-
//void MCCanvasImageGetMetadata(const MCCanvasImage &p_image, MCArrayRef &r_metadata);
314319

315320
// TODO - Implement image operations
316321
//void MCCanvasImageTransform(MCCanvasImage &x_image, const MCCanvasTransform &p_transform);

0 commit comments

Comments
 (0)