I'm using react native image picker and image resizer to pick and then resize an image. How do I get the base64 of the image once it has been resized?
ImagePickerManager.showImagePicker(imagepicker_options, (response) => {
ImageResizer.createResizedImage(response.uri, 550, null, 'JPEG', 100).then((resizedImageUri) => {
//get base64 of image
});
});
https://libraries.io/npm/react-native-asset-library-to-base64
ImagePickerManager.showImagePicker(imagepicker_options, (response) => {
ImageResizer.createResizedImage(response.uri, 550, null, 'JPEG', 100).then((resizedImageUri) => {
//get base64 of image, uri is link to asset-library://
ReadImageData.readImage(uri, (imageBase64) => {
console.log(imageBase64);
});
});
});
you might also want to read this if you haven't https://github.com/facebook/react-native/issues/1158
Actually the imagepicker_options provides a way to resize.
You can pass maxWidth and maxHeight on options.
The code:
const imagepicker_options = {
mediaType: 'photo',
maxWidth: 550,
storageOptions: {
skipBackup: true,
cameraRoll: false,
path: 'images',
},
}
ImagePickerManager.showImagePicker(imagepicker_options, (response) => {
//get base64 of image
const base64 = response.data
});
Related
I'm figuring out how to enable a local upload folder for a profile image.
Now, i've come as far as storing a file in the uploads folder. However, when I return that file it has no extension and its a JFIF binary file:
���� JFIF �� cmp3.10.3.3Lq4 0xa61382cc�� C
// etcetera...
The controller I've created is:
./src/controllers/user-profile.controller.ts
#Controller('user-profile')
export class UserProfileController {
#Post('/:id/upload-photo')
#UseInterceptors(FileInterceptor('image', { dest: './uploads' }))
uploadSinglePhoto(
#Param('id', ParseIntPipe) id: number,
#UploadedFile() image
) {
console.log('===> ', image);
return this.userProfileService.saveUserProfilePhotoLocation(id, image.path);
}
#Get('/:id/profile-photo')
getUserProfilePhoto(
): any {
// '15c924f42ffaa67b3f14a5be05f0a312' is the file name that is created by the upload
return new StreamableFile(createReadStream(join(process.cwd(), 'uploads', '15c924f42ffaa67b3f14a5be05f0a312')))
}
}
The image object in the console log is:
===> {
fieldname: 'image',
originalname: '526dad4edd250b689eeb1394c3c6eb41.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: './uploads',
filename: '590b454b4315009660273deac082b4ed',
path: 'uploads\\590b454b4315009660273deac082b4ed',
size: 45842
}
Then I store the path to the database.
./src/services/user-profile.service.ts
#Injectable()
export class UserProfileService {
constructor(
#InjectRepository(UserProfileEntity)
private userProfileRepostory: Repository<UserProfileEntity>
) {}
async saveUserProfilePhotoLocation(id, path): Promise<UserProfileEntity> {
const result = await this.userProfileRepostory.createQueryBuilder()
.update(UserProfileEntity)
.set({
photo: path
})
.where({id})
.returning('*')
.execute();
return result.raw;
}
}
And finally I've configured the express server to be able to serve static files from the uploads folder:
./src/main.ts
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.useStaticAssets(join(__dirname, '..', 'uploads'), {
index: false,
prefix: 'uploads',
});
await app.listen('3000');
}
bootstrap();
Now when I do a get on the end point /:id/profile-photo it does not return me a rendered image. Ïnstead it returns a file with a random set of characters in it which is probably because of the encoding.
What should I do so that I can serve an jpeg file to my application?
What is happening here?
When setting the content header (thanks Jay McDoniel) to 'image/jpeg' and creating a readable stream it returns the image:
#Get('/:id/profile-photo')
getUserProfilePhoto(
#Res({ passthrough: true }) res: Response
): StreamableFile {
res.set({'Content-Type': 'image/jpeg'});
const imageLocation = join(process.cwd(), 'uploads', '15c924f42ffaa67b3f14a5be05f0a312');
const file = createReadStream(imageLocation);
return new StreamableFile(file);
}
I want to process images using sharp before saving so I don't need to save the file twice (one by multer and one by sharp). The best way I found is to save the file in memory with initializing multer with no argument:
const upload = multer()
and then giving the file buffer to sharp in the route handler:
await sharp(req.file.buffer)
.resize(500)
.jpeg({ quality: 50 })
.toFile(path)
);
If is there a better way let me know.
The better question would be:
Is there something like a hook in multer that calls before saving? so I can change the file content before saving it.
the process is start from fileFilter method then fileName of multer so you should start resize it in fileFilter save it to temporary directory then reszie image after resize you can use method .ToFile of sharp package it will save the destination inside .toFile("./upload")
file-mapper.ts (use for return another object)
export const fileMapper = ({ file, req }: FileMapper) => {
if (!file) {
return null!;
}
const fileName = editFilename(req.file);
const image_url = `${req.protocol}://${req.headers.host}/${req.file.destination}/${fileName}`;
resizeImage(req, fileName);
return {
filename: file.filename,
image_url,
path: file.path,
};
};
my resize-image.ts
import { Request } from 'express';
import path from 'path';
import sharp from 'sharp';
import fs from 'fs';
export const resizeImage = async (req: Request, fileName: string) => {
await sharp(req.file.path)
.resize({ height: 700, width: 700, position: 'center' })
.jpeg({ quality: 90, chromaSubsampling: '4:4:4' })
.toFile(path.resolve(req.file.destination, fileName))
.then((sharpOutPut) => {
if (sharpOutPut) fs.unlinkSync(req.file.path);
})
.catch((err) => {
throw err;
});
};
disk-storage.ts
const storage= diskStorage({
destination: 'upload/product',
filename: editFileName,
}),
fileFilter: imageFileFilter,
})
use sharp in fileFilter of multer
I'm using fileMapper because I want to receive new object for my db
I am testing a portal with Cypress.io, which has a file upload functionality.
But my file always failed to upload because the API call is going wrong.
Correct API Call:
**
POST 200 /etl/v1.0.0/datauploaderetl/spaces/etl_jyddc0tx/data-files
**
But when uploading through Cypress, the following is the URL:
**
POST 404 /etl/v1.0.0/datauploaderetl/data-files
**
As you can clearly see, the API is incorrect. I added the wait here, still, it doesn't work.
Following is the piece of code:
cy.fixture(fileName1).then(fileContent => {
cy.get('input[type="file"]').attachFile({
fileContent: fileContent.toString(),
fileName: fileName1,
mimeType: fileType
})
});
cy.waitUntil(() => cy.get(":nth-child(98) > .modal > .modal-lg > .modal-content > .modal-body")
.should('contain.text', 'Status: completed')
);
Please help!
At Command.js, add below code:
let LOCAL_STORAGE_MEMORY = {};
Cypress.Commands.add("saveLocalStorage", () => {
Object.keys(localStorage).forEach(key => {
LOCAL_STORAGE_MEMORY[key] = localStorage[key];
});
});
Cypress.Commands.add("restoreLocalStorage", () => {
Object.keys(LOCAL_STORAGE_MEMORY).forEach(key => {
localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);
});
});
Then at the test case file, add below beforeEach and afterEach block respectively:
beforeEach(() => {
cy.restoreLocalStorage();
})
afterEach(() => {
cy.saveLocalStorage();
})
This will solve the issue where Cypress clears the "local storage" at the browser.
As per documentation this is the way to upload file :
cy.fixture('filepath').as('filetoupload')
cy.get('input[type=file]').then(function($input) {
// convert the logo base64 string to a blob
const blob = Cypress.Blob.base64StringToBlob(this.filetoupload, fileType)
$input.fileupload('add', { files: blob })
})
or
cy.fixture('filepath').as('filetoupload')
cy.get('input[type=file]').then(function(el) {
// convert the logo base64 string to a blob
const blob = Cypress.Blob.base64StringToBlob(this.filetoupload,fileType )
const file = new File([blob], '<path>', { type: fileType })
const list = new DataTransfer()
list.items.add(file)
const myFileList = list.files
el[0].files = myFileList
el[0].dispatchEvent(new Event('change', { bubbles: true }))
})
https://docs.cypress.io/api/utilities/blob.html#Image-Fixture
I am trying to create an app and within the app the user can install a theme, however, I can't seem to work out why the theme is not being created. It keeps pulling the themes already installed on my store to the console, my code doesn't seem to create a theme that would show up on my shopify store.
server.js
router.post('/api/theme', async (ctx) => {
try {
const results = await fetch("https://" + ctx.cookies.get('shopOrigin') + "/admin/themes.json", {
headers: {
'X-Shopify-Access-Token': ctx.cookies.get('accessToken')
},
})
.then(response => response.json())
.then(json => {
console.log("https://" + ctx.cookies.get('shopOrigin') + "/admin/api/2020-01/themes.json", json);
});
ctx.body = {
data: results
};
} catch (err) {
console.log(err)
}
});
frontend .js file
async function getUser() {
var url = `/api/theme`;
var method = 'post';
const theme = {
theme: {
name: "Lemongrass",
src: "https://codeload.github.com/Shopify/skeleton-theme/zip/master"
}
};
const data = JSON.stringify(theme);
fetch(url, { method: method, body: data})
}
In order to create a theme you need a zip archive of the theme you like to create.
The end point should be /admin/api/2020-01/themes.json and the body should be something like this:
{
"theme": {
"name": "Theme name",
"src": "http://themes.shopify.com/theme.zip",
"role": "unpublished"
}
}
Please refer to https://shopify.dev/docs/admin-api/rest/reference/online-store/theme#create-2020-01 for more information.
At the moment from your code I don't see neither the correct POST request, neither the archive file.
when I tried to upload multiple images at same time it uploads the same image (an image which one was selected first) twice.
I use {multiple:1} but still it doesn't work.
const uploadToCloudinary = filename =>
new Promise((resolve, reject) => {
const publicId = randomize("0", 5);
// cloudinary.uploader.image_upload_tag(filename, { html: { multiple: 1 } });
cloudinary.uploader.upload(
filename,
{
html: { multiple: 1 },
tags: "basic_sample",
public_id: publicId,
folder: "vizard",
eager: [
{
width: 200,
crop: "fit"
},
{ width: 10, crop: "fit" }
]
},
(err, image) => {
if (err) console.warn(err);
return resolve({
original: image && image.url,
w200: image && image.eager[0].url,
placeholder: image.eager[1].url,
publicId: image.public_id
});
}
);
});
The upload method of the Upload API does not support a field called html and is used to upload files directly rather than create an input field where those can be selected.
What you're probably looking for is the image_upload_tag or the jQuery direct upload functionality for multiple files - https://cloudinary.com/documentation/jquery_image_and_video_upload#upload_multiple_images