Titanium Alloy: Saving a View as image to the photoGallery? - ios

So I currently have a window with a view (id="newPhoto") in which I put an image from a previous step. Onto this newPhoto-view I position a new view (id="content") via css with an icon and some text on it.
Then I want to save the parent view with the image and the icon and text on it as a new image to the photoGallery. What would be the easiest way? To put all in one view and save the new view, or to screenshot the desired part and save it?
Cannot make this to work :(
my filterWindow.xml file:
<Alloy>
<Window id="filterWindow">
<View id="finalImage" />
<View id="selectedPhoto" />
<View id="counter">
<ImageView id="weatherIcon" />
<Label id="label" />
</View>
<Button id="filterAndSaveBtn" onClick="filterAndSave">Filter</Button>
</Window>
</Alloy>
My filterWindow.js:
var photo = Alloy.createController('photo').getView();
$.selectedPhoto.add(photo);
$.selectedPhoto.width = appWidth;
$.selectedPhoto.height = appWidth;
$.label.text = "Some text";
function filterAndSave(e) {
var blob = $.finalImage.toBlob();
Ti.Media.saveToPhotoGallery(blob,{
success: function(e){
alert('Saved image to gallery');
},
error: function(e){
alert("Error trying to save the image.");
}
});
}
Thanks in advance for having a look at this one!

I had a similar issues in one of my projects. I made a screenshot of the area I needed as the new picture.
//This should be put in your filterAndSave method
if (Ti.Platform.osname == "android") {
var image = $.imageContainer.toImage().media;
} else {
var image = $.imageContainer.toImage(null, true);
}
//Saving the image if it is needed somewhere else
var f = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, "finalChallengeImage.jpeg");
f.write(image);
//Save it to the gallery and do what has to be done
You should have a look at the official documentation of the toImage() function. It needs different arguments depending on the platform you are using.
Please note that I did not needed to save the image to the gallery so that must be done additionally (although it seems like you already figured out how to do this).

Ok... found it. Need to Save it as a png file, otherwise it sets the background of the overlapping element white though it has a smaller height. But anyway... saving as a png works. But have only tried it in iOS.
So here is the final working code:
filterWindow.xml:
<View id="finalImage">
<View id="selectedPhoto" />
<View id="counter">
<ImageView id="weatherIcon" />
<Label id="label" />
</View>
</View>
filterWindow.js:
var photo = Alloy.createController('photo').getView();
// adding the selected photo from the previous step into the first child-View
$.selectedPhoto.add(photo);
$.selectedPhoto.width = appWidth;
$.selectedPhoto.height = appWidth;
$.finalImage.width = appWidth;
$.finalImage.height = appWidth;
$.label.text = "Some text";
function filterAndSave(e) {
if (Ti.Platform.osname == "android") {
var image = $.finalImage.toImage().media;
} else {
var image = $.finalImage.toImage(null, true);
}
//Saving the image if it is needed somewhere else
var f = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, "finalImage.png");
f.write(image);
//Save it to the gallery
Ti.Media.saveToPhotoGallery(image,{
success: function(e){
alert('Saved image to gallery');
},
error: function(e){
alert("Error trying to save the image.");
}
});
}
Once again, thanks so much for your, Robin.

Related

Konva Image showing black when loading

I'm trying to have a grid as a background using ImageKonva and filling it with a pattern.
The problem is that when I load the canvas, the ImageKonva looks completely black, and it shows up as soon as I add children elements.
import React from 'react'
import { Stage, Layer, Image as ImageKonva } from 'react-konva'
const Canvas = ({ children, width, height, onClick }) => {
const image = new Image()
// this hash is the image of a grid
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAIElEQVQoU2NkIAK8e/fuPyMR6hhGFeINJXDwgAhiwhIAOZAl5YYZd5AAAAAASUVORK5CYII='
return (
<Stage width={width} height={height}>
<Layer>
<ImageKonva
preventDefault={false}
width={width / 2}
height={width / 2}
fillPatternImage={image}
onClick={onClick}
/>
{children}
</Layer>
</Stage>
)
}
I've created this codesandbox where you can see the issue: https://codesandbox.io/s/angry-river-kszh0?file=/src/App.js
Note: It's not always reproducible, (can't figure out what's the pattern).
Sometimes it wouldn't happen, and I need to open chrome's console and refresh the page to make it happen.
You'll see the black box, and it will only show the grid after you click the button. The button only adds a child element.. from there, the image would always show. This problem only happens during the first load.
I believe I've figured it out, it seems I didn't consider that the image could be added asynchronously... so when I load the canvas, the image is not there yet.
So the solution is to only load ImageKanvas once the image is loaded using by setting an onload method to the image object
const Canvas = ({ children, width, height, onClick }) => {
const [loadGrid, setLoadGrid] = useState(false);
const image = new Image();
// this hash is the image of a grid
image.src =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAIElEQVQoU2NkIAK8e/fuPyMR6hhGFeINJXDwgAhiwhIAOZAl5YYZd5AAAAAASUVORK5CYII=";
image.onload = () => {
setLoadGrid(true);
};
return (
<Stage width={width} height={height}>
<Layer>
{loadGrid && (
<ImageKonva
preventDefault={false}
width={width / 2}
height={width / 2}
fillPatternImage={image}
onClick={onClick}
/>
)}
{children}
</Layer>
</Stage>
);
};
https://codesandbox.io/s/wild-wind-br2qo?file=/src/App.js

How can I repeat a pattern image to create a background in React Native?

I'm building a simple ReactNative app for iOS and I'm trying to add a background image. It seems like there is no backgroundImage tag, and while I did manage to show the image on the page once, I can't repeat it throughout the page like you can with CSS. Any suggestions?
iOS
Images on iOS now include a repeat resizeMode property.
Use it like so:
<Image
src={/* whatever your source is */}
resizeMode="repeat"
/>
Android
June 2018 Update:
Starting from react-native 0.56 Android Images also support the repeat prop. (https://github.com/facebook/react-native/commit/0459e4ffaadb161598ce1a5b14c08d49a9257c9c)
Before June 2018:
On Android the repeat property does NOT work so:
you'll have to use something like Shiraman's answer
External lib:
There's now this great project called react-native-bgimage (created by Alex Melanchenko) which works well:
Here's how I use it:
import RepeatingPattern from 'react-native-bgimage';
<RepeatingPattern
drawable="block_pattern"
style={{
height: 45,
}}
/>
and then I add a pattern png file in android/app/src/main/res/drawable/block_pattern.png
Despite that this question is pretty old I would like to put my two cents in. It is also can be done via <ImageBackground> component (reference).
Example:
<ImageBackground source={require('./path/to/image.png')} style={{width: '100%', height: '100%'}} imageStyle={{resizeMode: 'repeat'}}>
// Your inside content goes here
</ImageBackground>
Don't forget to import component in the beginning of file, e.g. import { ImageBackground } from 'react-native';
I would like to extend Sriraman answer. To make the repeated images as the background, you need to take an addtional step of adding a new view and making its position absolute and background transparent, then adding all the other components inside of it.
var React = require('react-native');
var Dimensions = require('Dimensions');
var {
Image
} = React;
var RepeatImage = React.createClass({
render: function(){
var images = [],
imgWidth = 7,
winWidth =Dimensions.get('window').width;
for(var i=0;i<Math.ceil(winWidth / imgWidth);i++){
images.push((
<Image source={{uri: 'http://xxx.png'}} style={} />
))
}
return (
<View style={{flex:1,flexDirection:'row'}}>
{
images.map(function(img,i){
return img;
})
}
<View style={{position: 'absolute', top: 0, bottom: 0, left: 0, right: 0}}>
{/*Place all you compoents inside this view*/}
</View>
</View>
)
}
});
You can't repeat background image like CSS in React Native. But, You can achieve it by iterating the image like
var React = require('react-native');
var Dimensions = require('Dimensions');
var {
Image
} = React;
var RepeatImage = React.createClass({
render: function(){
var images = [],
imgWidth = 7,
winWidth =Dimensions.get('window').width;
for(var i=0;i<Math.ceil(winWidth / imgWidth);i++){
images.push((
<Image source={{uri: 'http://xxx.png'}} style={} />
))
}
return (
<View style={{flex:1,flexDirection:'row'}}>
{
images.map(function(img,i){
return img;
})
}
</View>
)
}
});

how to flip from bottom an iOS view with appcelerator

I have an application which displays a view inside another view with appcelerator 5.1.2.
I want to animate the view to appear from bottom when opened, but could not figure out how to do it.
I have already done the exact opposite which is to make it disappear to bottom. Here is the code :
function closeViewFromBottom(animationView) {
var newtop = Ti.Platform.displayCaps.platformHeight + 20;
animationView.animate({
top:newtop,
duration:1000,
autoreverse: false
});
};
You can set the start top value to platformHeight and then animate top to 0. Also set the height of that view to platformHeight. For iOS you can also set the outer-view clipMode to Titanium.UI.iOS.CLIP_MODE_ENABLED
Edit: full example
index.tss
"Window": {
backgroundColor: "#fff"
}
"#view":{
backgroundColor: "red",
width:Ti.UI.FILL,
height:Ti.UI.FILL,
}
index.xml
<Alloy>
<Window >
<View id="view"/>
<Button id="btn" title="show view"/>
</Window>
</Alloy>
index.js
$.view.top = Ti.Platform.displayCaps.platformHeight;
function openViewFromBottom(animationView) {
animationView.top = Ti.Platform.displayCaps.platformHeight;
animationView.animate({
top:0,
duration:1000
});
};
function onClickButton(e){
openViewFromBottom($.view);
}
$.btn.addEventListener("click",onClickButton);
$.index.open();

React native Image variable in name doesn't work

I'm trying to load an image that has a variable in it's source, something like this.
<View>
{_.map(this.state.ambiences, (id) => {
var image = require('../../assets/img/ambiances/icons/' + label + '.png'); // variable label equals "chic" here
var image2 = require('../../assets/img/ambiances/icons/chic.png');
return <Image style={styles.pastilleOverlay} source={image} />;
})}
</View>
I get the following error (thrown when trying to set variable image) : Requiring unknown module "../../assets/img/ambiances/icons/chic.png"
If I comment the var image = ... line, it works fine with source={image2} in the Image tag.
I checked, both strings in the are exactly the same. Any ideas ?
Workaround
Maybe this Issue could help you.
We intentionally don't support dynamically generated image names because it makes it very hard to manage assets over time, just like how you wouldn't want to do
var MyComponent = require('./' + libName + typeOfComponent);
or something like that. Dynamic image name generation like this also
won't work with the new dynamic asset managing system we're rolling
out which let's you add and update assets on the fly with just cmd+R
(no more need to add to Xcode and recompile).
Bundled Images
The images you want to use, need to be bundled "via Xcode asset catalogs or Android drawable folder", as the documentation says. Also you have to specify the dimensions of the images manually.
Note that this approach provides no safety checks. It's up to you to guarantee that those images are available in the application.
<View>
{_.map(this.state.ambiences, (id) => {
return <Image style={styles.pastilleOverlay} source={{ uri: '../../assets/img/ambiances/icons/' + label + '.png' }} style={{width: 40, height: 40}} />;
})}
</View>
Alternative
What do you think about using a switch- or if-statement?
<View>
{_.map(this.state.ambiences, (id) => {
switch (label) {
case "chic":
return <Image style={styles.pastilleOverlay} source={require('../../assets/img/ambiances/icons/chic.png')} />;
case "otherimage":
return <Image style={styles.pastilleOverlay} source={require('../../assets/img/ambiances/icons/otherimage.png')} />;
default:
return <Image style={styles.pastilleOverlay} source={require('../../assets/img/ambiances/icons/default.png')} />;
}
})}
</View>
This might be little late, but if you have to have to change image source, update the key for image element. It will treat the re-rendered images as a new component and will require the image correctly.
Simply using image name in the key, did the trick.

Upload images with preview on picture box in asp.net mvc

I want to upload image in asp.net mvc like this way.I am using input type file for uploading images , its working fine but I want that when user click on this image and select that image , that image would appear on this type of box , how would I do that . I am saving images path in database and putting them on file directory.
I suspect the best bet is to use the HTML5 file API to read the contents of the attached image to display a preview. When the user submits the file you could do the server-side processing as you currently are, store the URL and return to the browser the location of the new image for proper preview. But check the performance of previewing a large image.
The link shows an example of previewing the file. I've copied the code in here as well, but please check the article for better understanding.
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function(theFile) {
return function(e) {
// Render thumbnail.
var span = document.createElement('span');
span.innerHTML = ['<img class="thumb" src="', e.target.result,
'" title="', escape(theFile.name), '"/>'
].join('');
document.getElementById('list').insertBefore(span, null);
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
.thumb {
height: 75px;
border: 1px solid #000;
margin: 10px 5px 0 0;
}
<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>

Resources