I made this gradient effect. I used SoftMask to mark the place I want to cover with the background getting the gradient effect on text. I know it would be easier to just use image background and make a gradient in photoshop (example). But what if I want things to be more dynamic? For example, I have a video in the background that on click pauses and shows up the same scroll text. Now, the tool that I made wouldn't work because the background in this scenario would be different. I've been searching for a shader that could do the trick, but couldn't find any. Is Unity even capable of doing something like this? The effect is pretty obvious and looks easy to make, but man in was pain in the a** to make this work efficiently.
The gradient effect function:
private void FadeOutTextGradiantAndArrow(Vector2 scrollRectValue)
{
var contentY = _textScrollViewContent.anchoredPosition.y;
var contentMaxY = _textScrollViewContent.rect.height - _textScrollView.GetComponent<RectTransform>().rect.height;
var gradientHeight = _softMaskCanvasGroup.GetComponent<RectTransform>().rect.height;
var contentYSkewed = contentY - (contentMaxY - gradientHeight);
var positionPercentage = contentYSkewed / gradientHeight;
if (contentMaxY - gradientHeight < contentY)
{
_softMaskCanvasGroup.alpha = 1 - positionPercentage;
_arrowBelowTextCanvasGroup.alpha = _softMaskCanvasGroup.alpha;
}
else
{
_softMaskCanvasGroup.alpha = 1;
_arrowBelowTextCanvasGroup.alpha = _softMaskCanvasGroup.alpha;
}
}
Related
I put a scaled (2x) and binarized image (text black, everything else white) into tesseract and want to do the OCR as fast as possible:
private OCRResultData getOCRResult(Bitmap image, int minConf)
{
// Prepare input image for tesseract
Pix imageAsPix = PixConverter.ToPix(image);
// Process image by engine
Page page = this.engine.Process(imageAsPix, PageSegMode.SparseText);
string result = page.GetTsvText(0);
// Get data (split string into array of arrays to make information easier to acces)
string[][] data = getDataArray(result);
// Create result object and return it (class defiend by myself)
OCRResultData resultData = new OCRResultData();
resultData.confidences = getConfidences(data, minConf);
resultData.boundingBoxes = getBoundingBoxes(data, minConf);
resultData.detectedText = getDetectedText(data, minConf);
resultData.labelCoordinates = getLabelCoordsList(data, minConf);
page.Dispose();
return resultData;
}
Problem:
The best method I found for getting information like the detected string, its confidence, the bounding box coords, etc. was page.GetTsvText(0). Now while the processing is really fast (this.engine.Process(imageAsPix, PageSegMode.SparseText) takes like 30 ms for a 3000px X 3000px image), the page.GetTsvText(0) method needs about 1800 ms, which is too slow for my needs.
Is there a way to get it faster?
As a last option, I would try to introduce a string property and call the GetTsvText(0) in an asynchronous method at programm start and set it that way; In the case the user does nothing in the first 1800ms after loading the image, he wouldn't feel the delay anymore when pressing the OCR button (the code uses a WinForms GUI);
I know that there are lot of different threads about horizontal text animation/text scrolling, but unfortunately none of them give smooth scrolling with repeatable text. I have tried double/thickness animation using various WPF controls containing text. Also tried animating with visual brush which gives me by far the most elegant scrolling compared to other approaches (for e.g. playing with Canvas.Left property etc.) but that too goes blur the text, if the text length or the animation speed is too high.
I'm over to a pure DirectX C# implementation using SharpDX library. Should also mention that I'm a beginner with DirectX programming. Here is the code:
public void RunMethod()
{
// Make window active and hide mouse cursor.
window.PointerCursor = null;
window.Activate();
var str = "This is an example of a moving TextLayout object with no snapped pixel boundaries.";
// Infinite loop to prevent the application from exiting.
while (true)
{
// Dispatch all pending events in the queue.
window.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessAllIfPresent);
// Quit if the users presses Escape key.
if (window.GetAsyncKeyState(VirtualKey.Escape) == CoreVirtualKeyStates.Down)
{
return;
}
// Set the Direct2D drawing target.
d2dContext.Target = d2dTarget;
// Clear the target.
d2dContext.BeginDraw();
d2dContext.Clear(Color.CornflowerBlue);
//float layoutXOffset = 0;
float layoutXOffset = layoutX;
// Create the DirectWrite factory objet.
SharpDX.DirectWrite.Factory fontFactory = new SharpDX.DirectWrite.Factory();
// Create a TextFormat object that will use the Segoe UI font with a size of 24 DIPs.
textFormat = new TextFormat(fontFactory, "Verdana", 100.0f);
textLayout2 = new TextLayout(fontFactory, str, textFormat, 2000.0f, 100.0f);
// Draw moving text without pixel snapping, thus giving a smoother movement.
// d2dContext.FillRectangle(new RectangleF(layoutXOffset, 1000, 1000, 100), backgroundBrush);
d2dContext.DrawTextLayout(new Vector2(layoutXOffset, 0), textLayout2, textBrush, DrawTextOptions.NoSnap);
d2dContext.EndDraw();
//var character = str.Substring(0, 1);
//str = str.Remove(0, 1);
//str += character;
layoutX -= 3.0f;
if (layoutX <= -1000)
{
layoutX = 0;
}
// Present the current buffer to the screen.
swapChain.Present(1, PresentFlags.None);
}
}
Basically it creates an endless loop and subtracts the horizontal offset. Here are the challenges: I need repeatable text similar to HTML marquee without any gaps, Would probably need to extend it to multiple monitors.
Please suggest.
I don't know neither how to use DirectX nor sharpdx, but if you want you can consider this solution
I had a similar problem a while ago, but with the text inside a combobox. After a bounty i got what i was looking for. I'm posting the relevant piece of code as an example, but you can check the complete answer here
Basically, whenever you have a textblock/textbox that contain a string that cannot be displayed completely, cause the length exceed the textblock/box lenght you can use this kind of approach. You can define a custom usercontrol derived from the base you need (e.g. SlidingComboBox : Combobox) and define an animation for you storyboard like the following
_animation = new DoubleAnimation()
{
From = 0,
RepeatBehavior = SlideForever ? RepeatBehavior.Forever : new RepeatBehavior(1), //repeat only if slide-forever is true
AutoReverse = SlideForever
};
In my example i wanted this behaviour to be active only when the mouse was on the combobox, so in my custom OnMouse enter i had this piece of code
if (_parent.ActualWidth < textBlock.ActualWidth)
{
_animation.Duration = TimeSpan.FromMilliseconds(((int)textBlock.Text?.Length * 100));
_animation.To = _parent.ActualWidth - textBlock.ActualWidth;
_storyBoard.Begin(textBlock);
}
Where _parent represent the container of the selected item. After a check on the text lenght vs combobox lenght i start the animation and end it at the end of the text to be displayed
Note that in the question i mentioned there are also other soltions. I'm posting the one that worked for me
I have 2 CALayers, each with an image. Both have an initial Opacity of 0.
I want to animate Layer1's Opacity to 1 over 1 second, starting straight away. Then after a delay of 0.5 seconds, I want to animate Layer2's Opacity to 1 over 1 second. These 2 layers sit on top of one another.
What I am trying to achieve is having the first image fade in, then while it is fading in, fade the second image over it.
But I cannot use UIView.Animate for some reason as it does not animate at all, just sets the values straight away.
UIView.Animate(1, 0, UIViewAnimationOptions.CurveEaseIn, () =>
{
backgroundLayer.Opacity = 1;
}, () => UIView.Animate(5, () =>
{
backgroundLayer2.Opacity = 1;
}));
Here is simply tried to run the animation straight after one another and it still just sets the values right away and there is no animation.
UIView animations are intended for animating UIView properties and don't seem to play well with CALayers. Using UIImageViews instead of CALayers would solve your problem (then you should use the imageView.alpha property instead of the layer.opacity property).
However, if you insist on using CALayers you can animate them with CABasicAnimation. The code below accomplishes the animation you described (note that this is Swift code, as I don't use Xamarin).
var animation1 = CABasicAnimation(keyPath: "opacity")
// Don't go back to the initial state after the animation.
animation1.fillMode = kCAFillModeForwards
animation1.removedOnCompletion = false
// Set the initial and final states of the animation.
animation1.fromValue = 0
animation1.toValue = 1
// Duration of the animation.
animation1.duration = 1.0
var animation2 = CABasicAnimation(keyPath: "opacity")
animation2.fillMode = kCAFillModeForwards
animation2.removedOnCompletion = false
animation2.fromValue = 0
animation2.toValue = 1
animation2.duration = 1.0
// Add a 0.5 second delay.
animation2.beginTime = CACurrentMediaTime() + 0.5
// Animate!
backgroundLayer.addAnimation(animation1, forKey: "opacity")
backgroundLayer2.addAnimation(animation2, forKey: "opacity")
You can only animate following properties with UIView.Animate:
UIView.Frame
UIView.Bounds
UIView.Center
UIView.Transform
UIView.Alpha
UIView.BackgroundColor
UIView.ContentStretch
For more sophisticated animations you have to use CABasicAnimation like in #bjornorri answer.
You guys are correct in that I was trying to animate layers using the incorrect methods. What I ended up doing was replacing the layers with UIImageView and using UIView.Animate to change the Alpha properties.
Not only was this easier to code, it seems that UIImageViews are actually more performant when it comes to images.
So I'm using Windows Forms Chart to generate graphs containing several lines that can create some clutter on the graph and need something to differentiate them other than color. There are too many points to using dotted or dashed lines as there is no observable difference between that and a continuous line. So what I'm hoping to do is to get markers with various shapes to show up on the lines like in Excel, for instance. Right now I'm have it coded like this
myChart.Series["MySeries"].ChartType = SeriesChartType.FastLine;
myChart.Series["MySeries"].MarkerStyle = MarkerStyle.Diamond;
What this does is put a diamond in the legend over that line, but it doesn't put diamonds on the actual line that is in the chart itself. Changing the marker size doesn't make a difference, unfortunately, and neither does changing the marker color. Is there a way to get that to happen. Thanks for reading, and any help you have.
EDIT:
Heres the relevant code.
Its data is held in a class that is the value-peice of a dictionary.
The class contains a list of doubles.
public void Charter(Color colorOfLine)
{
double xValue;
double yValue;
myChart.Series.Add("MySeries");
myChart.Series["MySeries"].ChartType.FastLine;
myChart.Series["MySeries"].ChartArea = "ChartArea1";
myChart.Series["MySeries"].Color = colorOfLine;
myChart.Series["MySeries"].MarkerStyle = MarkerStyle.Diamond;
myChart.Series["MySeries"].MarkerColor = Color.Black;
myChart.Series["MySeries"].MarkerSize = 5;
myChart.Series["MySeries"].MarkerBoarderColor = Color.DeepPink;
foreach (KeyValuePair<int, MyClass> Pair in MyDictionary)
{
xValue = Pair.Value.MyClassList[0];
yValue = Pair.Value.MyClassList[1];
myChart.Series["MySeries"].Points.AddXY(xValue, yValue);
}
}
I should add that I've played around with the MarkerStep, and MarkerBoarderWidth as well, all to no benefit. The issue seems to be that the marker simply isn't appearing on the actual lines in the chart itself. Also I'm using Visual Studio 2010 Express for what its worth. Thanks again for reading.
Use Line. Don't use FastLine. FastLine won't generate markers for you.
myChart.Series["MySeries"].ChartType = SeriesChartType.Line
Set the MarkerSize to something bigger:
myChart.Series["MySeries"].MarkerSize = 4;
ETA:
You may also need to set the color of the marker:
myChart.Series["MySeries"].MarkerColor = Color.Blue;
myChart.Series["MySeries"].Color = Color.Blue;
I want to report status of an operation in a WinForm application written in C#.
To make it more user-friendly, I want to show an icon on the left depending on the status.
Animated GIF during the process
Ok or Error icon depending on the result.
I wanted to use the native WinForms Label control which works well with animated GIFs and looks as standard as it can get.
My problem however is that text comes is written over the picture.
There does not seem to be any property to set a margin for the text.
I tried the most obvious thing, which is to prefix it with spaces, which works, except when the text wraps to the next line, as shown below.
I would prefer not spend too much time writing/testing/debugging derived control for this if possible...
I could put a quick and dirty user-control, with a picturebox on the left of a label, but it doesn't feel very clean.
Is there any trick to get around this quickly and elegantly, or can someone point me to a Label derived class supporting this that is relatively lightweight? (I had a look at CodeProject but couldn't find much).
Thank you.
A simple alternative is to use a Button instead of a Label, as shown below:
By using the following properties, you can style the Button to look just like a Label, whilst also having the option to keep the image and text aligned next to eachother:
FlatAppearance ↴
BorderSize = 0
MouseDownBackColor = Control
MouseOverBackColor = Control
FlatStyle = Flat
Image = [Your image]
ImageAlign = MiddleLeft
Text = [Your text]
TextAlign = MiddleLeft
TextImageRelation = ImageBeforeText
A simple way to achieve the desired effect; no user controls!
The quick-and-dirty usercontrol with an image and a separate label is your best option. Just add a public string property to set the label's text and you're pretty much done.
Here's a different solution that I find less hacky than the "styled button" approach. It also allows you to set the distance (spacing) between the image and the text.
class ImageLabel : Label
{
public ImageLabel()
{
ImageAlign = ContentAlignment.MiddleLeft;
}
private Image _image;
public new Image Image
{
get { return _image; }
set
{
const int spacing = 4;
if (_image != null)
Padding = new Padding(Padding.Left - spacing - _image.Width, Padding.Top, Padding.Right, Padding.Bottom);
if (value != null)
Padding = new Padding(Padding.Left + spacing + value.Width, Padding.Top, Padding.Right, Padding.Bottom);
_image = value;
}
}
protected override void OnPaint(PaintEventArgs e)
{
if (Image != null)
{
Rectangle r = CalcImageRenderBounds(Image, ClientRectangle, ImageAlign);
e.Graphics.DrawImage(Image, r);
}
base.OnPaint(e); // Paint text
}
}
One alternative to a UserControl would be to use a TableLayoutPanel with two columns and one row, placing the image control in one cell and the text control in the other.
Its an old question, but maybe someone will look here just like I got here...
You can use the Align on the Image and on the text:
label.TextAlign = ContentAlignment.MiddleRight;
label.ImageAlign = ContentAlignment.MiddleLeft;
nameoftextlabel.hidden=1
That should work.