How to make watermark always floating above the screen in MacOS - ios

I want to make an application that will add a watermark to the live screen on MacOS,and watermark should always floating above other app .
I defined a custom, transparent, window. It works perfectly except in following cases: fullscreen mode,Mission Control Combination key down,Show Desktop Combination key down.
Since it doesn’t work when other app in full screenmode,so is that possible to disable other app in full screenmode
I notice that NSWindowLevel and CGWindowLevelKey,Anyone know how to use for my situation?
Is that other ways to make this app floating above other app by use other API?
I have attached my implementation for your reference, with the following codes then watermark window could float above other windows.
attached screenshot
Click here to download my project
class WaterMarkWindow: NSWindow {
override func awakeFromNib() {
super.awakeFromNib()
self.level = .floating;
self.ignoresMouseEvents = true;
self.isReleasedWhenClosed = false;
self.isMovableByWindowBackground = false;
self.alphaValue = 0.3
self.backgroundColor = NSColor.clear;
self.isOpaque = false;
self.hasShadow = false;
self.contentView?.wantsLayer = true;
}
}

Related

Xamarin.Forms Xam.Plugin.Media Take Picture on iOS

I'm using the Xam.Plugin.Media in my Forms app to take pictures.
I take the Image stream (GetStream) and convert to a byte[] and store in my DB.
I then use that as the image source.
On Android and UWP, its working fine.
On iOS, if the picture is taken in portrait mode, the image once, selected is always rotated 90 deg.
I will later, upload this to a server and that image could be used on a different device.
For this, I also tried the GetStreamWithImageRotatedForExternalStorage but in this case, I cant see the image at all.
There are bytes in the stream (I DisplayAlert the length) but the image does not display.
Any idea what I might be doing wrong?
My code:-
private async Task TakePicture(WineDetails details)
{
await CrossMedia.Current.Initialize();
if (CrossMedia.Current.IsCameraAvailable && CrossMedia.Current.IsTakePhotoSupported)
{
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
AllowCropping = true,
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium,
SaveToAlbum = false,
RotateImage = true
});
if (file == null)
return;
using (var ms = new MemoryStream())
{
var stream = file.GetStreamWithImageRotatedForExternalStorage();
stream.CopyTo(ms);
details.LabelImage = ms.ToArray();
details.NotifyChange("ImageSource");
}
}
}
The image is updated in the page via the NotifyChange and looks like this:-
ImageSource.FromStream(() => new MemoryStream(this.LabelImage))
This works fine in all cases on Android and UWP, works on iOS using GetStream (except the image is incorrectly rotated) but does not work using GetStreamWithImageRotatedForExternalStorage on iOS.
Anyone else using this plugin?
Any idea why GetStream returns a rotated image?
Any idea why GetStreamWithImageRotatedForExternalStorage is not working?
Thanks
Update:-
Changed SaveToAlbum = true and when I open the gallery, the image is rotated 90 deg.
Have RotateImage = true which could cause the issue? I'll try setting it to false.
I still can't set the image source to the byte array of the image using GetStreamWithImageRotatedForExternalStorage.
using (var ms = new MemoryStream())
{
file.GetStreamWithImageRotatedForExternalStorage().CopyTo(ms);
details.LabelImage = ms.ToArray();
}
using the byte array for an image
return ImageSource.FromStream(() => new MemoryStream(this.LabelImage));
This does not work for me, GetStream works ok.
Update:-
Ok so, RotateImage = false + GetStreamWithImageRotatedForExternalStorage allows me to display the image but its still incorrectly rotated in my app and the gallery.
I'm using this plugin, which is similar (if not the same thing - I know James Montemagno has recently packaged/bundled his work with Xamarin).
If you check the issues board there, you'll see there are quite a few people that have similar troubles (image rotation on iOS). Almost every 'solution' mentions using GetStreamWithImageRotatedForExternalStorage.
My issue was similar - I was unable to take a photo on iOS in portrait mode, without other (non-ios Devices) rotating the image. I have tried for weeks to solve this issue, but support on the plugin seems to be quite limited.
Ultimately I had to solve this with a huge workaround - using a custom renderer extending from FFImageLoading to display our images and MetadataExtractor. We were then able to extract the EXIF data from the stream and apply a rotation transformation to the FFImageLoding image control.
The rotation information was stored in a sort of weird way, as a string. This is the method I'm using to extract the rotation information, and return the amount it needs to be rotated as an int. Note that for me, iOS was able to display the image correctly still, so it's only returned a rotation change for Android devices.
public static int GetImageRotationCorrection(byte[] image)
{
try
{
var directories = ImageMetadataReader.ReadMetadata(new MemoryStream(image));
if (Device.Android == "Android")
{
foreach (var directory in directories)
{
foreach (var tag in directory.Tags)
{
if (tag.Name == "Orientation")
{
if (tag.Description == "Top, left side(Horizontal / normal)")
return 0;
else if (tag.Description == "Left side, bottom (Rotate 270 CW)")
return 270;
else if (tag.Description == "Right side, top (Rotate 90 CW")
return 90;
}
}
}
}
return 0;
}
catch (Exception ex)
{
return 0;
}
}
Note that there is also a custom renderer for the image for FFImage Loading.
public class RotatedImage : CachedImage
{
public static BindableProperty MyRotationProperty = BindableProperty.Create(nameof(MyRotation), typeof(int), typeof(RotatedImage), 0, propertyChanged: UpdateRotation);
public int MyRotation
{
get { return (int)GetValue(MyRotationProperty); }
set { SetValue(MyRotationProperty, value); }
}
private static void UpdateRotation(BindableObject bindable, object oldRotation, object newRotation)
{
var _oldRotation = (int)oldRotation;
var _newRotation = (int)newRotation;
if (!_oldRotation.Equals(_newRotation))
{
var view = (RotatedImage)bindable;
var transformations = new System.Collections.Generic.List<ITransformation>() {
new RotateTransformation(_newRotation)
};
view.Transformations = transformations;
}
}
}
So, in my XAML - I had declared a RotatedImage instead of the standard Image. With the custom renderer, I'm able to do this and have the image display rotated the correct amount.
image.MyRotation = GetImageRotationCorrection(imageAsBytes)
It's a totally unnecessary workaround - but these are the lengths that I had to go to to get around this issue.
I'll definitely be following along with this question, there might be someone in the community who could help us both!
The SaveMetaData flag is causing the rotation issue.
Setting it to false (default is true) now displays the photo correctly.
One side effect of that, the image no longer appears in the gallery if SaveToAlbum=true.
Still can't use an image take when using GetStreamWithImageRotatedForExternalStorage, even using FFImageLoading.
I found that while using Xam.Plugin.Media v5.0.1 (https://github.com/jamesmontemagno/MediaPlugin), the combination of three different inputs produced different results on Android vs. iOS:
StoreCameraMediaOptions.SaveMetaData
StoreCameraMediaOptions.RotateImage
Using MediaFile.GetStream() vs. MediaFile.GetStreamWithImageRotatedForExternalStorage()
On Android, SaveMetaData = false, RotateImage = true, and using MediaFile.GetStreamWithImageRotatedForExternalStorage() worked for me whether I was saving the result stream externally or processing the result stream locally for display.
On iOS, the combination of RotateImage = true and StreamRotated = true would result in a NullReferenceException coming out of the plugin library. Using MediaFile.GetStreamWithImageRotatedForExternalStorage() appeared to have no impact on behaivor.
--
Before going further, it's important to understand that image orientation in the JPEG format (which Xam.Plugin.Media seems to use) isn't as straightforward as you might think. Rather than rotating the raw image bytes 90 or 180 or 270 degrees, JPEG orientation can be set through embedded EXIF metadata. Orientation issues will happen with JPEGs either if EXIF data is stripped or if downstream consumers don't handle the EXIF data properly.
The approach I landed on was to normalize JPEG image orientation at the point the image is captured without relying on EXIF metadata. This way, downstream consumers shouldn't need to be relied on to properly inspect and handle EXIF orientation metadata.
The basic solution is:
Scan a JPEG for EXIF orientation metadata
Transform the JPEG to rotate/flip as needed
Set the result JPEG's orientation metadata to default
--
Code example compatible with Xamarin, using ExifLib.Standard (1.7.0) and SixLabors.ImageSharp (1.0.4) NuGet packages. Based on (Problem reading JPEG Metadata (Orientation))
using System;
using System.IO;
using ExifLib;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Processing;
namespace Your.Namespace
{
public static class ImageOrientationUtility
{
public static Stream NormalizeOrientation(Func<Stream> inputStreamFunc)
{
using Stream exifStream = inputStreamFunc();
using var exifReader = new ExifReader(exifStream);
bool orientationTagExists = exifReader.GetTagValue(ExifTags.Orientation, out ushort orientationTagValue);
if (!orientationTagExists)
// You may wish to do something less aggressive than throw an exception in this case.
throw new InvalidOperationException("Input stream does not contain an orientation EXIF tag.");
using Stream processStream = inputStreamFunc();
using Image image = Image.Load(processStream);
switch (orientationTagValue)
{
case 1:
// No rotation required.
break;
case 2:
image.Mutate(x => x.RotateFlip(RotateMode.None, FlipMode.Horizontal));
break;
case 3:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate180, FlipMode.None));
break;
case 4:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate180, FlipMode.Horizontal));
break;
case 5:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate90, FlipMode.Horizontal));
break;
case 6:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate90, FlipMode.None));
break;
case 7:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate270, FlipMode.Horizontal));
break;
case 8:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate270, FlipMode.None));
break;
}
image.Metadata.ExifProfile.SetValue(ExifTag.Orientation, (ushort)1);
var outStream = new MemoryStream();
image.Save(outStream, new JpegEncoder{Quality = 100});
outStream.Position = 0;
return outStream;
}
}
}
And to use in conjunction with Xam.Plugin.Media:
MediaFile photo = await CrossMedia.Current.TakePhotoAsync(options);
await using Stream stream = ImageOrientationUtility.NormalizeOrientation(photo.GetStream);

Image brightness/contrast - Xamarin iOS

Xamarin provides some sample code for doing simple adjustments to an image in iOS:
https://github.com/xamarin/recipes/blob/master/ios/media/coreimage/adjust_contrast_and_brightness_of_an_image/color_controls_pro/ImageViewController.cs
This code updates the image only when the user lets go of the slider knob - not the continuous updating we normally expect.
However when I make the following change I reliably get SIGSEGV faults on hardware.
//sliderC.TouchUpInside += HandleValueChanged;
//sliderS.TouchUpInside += HandleValueChanged;
//sliderB.TouchUpInside += HandleValueChanged;
sliderC.ValueChanged += HandleValueChanged;
sliderS.ValueChanged += HandleValueChanged;
sliderB.ValueChanged += HandleValueChanged;
I expect that this is "overloading" the code in some way. How would you implement image adjustments that avoid this problem? Is there a lower-level approach, or do other apps simply use a much lower-rez version of the image for adjustments?
Here is a quickie version that I did that is 'more' realtime (This is a recording from the sim, the device (6s) is smooth depending upon initial image size.
Create a single viewcontroller iOS app from the template and add a UIImageView and three sliders to the storyboard so it looks like the animate gif.
I created a simple class to store the ColorCtrl values (brightness, contrast, saturation:
public class ColorCtrl
{
public float s;
public float b;
public float c;
}
Than in the ViewDidLoad method, do some setup:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
string filePath = Path.Combine (NSBundle.MainBundle.BundlePath, "hero.jpg");
originalImage = new CIImage (new NSUrl (filePath, false));
colorCtrls = new CIColorControls ();
colorCtrls.Image = originalImage;
// Create the context only once, and re-use it
var contextOptions = new CIContextOptions ();
contextOptions.UseSoftwareRenderer = false; // gpu vs. cpu
// On save of the image, create a new context with highqual attributes and re-apply the filter...
contextOptions.HighQualityDownsample = false;
contextOptions.PriorityRequestLow = false; // high queue order it
contextOptions.CIImageFormat = (int)CIFormat.ARGB8; // use 32bpp, vs. 64|128bpp
context = CIContext.FromOptions (contextOptions);
}
Then for the three slider's change handlers.
Within those I 'hack' a busy flag in order to skip the image transformation if the last transform is not done get. If we are not busy, then do an await call on our async transform method.
Note: I said 'hack', I am mean it, in a best practice way, this should pump transform requests to a queue and the queue handler would summarize all the pending items in the queue, flush them and do the transform.
Note: I added the "async" to the generated event handlers so I can await the image transform.
Note: The three slider's handlers are all the same except for the value that they are assigning; colorCtrlV.b | colorCtrlV.s | colorCtrlV.c
Note: You can down-sample large image at the moment the user does a touch down, perform the transforms on that, and on touch up, transform the original full-size image...
async partial void brightnessChange (UISlider sender)
{
if (!busy) {
busy = true;
colorCtrlV.b = sender.Value;
this.imageView.Image = await FilterImageAsync (colorCtrlV);
busy = false;
}
}
Ok, now for actual transform, a fairly simple Run.Task so we can get this work off the main thread and NOT block the UI. This way the sliders will not stutter as the user slides their finger, BUT due to the 'busy' flag/hack in the slider's handler we might skip some of those events (we should add a handler for the touch drag exit so we process the 'last' user's requested value....)
// async Task.Run() - not best practice - just a demo
async Task<UIImage> FilterImageAsync (ColorCtrl value)
{
if (transformImage == null)
transformImage = new Func<UIImage>(() => {
colorCtrls.Brightness = colorCtrlV.b;
colorCtrls.Saturation = colorCtrlV.s;
colorCtrls.Contrast = colorCtrlV.c;
var output = colorCtrls.OutputImage;
var cgImage = context.CreateCGImage (output, originalImage.Extent);
var filteredImage = new UIImage (cgImage);
return filteredImage;
});
UIImage image = await Task.Run<UIImage>(transformImage);
return image;
}
Personally For this type of realtime image transformations I prefer to do it via OpenGL-ES using GPUImage as the screen's interaction at the 60z refresh rate is as smooth as butter, but it is a lot more work than using CoreImage filters.

Any way to automate SFSafariViewController in UI tests?

Is there any way to automate SFSafariViewController? I like the Xcode 7 UI test feature, but it seems it does not support SFSafariViewController automation. Some of the UI flows I am testing require a web browser so the app uses SFSafariViewController to make it safer vs a web view.
If it's similar to launching extensions (currently broken with direct interactions), try tapping the screen at the point where the element you're looking for is:
Example of tapping an action sheet which launches an extension:
func tapElementInActionSheetByPosition(element: XCUIElement!) {
let tableSize = app.tables.elementBoundByIndex(0).frame.size
let elementFrame = element.frame
// get the frame of the cancel button, because it has a real origin point
let CancelY = app.buttons["Cancel"].frame.origin.y
// 8 is the standard apple margin between views
let yCoordinate = CancelY - 8.0 - tableSize.height + elementFrame.midY
// tap the button at its screen position since tapping a button in the extension picker directly is currently broken
app.coordinateWithNormalizedOffset(CGVectorMake(elementFrame.midX / tableSize.width, yCoordinate / app.frame.size.height)).tap()
}
Note: You must tap at the XCUIApplication query layer. Tapping the element by position doesn't work.
For now Xcode 9.3 has support for that, but it doesn't work properly because of annoying Xcode bug.
In test you can print app.webViews.buttons.debugDescription or app.webViews.textFields.debugDescription, and it prints correct information, but after tap or typeText you have crash.
To workaround you can parse debugDescription, extract coordinates and tap by coordinate. For text field you can insert text via "Paste" menu.
private func coordinate(forWebViewElement element: XCUIElement) -> XCUICoordinate? {
// parse description to find its frame
let descr = element.firstMatch.debugDescription
guard let rangeOpen = descr.range(of: "{{", options: [.backwards]),
let rangeClose = descr.range(of: "}}", options: [.backwards]) else {
return nil
}
let frameStr = String(descr[rangeOpen.lowerBound..<rangeClose.upperBound])
let rect = CGRectFromString(frameStr)
// get the center of rect
let center = CGVector(dx: rect.midX, dy: rect.midY)
let coordinate = XCUIApplication().coordinate(withNormalizedOffset: .zero).withOffset(center)
return coordinate
}
func tap(onWebViewElement element: XCUIElement) {
// xcode has bug, so we cannot directly access webViews XCUIElements
// as workaround we can check debugDesciption, find frame and tap by coordinate
let coord = coordinate(forWebViewElement: element)
coord?.tap()
}
Article about that: https://medium.com/#pilot34/work-with-sfsafariviewcontroller-or-wkwebview-in-xcode-ui-tests-8b14fd281a1f
Full code is here: https://gist.github.com/pilot34/09d692f74d4052670f3bae77dd745889

AIR iOS scaling entire content, can't see anything

I've created an app with the latest version of AIR (16.0.0.272) and I'm trying to scale the content to fit any resolution of the iPhone from 4 to 6+
In desktop debugging I see all perfectly scaled changing the stage dimension to test my solution. Trying on my iPhone 5 I can't see the scaled content.
If I comment the resize function everything is ok (I see all the content, not scaled obviously).
That's my solution
private function resize(e:Event=null):void{
w=stageW();
h=stageH();
var initW:Number=640;
var initH:Number=960;
//bg.img.width=w;
trace(w+"/"+h);
main.y=62;
//main.x=w*.5-320;
bg.width=w;
bg.height=h;
menu.bg.width=w;
menu.bg.height=h;
var divisor:Number = 640/w;
main.width = Math.floor(main.width / divisor);
main.height = Math.floor(main.height / divisor);
}
I have tried to temporize the resize call to test it on the iPhone but again after 2000ms I can't see anything.
After this I've tried with a listener addEventListener(Event.ADDED_TO_STAGE, init); calling the resize above at the end of my operations of building UI and so on.
Can't figure why resizing a movieclip that contains my app content make it disappear from iPhone and not from the desktop.
Hope in a solution
Thanks in advance
Capabilities.screenResolutionX and Capabilities.screenResolutionY are what you should use for screen width and height on apps.
Note: the X and Y don't change with rotation - they'll stay the same when screen rotates, so your code to get screen dimensions will look like this:
if (bStagePortrait) {
iScreenWidth = Capabilities.screenResolutionX;
iScreenHeight = Capabilities.screenResolutionY;
} else {
iScreenWidth = Capabilities.screenResolutionY;
iScreenHeight = Capabilities.screenResolutionX;
}
Also use this code to prevent app from resizing or moving:
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
For a variety of reasons, your resize function could be getting called more than once.
main.width = Math.floor(main.width / divisor);
main.height = Math.floor(main.height / divisor);
will continuously make the main clip smaller. It may be better to use a constant or number for size calculation. I usually do something with scaling, though.
main.scaleX = main.scaleY = percentStageScaled;

Swipe Gesture for iOS in Flash CS6

I'm creating an app for iOS (mainly) in Flash CS6 and I'm having a few problems with getting a particular page to work.
The layout is as follows: I have a movie clip that is 3 times the width of the stage with my content, with the instance name of txtContent.
On a separate layer, my Action Script (v3.0) reads as follows:
import com.greensock.*;
import flash.events.MouseEvent;
//Swipe
Multitouch.inputMode = MultitouchInputMode.GESTURE;
var currentTile:Number = 1;
var totalTiles:Number = 3;
txtContent.addEventListener(TransformGestureEvent.GESTURE_SWIPE , onSwipe);
function moveLeft():void{
txtContent.x += 640;
}
function moveRight():void{
txtContent.x -= 640;
}
function onSwipe (e:TransformGestureEvent):void{
if (e.offsetX == 1) {
if(currentTile > 1){
moveLeft()
currentTile--
} else {}
}
if (e.offsetX == -1) {
if(currentTile < totalTiles){
moveRight()
currentTile++
}
}
}
stop();
When I test the movie, with a touch layer, the movie clip successfully moves left and right for each swipe, and does not continue to move too far in either direction, in effect ignoring any other swipes.
However, when I compile the IPA and test on the iPhone, only the first two "tiles" move (I can only see two thirds of the movie clip with swiping), as if I swipe to the third "tile" I cannot swipe back at all. No matter what I do, it gets stuck on that third section.
Is there a problem in my code that isn't registering properly in iOS?
FYI, I'm testing on an iPhone 3GS.
It was my own mistake - the final 'page' of the slides did not have a large background with the alpha set to 0% like the others, therefore to slide it back it would only work when holding the text (which was small). With the addition of the background, the movieclip is solid and therefore swiping the whole screen worked fine.

Resources