i wanna Export a Signature from SignatureController and upload to hosting with FtpConnect pub in Flutter.
I tried 100 different ways but it's not going with Future Uint64 for upload , FtpConnect can upload only String File(), I think this is a File path ? Or can I direct upload a Signature without save on Phone Local Storage ? I must convert this Signature as Png or Jpeg then I can upload to my Hosting.here ist my code ,
late final SignatureController signature = SignatureController(
penStrokeWidth: 2,
penColor: Colors.black,
exportBackgroundColor: const Color.fromARGB(255, 154, 153, 153),
);
uploadSignature() async {
final pngUpload = signature.toPngBytes();
//Show Image on Pop up
/* Get.defaultDialog(
content: Container(
width: Get.width * 0.5,
height: Get.height * 0.5,
child: Image.memory(pngUpload),
));
*/
debugPrint("FTP Upload Starting ----------------");
FTPConnect ftpConnect =
FTPConnect('**********', user: '********', pass: 'FtpPassword');
await ftpConnect.connect();
bool res = await ftpConnect.uploadFileWithRetry(File(pngUpload.toString()),
pRetryCount: 2,
pRemoteName: "sign-" + DateTime.now().toString() + ".png");
await ftpConnect.disconnect();
print(res);
}
pubs
https://pub.dev/packages/signature
https://pub.dev/packages/ftpconnect
Thanks for all.
Hosting Upload File Screenshot , if i use it then its coming as 0 Byte not showing.
Related
I currently have this function that returns a Uint8List. I would like to render it as a pdf in my android app so I can see it. Not sure how to do this, any help is appreciated! This is the source code if that is also of any help. Thank you
https://github.com/DavBfr/dart_pdf/blob/master/demo/lib/invoice.dart
Future<Uint8List> generateInvoice(PdfPageFormat pageFormat) async {
final lorem = pw.LoremText();
final products = <Product>[
Product('19874', lorem.sentence(4), 3.99, 2),
Product('98452', lorem.sentence(6), 15, 2),
Product('28375', lorem.sentence(4), 6.95, 3),
Product('95673', lorem.sentence(3), 49.99, 4),
Product('23763', lorem.sentence(2), 560.03, 1),
Product('55209', lorem.sentence(5), 26, 1),
Product('09853', lorem.sentence(5), 26, 1),
];
final invoice = Invoice(
invoiceNumber: '982347',
products: products,
customerName: 'Abraham Swearegin',
customerAddress: '54 rue de Rivoli\n75001 Paris, France',
paymentInfo:
'4509 Wiseman Street\nKnoxville, Tennessee(TN), 37929\n865-372-0425',
tax: .15,
baseColor: PdfColors.teal,
accentColor: PdfColors.blueGrey900,
);
return await invoice.buildPdf(pageFormat);
}
class Invoice {
Invoice({
this.products,
this.customerName,
this.customerAddress,
this.invoiceNumber,
this.tax,
this.paymentInfo,
this.baseColor,
this.accentColor,
});
final List<Product> products;
final String customerName;
final String customerAddress;
final String invoiceNumber;
static const _darkColor = PdfColors.blueGrey800;
static const _lightColor = PdfColors.white;
PdfColor get _baseTextColor =>
baseColor.luminance < 0.5 ? _lightColor : _darkColor;
PdfColor get _accentTextColor =>
baseColor.luminance < 0.5 ? _lightColor : _darkColor;
double get _total =>
products.map<double>((p) => p.total).reduce((a, b) => a + b);
double get _grandTotal => _total * (1 + tax);
PdfImage _logo;
Future<Uint8List> buildPdf(PdfPageFormat pageFormat) async {
// Create a PDF document.
final doc = pw.Document();
final font1 = await rootBundle.load('assets/roboto1.ttf');
final font2 = await rootBundle.load('assets/roboto2.ttf');
final font3 = await rootBundle.load('assets/roboto3.ttf');
_logo = PdfImage.file(
doc.document,
bytes: (await rootBundle.load('assets/logo.png')).buffer.asUint8List(),
);
// Add page to the PDF
doc.addPage(
pw.MultiPage(
pageTheme: _buildTheme(
pageFormat,
font1 != null ? pw.Font.ttf(font1) : null,
font2 != null ? pw.Font.ttf(font2) : null,
font3 != null ? pw.Font.ttf(font3) : null,
),
header: _buildHeader,
footer: _buildFooter,
build: (context) => [
_contentHeader(context),
_contentTable(context),
pw.SizedBox(height: 20),
_contentFooter(context),
pw.SizedBox(height: 20),
_termsAndConditions(context),
],
),
);
// Return the PDF file content
return doc.save();
}
You can save the file locally and render it using some pdf viewer
final String dir = (await getApplicationDocumentsDirectory()).path;
final String path = '$dir/example.pdf';
final File file = File(path);
await file.writeAsBytes(doc.save());
Now you can use this path to view the pdf using a pdf viewer.
You can check this medium post for reference.
With this solution, you don't need to save the file to view it as a widget.
Use the package: syncfusion_flutter_pdfviewer
syncfusion_flutter_pdfviewer: ^19.4.42-beta
This package provides a widget which can load pdf from bytes
Scaffold(
body:SfPdfViewer.memory(_your_pdf_in_bytes),
);
This widget can be added anywhere in the widget tree in your app
i dont want to store image in cache.. iam using CachedNetworkImage for image loading..
I want know is there any option to remove or do not store image in cache like picasso..
my code:
var annotatedImg = CachedNetworkImage(
fit: BoxFit.fill,
imageUrl: Constants.IMAGE_BASE_URL + widget._fileId + Constants.CONTOUR_IMG_SUFFIX,
placeholder: (context, url) => progressBar,
errorWidget: (context, url, error) => new Icon(Icons.error),
);
i have tried
annotatedImg.cacheManager.emptyCache();
but its shows cant call emptyCache is null..
Since CachedNetworkImage version 2.3, all these solutions won't work because it cached images in 2 different places (DefaultCacheManager & NetworkImageProvider)
So the only solution is using the evictFromCache built-in method from CachedNetworkImage
like this:
Future _deleteImageFromCache() async {
String url = "your url";
await CachedNetworkImage.evictFromCache(url);
}
evictFromCache is a Static method so it doesn't require to have the CachedNetworkImage in your Widget tree, you can use it directly from any place.
I agree with MichaelM, Don't use CachedNetworkImage.If you show image like this :
Image.network(
_headImageUrl,
fit: BoxFit.fitHeight,
)
you can use those code to clean image cache:
PaintingBinding.instance.imageCache.clear();
Firstly add the package (flutter_cache_manager) to pubspec.yaml file as following:
dependencies:
flutter:
sdk: flutter
flutter_cache_manager: ^1.1.3
After a day, I found the solution. Use the DefaultCacheManager object by calling emptyCache() method, this clears the cache data.
DefaultCacheManager manager = new DefaultCacheManager();
manager.emptyCache(); //clears all data in cache.
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
await DefaultCacheManager().removeFile('YOUR_URL');
DONT USE emptyCache() from the first answer, it clear ALL your Cache
CachedNetworkImage stores the images in temporary(cache) folder, you can get access to it with path_provider's getTemporaryDirectory() method. There you will find libCachedImageData (You might need to check the name). There you can delete the folder.
To do it in your app you should use Directory class like:
final Directory tempDir = await getTemporaryDirectory();
final Directory libCacheDir = new Directory("${tempDir.path}/libCachedImageData");
await libCacheDir.delete(recursive: true);
If you do not want to store the downloaded image in a cache, then don't use CachedNetworkImage. Instead, use a FadeInImage widget with a NetworkImage:
FadeInImage(
// here `bytes` is a Uint8List containing the bytes for the in-memory image
placeholder: // This should be an image, so you can't use progressbar,
image: NetworkImage('https://backend.example.com/image.png'),
)
In your CachedNetworkImage, add CacheManager Config:
CachedNetworkImage(CacheManager(Config(
featureStoreKey,
stalePeriod: const Duration(seconds: 15),
maxNrOfCacheObjects: 1,
repo: JsonCacheInfoRepository(databaseName: featureStoreKey),
fileService: HttpFileService(),
),
),
fit: BoxFit.fill,
imageUrl: Constants.IMAGE_BASE_URL + widget._fileId + Constants.CONTOUR_IMG_SUFFIX,
placeholder: (context, url) => progressBar,
errorWidget: (context, url, error) => new Icon(Icons.error),
);
Then to clear it, add this void statement:
void _clearCache() {
try {
JsonCacheInfoRepository(databaseName: featureMain1Store).deleteDataFile();
} catch (e, s) {
print(s);
}
imageCache!.clear();
imageCache!.clearLiveImages();
setState(() {});
}
My goal is to open a CSV file from phone local storage ~/Downloads and import it into the DB.
I'm using Flutter and to this day I have looked over a dozen examples without a success.
However I was able to get contents of the file printed in the console, but for that I had to have a file in assets/res folder in the app project.
If I use getExternalStorageDirectory, I get emulated/storage/0/ as a result. How to get to device's internal storage (not external storage as phone used will not have an option for a SD card or if they will, it will not be used)?
For the DB, I was able to get a working example using sqflite, but I as I'm total noob, I can't get it to work within my already designed app.
Open the file as a text document using open_file from package:open_file/open_file.dart and parse the contents yourself.
See https://pub.dartlang.org/documentation/open_file/latest/
Back to beginning and yet a little bit closer to the solution I need. I have file_picker (https://pub.dartlang.org/packages/file_picker), which helps to pick file using file explorer:
String _filePath;
void getFilePath() async {
try {
String filePath = await FilePicker.getFilePath(
type: FileType.CUSTOM, fileExtension: 'csv');
if (filePath == '') {
return;
}
print("Path: " + filePath);
setState(() {
this._filePath = filePath;
});
} on PlatformException catch (e) {
print("Error picking file: " + e.toString());
}
}
Using above code returns the path of the file e.g. "/storage/emulated/0/Download/1.csv".
Now I use this path to read the contents of the file:
...
RaisedButton(
child: const Text('Import data - dummy'),
color: Theme.of(context).accentColor,
elevation: 4.0,
splashColor: Colors.blueGrey,
onPressed: () {
print('Verifying click done');
// Show contents of the file
readContents();
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: getFilePath,
tooltip: 'Choose file to import',
child: new Icon(Icons.sd_storage),
)
...
Future<File> get _localFile async {
final path = await _filePath;
return File('$path');
}
Future<int> readContents() async {
try {
final file = await _localFile;
// Read the file
String contents = await file.readAsString();
return int.parse(contents);
} catch (e) {
// If we encounter an error, return 0
return 0;
}
}
Now as the above code should return contents of a CSV file, it does nothing. CSV file contains a list of items.
Can somebody let me know why and be so kind to show me how I can save parsed content of a file to a string or even better strings which represent each column from the file?
THANKS!
Background: I'm using Firebase Cloud Functions, the new Firestore Database, and storage bucket with an Android client.
What I want to accomplish:
When a user uploads a picture to a storage bucket, I want to use cloud functions to get the file path/link to the image location in the storage bucket and store this string as a new document under a new collection called "pictures" under the currently logged in user's document in Firestore.
That way, I can see the images each user has uploaded directly in Firestore and it makes it easier to pull a specific user's images down to the Android client.
What I've completed so far:
1. When a user logs in for the first time, it creates a user doc in the new Firestore Database.
2. A logged in user can upload an image to a storage bucket.
3. Using Firebase Cloud Functions, I managed to get the file path/link of the storage location as follows:
/**
* When a user selects a profile picture on their device during onboarding,
* the image is sent to Firebase Storage from a function running on their device.
* The cloud function below returns the file path of the newly uploaded image.
*/
exports.getImageStorageLocationWhenUploaded = functions.storage.object().onFinalize((object) => {
const filePath = object.name; // File path in the bucket.
const contentType = object.contentType; // File content type.
// Exit if this is triggered on a file that is not an image.
if (!contentType.startsWith('image/')) {
console.log('This is not an image.');
return null;
}
console.log(filePath);
});
Question: How do I get the currently logged in user and store this user's uploaded image file path/link as a new doc under this logged in user's documents within the Firestore database using Cloud Functions?
Currently, with Cloud Storage triggers, you don't have access to authenticated user information. To work around that, you'll have to do something like embed the uid in the path of the file, or add the uid as metadata in the file upload.
I had a similar problem where I wanted to associate a user uploaded image with his/her uid. I found an elegant solution that does not necessarily requires inserting the uid in the path of the file or even adding it as metadata in the file upload. In fact, the uid is securely transmitted to the database via the standard idToken encoding. This example employs a modified version of the generate-thumbnail cloud function example (found here) which I believe the author of the question was using/alluding to. Here are the steps:
Client side:
Create a trigger function that will run once the user uploaded the image - this functions will simply call the cloud function directly (via the httpsCallable method). The cloud function will receive the user uid (idToken encoded), along with any image metadata you may wish to send. The cloud function will then return a signed URL of the image.
const generateThumbnail = firebase.functions().httpsCallable('generateThumbnail');
const getImageUrl = (file) => {
firebase.auth().currentUser.getIdToken(true)
.then((idToken) => generateThumbnail({
idToken,
imgName: file.name,
contentType: file.type
}))
.then((data) => {
// Here you can save your image url to the app store, etc.
// An example of a store action:
// setImageUrl(data.data.url);
})
.catch((error) => {
console.log(error);
})
}
Create an image upload function – this is a standard file upload handling function; you can make the uid part of storage file path location for the image (if you want to) but you can also trigger a firebase function once the image has been uploaded. This is possible using the 3rd parameter of the on method. Include the trigger function above as the 3rd argument in here.
// Function triggered on file import status change from the <input /> tag
const createThumbnail = (e) => {
e.persist();
let file = e.target.files[0];
// If you are using a non default storage bucket use this
// let storage = firebase.app().storage('gs://your_non_default_storage_bucket');
// If you are using the default storage bucket use this
let storage = firebase.storage();
// You can add the uid in the image file path store location but this is optional
let storageRef = storage.ref(`${uid}/thumbnail/${file.name}`);
storageRef.put(file).on('state_changed', (snapshot) => {}, (error) => {
console.log('Something went wrong! ', error);
}, getImageUrl(file));
}
Server side:
Create a cloud function to convert the image into a resized thumbnail and generate a signed URL – this cloud function takes the image from storage, converts it into a thumbnail (basically reduces its dimensions but keeps initial aspect ratio) using ImageMagick (this is installed by default on all cloud function instances). It then generates a signed URL of the image location and returns it to the client side.
// Import your admin object with the initialized app credentials
const mkdirp = require('mkdirp');
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');
// Max height and width of the thumbnail in pixels.
const THUMB_MAX_HEIGHT = 25;
const THUMB_MAX_WIDTH = 125;
// Thumbnail prefix added to file names.
const THUMB_PREFIX = 'thumb_';
async function generateThumbnail(data) {
// Get the user uid from IdToken
const { idToken, imgName, contentType } = data;
const decodedIdToken = await admin.auth().verifyIdToken(idToken);
const uid = decodedIdToken.uid;
// File and directory paths.
const filePath = `${uid}/thumbnail/${imgName}`;
const fileDir = path.dirname(filePath);
const fileName = path.basename(filePath);
const thumbFilePath = path.normalize(path.join(fileDir, `${THUMB_PREFIX}${fileName}`));
const tempLocalFile = path.join(os.tmpdir(), filePath);
const tempLocalDir = path.dirname(tempLocalFile);
const tempLocalThumbFile = path.join(os.tmpdir(), thumbFilePath);
// Exit if this is triggered on a file that is not an image.
if (!contentType.startsWith('image/')) {
return console.log('This is not an image.');
}
// Exit if the image is already a thumbnail.
if (fileName.startsWith(THUMB_PREFIX)) {
return console.log('Already a Thumbnail.');
}
// Cloud Storage files.
const bucket = initDb.storage().bucket('your_bucket_if_non_default');
const originalFile = bucket.file(filePath);
// Create the temp directory where the storage file will be downloaded.
// But first check to see if it does not already exists
if (!fs.existsSync(tempLocalDir)) await mkdirp(tempLocalDir);
// Download original image file from bucket.
await originalFile.download({ destination: tempLocalFile });
console.log('The file has been downloaded to', tempLocalFile);
// Delete the original image file as it is not needed any more
await originalFile.delete();
console.log('Delete the original file as it is not needed any more');
// Generate a thumbnail using ImageMagick.
await spawn('convert', [ tempLocalFile, '-thumbnail',
`${THUMB_MAX_WIDTH}x${THUMB_MAX_HEIGHT}>`, tempLocalThumbFile],
{ capture: ['stdout', 'stderr'] }
);
console.log('Thumbnail created at', tempLocalThumbFile);
// Uploading the Thumbnail.
const url = await uploadLocalFileToStorage(tempLocalThumbFile, thumbFilePath,
contentType);
console.log('Thumbnail uploaded to Storage at', thumbFilePath);
// Once the image has been uploaded delete the local files to free up disk space.
fs.unlinkSync(tempLocalFile);
fs.unlinkSync(tempLocalThumbFile);
// Delete the uid folder from temp/pdf folder
fs.rmdirSync(tempLocalDir);
await admin.database().ref(`users/${uid}/uploaded_images`).update({ logoUrl: url[0] });
return { url: url[0] };
}
// Upload local file to storage
exports.uploadLocalFileToStorage = async (tempFilePath, storageFilePath,
contentType, customBucket = false) => {
let bucket = initDb.storage().bucket();
if (customBucket) bucket = initDb.storage().bucket(customBucket);
const file = bucket.file(storageFilePath);
try {
// Check if file already exists; if it does delete it
const exists = await file.exists();
if (exists[0]) await file.delete();
// Upload local file to the bucket
await bucket.upload(tempFilePath, {
destination: storageFilePath,
metadata: { cacheControl: 'public, max-age=31536000', contentType }
});
const currentDate = new Date();
const timeStamp = currentDate.getTime();
const newDate = new Date(timeStamp + 600000);
const result = await file.getSignedUrl({
action: 'read',
expires: newDate
});
return result;
} catch (e) {
throw new Error("uploadLocalFileToStorage failed: " + e);
}
};
if (firebase.auth().currentUser !== null)
console.log("user id: " + firebase.auth().currentUser.uid);
Simple way to get userid of a user.
I am developing an Android app that manages PDFs. I know that Cloudinary allows users to upload PDFs and automatically generate thumbnails for the uploaded PDF (see here). Does Firebase Storage or Cloud Firestore offer a similar feature? If not, any recommended third-party tool for this task? Thanks!
Intro
ImageMagick comes pre installed on the cloud function environment, but Ghostscript does not (at least, not right now). Ghostscript is what’s needed to generate images from PDFs.
First, download a copy of the Ghostscript executable from here (linux 64 bit APGL Release), and store it in the root of your functions directory. You may want to rename the folder/executable name for shorter path references. This will be deployed when you deploy your function(s).
Second as seen in this repo, npm install —-save https://github.com/sina-masnadi/node-gs/tarball/master . This is a wrapper you’ll need to communicate with the Ghostscript executable from within your function.
Third, you may want to look over the Ghostscript / ImageMagick docs to customize even further.
Sample cloud function
Finally, here is a function that I just got working for my functions file structure. You’ll need to write better validation and tweek it for your setup, but know that the meat of this will work.
const admin = require('firebase-admin');
const functions = require('firebase-functions');
const fs = require('fs');
const os = require('os');
const path = require('path');
const write = require('fs-writefile-promise');
const spawn = require('child-process-promise').spawn;
const mkdirp = require('mkdirp-promise');
const gs = require('gs');
const gs_exec_path = path.join(__dirname, '../../../ghostscript/./gs-923-linux-x86_64');
try { admin.initializeApp(functions.config().firebase); } catch(e) {}
/*
Callable https function that takes a base 64 string of a pdf (MAX
10mb), uploads a thumbnail of it to firebase storage, and returns its
download url.
*/
module.exports = functions.https.onCall((data, context) => {
if (!data.b64str) { throw Error('missing base 64 string of pdf!'); }
const b64pdf = data.b64str.split(';base64,').pop();
const pg = typeof data.pg === 'number' ? data.pg : 1; //1-based
const max_wd = typeof data.max_wd === 'number' ? data.max_wd : 200;
const max_ht = typeof data.max_ht === 'number' ? data.max_ht : 200;
const st_fname = typeof data.fname === 'string' ? data.fname : 'whatever.jpg';
const bucket = admin.storage().bucket();
const tmp_dir = os.tmpdir();
const tmp_pdf = path.join(tmp_dir, 'tmp.pdf');
const tmp_png = path.join(tmp_dir, 'doesntmatter.png');
const tmp_thumb = path.join(tmp_dir, st_fname.split('/').pop();
const st_thumb = st_fname;
/* create tmp directory to write tmp files to... */
return mkdirp(tmp_dir).then(() => {
/* create a temp pdf of the base 64 pdf */
return write(tmp_pdf, b64pdf, {encoding:'base64'});
}).then(() => {
/* let ghostscript make a png of a page in the pdf */
return new Promise((resolve, reject) => {
gs().batch().nopause()
.option(`-dFirstPage=${pg}`)
.option(`-dLastPage=${pg}`)
.executablePath(gs_exec_path)
.device('png16m')
.output(tmp_png)
.input(tmp_pdf)
.exec(err => err ? reject(err) : resolve());
});
}).then(() => {
/* make a thumbnail for the png generated by ghostscript via imagemagick */
var args = [ tmp_png, '-thumbnail', `${max_wd}x${max_ht}>`, tmp_thumb ];
return spawn('convert', args, {capture: ['stdout', 'stderr']});
}).then(() => {
/* upload tmp_thumb to storage. */
return bucket.upload(tmp_thumb, { destination: st_thumb });
}).then(() => {
/* get storage url for the uploaded thumbnail */
return bucket.file(st_thumb).getSignedUrl({
action:'read',
expires: '03-01-2500'
});
}).then(result => {
/* clean up temp files and respond w/ download url */
fs.unlinkSync(tmp_pdf);
fs.unlinkSync(tmp_png);
fs.unlinkSync(tmp_thumb);
return result[0];
});
});
Sample invocation from client
var fn = firebase.functions().httpsCallable('https_fn_name');
fn({
b64str: 'base64 string for pdf here....',
pg: 2, //optional, which page do u want a thumbnail of? 1 is the first.
fname: 'path/to/file/in/storage.jpg', //optional but recommended, .png if u like
max_wd: 300, // optional, max thumbnail width
max_ht: 300 // optional, max thumbnail height
}).then(res => console.log(res));
If you cant generate a signed url...
You'll need to Add the role "Cloud Functions Service Agent" to whatever service account this function is using. You can Add the role to your service account in your cloud console.