Im currently trying to implement a CycleTile within a scheduled task agent. I need Large-Tile-Images like this:
(image on the left side, custom Background, text on the right side)
http://s7.directupload.net/file/d/3361/54hbvlby_png.htm
I think I must render everything to one Image and set it as "CycleImages" to the CycleTile...
My current code looks like this:
void SavetoIsoStore(BitmapImage image)
{
//(...)
WriteableBitmap wb = CreateLargeBookImage(image);
using (IsolatedStorageFileStream imageStream = new IsolatedStorageFileStream("/Shared/ShellContent/" + tempJPEG, System.IO.FileMode.Create, myIsolatedStorage))
{
wb.SaveJpeg(imageStream, wb.PixelWidth, wb.PixelHeight, 0, 100);
}
IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(tempJPEG);
fileStream.Close();
}
imageNameCounter++;
}
private WriteableBitmap CreateLargeBookImage(BitmapImage bitmap)
{
WriteableBitmap wb = new WriteableBitmap(691, 336);//Large TileSize
//Magic filling, changing and rendering here
return wb;
}
The CycleTile reads the IsolatedStore.
I dont know how to start this... By rendering an UI object or another way?! The web doesnt provide me with satisfactory results...
edit:
Running Code:
private WriteableBitmap CreateLargeBookImage(BitmapImage bitmap)
{
WriteableBitmap wb = new WriteableBitmap((int)widthL, (int)heightL);
//<Grid x:Name="LayoutRoot" Height="336" Width="691">
// <Grid Background="White">
// <Grid.ColumnDefinitions>
// <ColumnDefinition/>
// <ColumnDefinition/>
// </Grid.ColumnDefinitions>
// <Image Grid.Column="0"
// Source="Images\35.jpg"
// MaxHeight="200"/>
// <TextBlock Grid.Column="1"
// Text="Testassdaseasdf"
// Foreground="Black"
// FontSize="24"
// Margin="15,0,0,0"
// VerticalAlignment="Center"
// HorizontalAlignment="Left"/>
// </Grid>
//</Grid>
var backgroundColor = new SolidColorBrush(Colors.White);
Grid grid = new Grid()
{
Background = backgroundColor,
};
ColumnDefinition columnDef1 = new ColumnDefinition();
ColumnDefinition columnDef2 = new ColumnDefinition();
grid.ColumnDefinitions.Add(columnDef1);
grid.ColumnDefinitions.Add(columnDef2);
Image img = new Image()
{
MaxHeight = 200,
Source = bitmap,
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Center
};
img.SetValue(Grid.ColumnProperty, 0);
var fontColor = new SolidColorBrush(Colors.Black);
TextBlock txt1 = new TextBlock()
{
Text = "TETSTETSTETET",
FontSize = 24,
Margin = new Thickness(15, 0, 0, 0),
Foreground = fontColor,
VerticalAlignment = VerticalAlignment.Center
};
txt1.SetValue(Grid.ColumnProperty, 1);
grid.Children.Add(img);
grid.Children.Add(txt1);
grid.UpdateLayout();
grid.Measure(new Size(widthL, heightL));
grid.Arrange(new Rect(0, 0, widthL, heightL));
wb.Render(grid, new TranslateTransform()
{
X = 0,
Y = 0
});
wb.Invalidate();
return wb;
}
You'll have make a render of UI controls.
Here is some sample code that creates a simple "Hello world" tile:
1. Instantiate the controls
var fontFamily = new FontFamily("Segoe WP SemiLight");
var fontColor = new SolidColorBrush(Colors.White);
var textTextBlock = new TextBlock()
{
Text = "Hello world!",
FontSize = 40,
Foreground = fontColor,
FontFamily = fontFamily
};
2. Render the controls as a WriteableBitmap
var bitmap = new WriteableBitmap(173, 173);
bitmap.Render(textTextBlock, new TranslateTransform()
{
X = 9,
Y = 9
});
bitmap.Invalidate();
If your layout is complex, my advice is to create the XAML first with a designer tool like Blend, and when it's done you do the same thing in C#.
EDIT: if you want to render a Grid control, you need to add the Children elements to the grid:
grid.Children.Add(textTextBlock);
and call the following methods to ensure that the Controls are positionned correctly:
grid.UpdateLayout();
grid.Measure(new Size(tileWidth, tileHeight));
grid.Arrange(new Rect(0, 0, tileWidth, tileHeight));
Related
I need to come up with a way to watermark user generated HTML and display it to the user.
I played around with modifying the HTML by setting a background image, but the solution didn't work if the any html element contained a background color or image.
So I thought it would be easier to display the HTML in a web browser control and watermark the control. Boy was I wrong.
I tried creating a user control and derive from WebBrowser and overwrite the paint method. That didn't work.
Next idea was to just draw on top of a webbrowser control.
here's what I've come up with. In this example I slapped a label, webbrowser control and two picture boxes on a form. I create the image and set it to both picture boxes. I put one picture box over the label and the other over the watermark.
The picturebox over the label displayed as I expected, but the picturebox over the webbrowser control did not.
I'm out of ideas. Any suggestions?
public partial class Form1 : Form
{
string WatermarkText = "Confidential";
Font WatermarkFont = new Font("Microsoft Sans Serif", 24, FontStyle.Bold);
int WatermarkAngle = 45;
Color WatermarkColor = Color.PaleTurquoise;
public Form1()
{
InitializeComponent();
AllowTransparency = true;
label1.AutoSize = false;
label1.Text = "Test Text";
label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
webBrowser1.Navigate("http://www.google.com");
var img = creategraphics(WatermarkText);
label1.Size = pictureBox2.Size = pictureBox1.Size = img.Size;
label1.Controls.Add(pictureBox1);
pictureBox1.Image = img;
pictureBox1.BackColor = Color.Transparent;
pictureBox1.Location = new Point(0, 0);
webBrowser1.Controls.Add(pictureBox2);
pictureBox2.Image = img;
pictureBox2.BackColor = Color.Transparent;
pictureBox2.Location = new Point(0, 0);
}
Image creategraphics(string text)
{
if (String.IsNullOrWhiteSpace(text)) return null;
var size = getWatermarkSize(text, WatermarkAngle, WatermarkFont, out double hypotenuse);
var img = new Bitmap(size.Width, size.Height);
var g = Graphics.FromImage(img);
var brush = new SolidBrush(WatermarkColor);
var stringFormat = new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
g.RotateTransform((float)-WatermarkAngle);
g.DrawString(text, WatermarkFont, brush, new Point(0, (int)hypotenuse / 2), stringFormat);
return img;
}
private static Size getWatermarkSize(string text, int angle, Font font, out double hypotenuse)
{
if (angle > 90) throw new ArgumentOutOfRangeException("angle");
using (var bitmap = new Bitmap(1, 1))
using (var graphics = Graphics.FromImage(bitmap))
{
var size = graphics.MeasureString(text, font);
hypotenuse = size.Width + size.Height;
double radians = (angle / 180.0) * Math.PI;
var width = (Math.Cos(radians) * size.Width) + (Math.Sin(radians) * size.Height);
var height = (Math.Cos(radians) * size.Height) + (Math.Sin(radians) * size.Width);
return new Size((int)width, (int)height);
}
}
}
This is what I get
I'm using geoTools 14.1
I'm trying to plot on an image some points
This is the code I'm using:
double[][] points = new double[8][2];
points[0] = new double[]{45.46433710338643, 9.190417528152478};
points[1] = new double[]{45.46195085146914, 9.189746320685355};
points[2] = new double[]{45.460062304163635, 9.19015527826191};
points[3] = new double[]{45.472950871127445, 9.17363731952788};
points[4] = new double[]{45.4737153001908,9.203728795018847};
points[5] = new double[]{45.4849795331724,9.20162835217198};
points[6] = new double[]{45.48560542313713,9.195953607559215};
points[7] = new double[]{45.48348421787171,9.188765287399292};
final SimpleFeatureType TYPE = DataUtilities.createType("Location",
"location:Point:srid=3857,"+// <- the geometry attribute: Point type
"nome:String," + // <- a String attribute
"id:Integer" // a number attribute
);
FeatureCollection<SimpleFeatureType, SimpleFeature> collection = new DefaultFeatureCollection();
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
CoordinateReferenceSystem pointSrc = CRS.decode("EPSG:4326");
CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:3857");
MathTransform transform = CRS.findMathTransform(pointSrc, targetCRS);
for (int i = 0; i < points.length; i++)
{
double[] coords = points[i];
Point point = geometryFactory.createPoint(new Coordinate(coords[0], coords[1]));
Point converted = (Point) JTS.transform( point, transform);
featureBuilder.add(converted);
featureBuilder.add("Punto "+i);
featureBuilder.add(i);
SimpleFeature feature = featureBuilder.buildFeature(""+i);
logger.info(""+feature+" feature.getDefaultGeometry() "+feature.getDefaultGeometry()+ " feature.getDefaultGeometryProperty() "+feature.getDefaultGeometryProperty());
((DefaultFeatureCollection)collection).add(feature);
}
String wellKnownName = "Circle";
Style style = SLD.createPointStyle(wellKnownName,Color.RED,Color.RED,0f,10f);
FeatureLayer fl = new FeatureLayer(collection, style);
fl.setVisible(true);
fl.setSelected(true);
logger.info(""+fl);
mapcontent.addLayer((org.geotools.map.Layer)fl); //"1010177.1917802,5688070.7096562,1029133.5747922,5704122.4855938"
ReferencedEnvelope bounds = new ReferencedEnvelope(1010177.1917802,1029133.5747922,5688070.7096562, 5704122.4855938, targetCRS);
BufferedImage ret = buildImage(mapcontent, 5000, 5000, bounds, Color.white);
ImageIO.write((RenderedImage) ret, "png", new File("/home/angelo/Scrivania/immagineResult.png"));
It seems to me all correct, but the generated image contains no point.
This is the generated image
As you can see it's all white; I was expecting only 8 red circles on the image... Is there any error in my code? Am I doing anything wrong?
Thank you
Angelo
UPDATE: added build image method
public BufferedImage buildImage(final MapContent map, final int imageWidth,final int imageHeight,ReferencedEnvelope bounds,Color bgcolor) {
GTRenderer renderer = new StreamingRenderer();
renderer.setMapContent(map);
renderer.setMapContent(map);
Rectangle imageBounds = null;
ReferencedEnvelope mapBounds = bounds;
try {
if(bounds==null) mapBounds = map.getMaxBounds();
imageBounds = new Rectangle(imageWidth, imageHeight);
} catch (Exception e) {
failed to access map layers
throw new RuntimeException(e);
}
BufferedImage image = new BufferedImage(imageBounds.width, imageBounds.height, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D gr = image.createGraphics();
int type = AlphaComposite.SRC;
gr.setComposite(AlphaComposite.getInstance(type));
Color c = new Color(bgcolor.getRed(), bgcolor.getGreen(), bgcolor.getBlue(), 0);
gr.setBackground(bgcolor);
gr.setColor(c);
gr.fillRect(0, 0, image.getWidth(), image.getHeight());
type = AlphaComposite.SRC_OVER;
gr.setComposite(AlphaComposite.getInstance(type));
try {
renderer.paint(gr, imageBounds, bounds);
} catch (Exception e) {
throw new RuntimeException(e);
}
return image;
}
After a lot of playing I have found the problem :-) There is no bug in your code! There are in fact 8 red dots in that white image, but they are very hard to find!
As the above image shows at 2000% zoom (and panning along the top edge) you will find a dot (I'm assuming the others are there) - the simple answer is either to make the dots 10 times bigger (100px) or the image much smaller (500x500) and in both cases the dots are immediately visible.
I want to update my live tile by creating and saving a writable bitmap image in scheduled task agent.my code works inside the app but in background task, it breaks into the debugger
I'm using this simple code:
protected override void OnInvoke(ScheduledTask task)
{
#if DEBUG_AGENT
ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(30));
#endif
CreateWideTile();
NotifyComplete();
}
and my code to create and save image is this:
private void CreateWideTile()
{
int width = 691;
int height = 336;
string imagename = "WideBackground";
WriteableBitmap b = new WriteableBitmap(width, height);
var canvas = new Grid();
canvas.Width = b.PixelWidth;
canvas.Height = b.PixelHeight;
var background = new Canvas();
background.Height = b.PixelHeight;
background.Width = b.PixelWidth;
//Created background color as Accent color
SolidColorBrush backColor = new SolidColorBrush(Colors.Red);
background.Background = backColor;
var textBlock = new TextBlock();
textBlock.Text = "Example text";
textBlock.FontWeight = FontWeights.Normal;
textBlock.TextAlignment = TextAlignment.Left;
textBlock.Margin = new Thickness(20, 20, 0, 0);
textBlock.TextWrapping = TextWrapping.Wrap;
textBlock.Foreground = new SolidColorBrush(Colors.White); //color of the text on the Tile
textBlock.FontSize = 30;
canvas.Children.Add(textBlock);
b.Render(background, null);
b.Render(canvas, null);
b.Invalidate(); //Draw bitmap
//Save bitmap as jpeg file in Isolated Storage
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream imageStream = new IsolatedStorageFileStream("/Shared/ShellContent/" + imagename + ".jpg", System.IO.FileMode.Create, isf))
{
b.SaveJpeg(imageStream, b.PixelWidth, b.PixelHeight, 0, 100);
}
}
}
when I test the app, after executing background task, an error comes that point to Debugger.Break();
private static void UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
Debugger.Break();
}
}
I don't understand the reason. my code works in foreground app but not in background ...
any solution ????
You should use dispatcher, because WriteableBitmap.Render should be used in the UI thread:
protected override void OnInvoke(ScheduledTask task)
{
Deployment.Current.Dispatcher.BeginInvoke( () =>
{
CreateWideTile();
NotifyComplete();
} );
}
I want to add border around TextBlock programatically in Windows Store Application.
How can I do this?
Thanks.
Create new project and add this code in OnNavigatedTo event.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var tb = new TextBlock()
{
Text = "...TextBlock with border...",
FontSize = 20
};
//To get actual height and width of TextBlock
tb.Arrange(new Rect(0, 0, Window.Current.Bounds.Width, Window.Current.Bounds.Height));
tb.Measure(new Size(Window.Current.Bounds.Width, Window.Current.Bounds.Height));
var border = new Border()
{
BorderThickness = new Thickness(3),
BorderBrush = new SolidColorBrush(Windows.UI.Colors.Red),
Height = tb.ActualHeight + 10,
Width = tb.ActualWidth + 10
};
var rootGrid = (Grid)(((Page)this).Content);
rootGrid.Children.Add(border);
border.Child = tb;
}
I want to be able to cahce HTML text as bitmap, for use in AlivePDF. My testing works well with TextArea or if the component is on the Stage or visible. But I want to be able to crunch text blocks that dont necessarily sit on screen. Does anyone know how to do this?
What I have failing so far
public static function rasterizeText( text:String, width:int = 100, height:int = 100, x:int = 0, y:int = 0 ):BitmapData {
var textRenderer:TextArea = new TextArea();
textRenderer.width = width;
textRenderer.height = height;
textRenderer.htmlText = text;
var bitdata:BitmapData = new BitmapData(width, height, true, 0xFF000000)
bitdata.draw( textRenderer );
return bitdata;
}
Your code should work fine. There is no need to add textRenderer to the stage in order to draw it into the BitmapData. You are drawing your textRenderer onto a solid black background. Maybe your text is also black and that is why you can not see it?
Try changing 0xFF000000 to e.g. 0xFFFF0000 and see if the text will show up.
No it wasn't a color issue. Also I had the color set to FF000000 which at least should have been showing up black. TextArea didn't seem to play nice with bitmaps, although TextField works perfectly fine.
Edit: I'm guessing TextArea wasn't working as spark or mx because they're a FlexSprite thingy, which act differently to normal AS3 Sprites. They'll defer rendering until they're added to the display list.
Working function:
public function rasterizeText( text:String,
width:int = 100, height:int = 100 ):BitmapData {
var tf:TextField = new TextField();
tf.multiline = true;
tf.wordWrap = true;
tf.width = width;
tf.height = height;
tf.htmlText = text;
var bd:BitmapData = new BitmapData(width, height, true,0x00000000);
bd.draw(tf);
return bd;
}
This was not working (I tried mx & spark textarea components):
public function rasterizeText( text:String,
width:int = 100, height:int = 100 ):BitmapData {
var textRenderer:TextArea = new TextArea();
textRenderer.width = width;
textRenderer.height = height;
textRenderer.textFlow = TextConverter.importToFlow( text, TextConverter.TEXT_FIELD_HTML_FORMAT );
var bitdata:BitmapData = new BitmapData( width, height, false, 0xFF000000 )
bitdata.draw( textRenderer );
return bitdata;
}
However it would work when drawing from the Stage:
public function rasterizeText( text:String,
width:int = 100, height:int = 100 ):BitmapData {
var textRenderer:TextArea = new TextArea();
textRenderer.width = width;
textRenderer.height = height;
textRenderer.textFlow = TextConverter.importToFlow( text, TextConverter.TEXT_FIELD_HTML_FORMAT );
canvas.addElement( textRenderer );
var bitdata:BitmapData = new BitmapData( width, height, false, 0xFF000000 )
bitdata.draw( canvas );
return bitdata;
}