Creating QR Code as Base64 String using Spring Boot - java

I am creating a microservice using spring boot where in i have a file handling.
My task is to write the QR code to image file and base64 encode to transfer over network.
Because I need to write to an image file and then read and then base64 encode it , I need to first create the image file and then write to it.
Creating a temperory folder and keep the file ?, create a folder in root directory and keep the file? or use the java.io.tmpdir ....
Note: I have no use of this file once I encode it. Also there are lot of user to whom we will be exposing this service as rest api.
I want to know what is the best way to do this.

If you are using the https://github.com/zxing/zxing library i.e.
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.2.1</version>
</dependency>
Then something like the following will work.
#RestController
public class TestController {
#GetMapping(value = "/test")
public QrInfo getQrInfo() throws Exception {
String url = "https://news.bbc.co.uk";
int imageSize = 200;
BitMatrix matrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE,
imageSize, imageSize);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(matrix, "png", bos);
String image = Base64.getEncoder().encodeToString(bos.toByteArray()); // base64 encode
// return QrInfo
QrInfo qrInfo = new QrInfo();
qrInfo.setUrl(url);
qrInfo.setImage(image);
return qrInfo;
}
}
#Data // lombok for brevity
class QrInfo {
private String url;
private String image;
}
NOTE: This approach doesn't write any files but does it all in-memory using a ByteArrayOutputStream .
If you hit this endpoint you'll see the following: -
{
"url": "https://news.bbc.co.uk",
"image": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAQAAAACFI5MzAAABGUlEQVR42u2YSw7DIAxEzYpjcFM+N+UYrErtMUkjpd2WWQQlyudtLI89JpH5a8lDHvJnUkVXmkMPKcMeAg1peo70inrpRbm/ISFDwkhNX4NUSWxEo26WVFKisgc2ArWncSO3OthJvEs0nTju/bOT+NJKzJK++c5OovJWRIob2AwNsf6YXWJ3eFGbgXS4skgEGafaDGSifVONS/ZCQ/Q2YI5l8BdSS0ImwtTezehjiM9C3FG8fbVdykft/URTeEY918hlIZZFC9Yq0Rw6ns63nyxXtkTCYK6VuJv4NKvmMdgFMBHfBbRjb8JFxgoWW04RPmKfEaY2pgcZcT/OsL3GQ5baFrUN23iZZrvJ6pKjDJFXFvL8P3jIfvIGvNX7jsCaJvEAAAAASUVORK5CYII="
}
If you paste the Base64 into e.g https://codebeautify.org/base64-to-image-converter and point camera from your phone you will see the URL.
If you rendering this out it is easy i.e. in React (any JavaScript approach will be similar).
<img src={`data:image/png;base64,${image}`} />
I like this approach as if you are e.g. generate 2FA codes you can pass down both the random secret and the QR code - useful to have both as a backup if the user doesn't have access to a mobile device.

You can do this in a designated folder in your file-system easily and once you are done with the transfer, you can remove the file. But since, this operation is exposed over a rest api, concurrency and file collision can be an issue. To avoid that you can give unique to every file-name, that way same file-name collision can be avoided.
One approach could be to UUID for writing the file-name and storing the file with this name in the file-system. It will ensure collision doesn't occur.
String fileName = UUID.randomUUID().toString();

Related

How to fetch Azure Blob Content Using Java from Azure Functions

I am creating Azure function using Java, My requirement I need to copy blob from one container to another container with encryption
so, for encrypting blob I am adding 4bites before and after the blob while uploading to sink container
now, I need to fetch blob content, for this I found one class in azure i.e,
#BlobInput(
name = "InputFileName",
dataType = "binary",
path = sourceContainerName+"/{InputFileName}")
byte[] content,
Here byte[] content, fetching content of blob
but I am facing some errors like, if I pass any file name as InputFileName parameter it is giving 200ok means returning successful. also it is difficult to mefor exception handling
so I am looking for other ways for fetching blob content.... please answer me if any methods or classes we have
If you are looking for more control, instead of using the bindings, you can use the Azure Storage SDK directly. Check out the quickstart doc for getting
setup.
This sample code has full end-to-end code that you could build upon. Here is the code that you are looking for in it for reference
String data = "Hello world!";
InputStream dataStream = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
/*
* Create the blob with string (plain text) content.
*/
blobClient.upload(dataStream, data.length());
dataStream.close();
/*
* Download the blob's content to output stream.
*/
int dataSize = (int) blobClient.getProperties().getBlobSize();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(dataSize);
blobClient.downloadStream(outputStream);
outputStream.close();

How can i send images from server to my client?

I have been learning spring and to get the things together I am making an e-commerce application. I have used rest api to connect client and server. Now i need to send images to the client. My images are already stored in src/resources folder. What i need to know is that how do i send those images through rest api. so that i can use it in my client
I am very noob at this. I tried google and all i can find is examples of image files uploading to the server. I can't find a example of sending file from server to client through rest api. i've been stuck in this for past three day
Here is my rest controller:
now i need to know what should i do next so that i can send images
#RestController
#RequestMapping("/api")
public class CategoriesRestController {
// autowire customer service
#Autowired
private CategoriesService service;
//add mapping for GET all customer
#GetMapping("/categories")
public List<Categories> getCategories() {
return service.getCategories();
}
// adding mapping for GET only one customer
#GetMapping("/categories/{categoryId}")
public Categories getCategory(#PathVariable int categoryId) {
Categories categories = service.getCategory(categoryId);
if(categories == null) {
throw new CustomerNotFoundException("Customer id not found- "+ categoryId);
}else {
return categories;
}
}
// adding mapping for POST/customer i.e. insert a customer
#PostMapping("/categories")
public Categories addCategories(#RequestBody Categories theCategories) { //#RequestBody will convert JSON to JAVA object
// just to make things clear... always set id to 0 when inserting new object
// so that it will be created instead of update
theCategories.setId(0);
service.saveCategories(theCategories);
return theCategories;
}
You might be thinking about the problem the wrong way. Instead of sending the image itself through the rest API, the HTML only needs the path to the image. You store the image in a directory, and you can pass the path to the image to your HTML. You could add a variable "imagePath" to Categories and the HTML could reference it in the tag
You can convert your images to base64:
byte[] fileContent = FileUtils.readFileToByteArray(new File(filePath));
String encodedString = Base64.getEncoder().encodeToString(fileContent);
and then send this property through your API. then in your client side you can use it like this:
<img src=json.encodedString />
Here json is an object which has been sent over API.
Before sending the encodedString you may appned at its beginning some things like below, to make it easier to display in front-end:
"data:image/png;base64,"
To display a base64 image in front-end you should use some thing like this:
<img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />
Read more:
https://www.baeldung.com/java-base64-image-string
How to display Base64 images in HTML?

Is it possible to embed images in exported html

I'm trying to use the JasperHtmlExporterBuilder to generate an HTML version of a report that has images. The two options that I seem to have are:
Use JasperHtmlExporterBuilder and .setImagesURI("image?image="); This method relies on the code living in some kind of web container (like tomcat) and generates IMG tags to grab images from the server.
Use setOutputImagesToDir option of JasperHtmlExporterBuilder and force the images to be outputted separately to a local directory on disk.
I was wondering whether there might be a 3rd option where the images are base64 encoded and put directly into the HTML that's generated.
This would be ideal for me as I'd really like to return one complete result that's entirely self-contained.
One way I can "hack" it would be to use option #2 from above, then iterate over the images that get outputted, read them in, convert to base64 and manually replace the src part of the generated HTML.
Update: Below is my actual implementation based on the "hack" I describe above. Would be nice to do this better - but the code below is doing what I need (thought not very memory friendly).
public String toHtmlString() throws IOException, DRException {
File tempFile = Files.createTempFile("tempInvoiceHTML", "").toFile();
Path tempDir = Files.createTempDirectory("");
FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
JasperHtmlExporterBuilder htmlExporter = export.htmlExporter(fileOutputStream).setImagesURI("");
htmlExporter.setOutputImagesToDir(true);
htmlExporter.setImagesDirName(tempDir.toUri().getPath());
htmlExporter.setUsingImagesToAlign(false);
reportBuilder.toHtml(htmlExporter);
String html = new String(Files.readAllBytes(Paths.get(tempFile.toURI())));
for (Path path : Files.list(Paths.get(tempDir.toUri().getPath())).collect(Collectors.toList())) {
String fileName = path.getFileName().toString();
byte[] encode = Base64.encode(FileUtils.readFileToByteArray(path.toFile()));
html = html.replaceAll(fileName, "data:image/png;base64,"+ new String(encode));
}
return html;
}
Is there a better way to do this?
Thanks!

How to properly upload and service an image with Google Cloud Storage?

I've been stuck on this particular problem for a few days now without any success so I think it's time to reach out.
I have a form in a jsp which is part of a Google App Engine web-app, running with Struts2. My use case is that this form should be used to upload a "Tile" to my back-end storage. The form contains text fields, checkboxes and a file field, which will be used to upload an image which represents the Tile (for context, the Tile is for use in a game).
The text/boolean fields will be objectified into a "Tile" Entity and stored in Google Datastore, which is currently functional and works as intended, and the image file will be uploaded to Google Cloud storage and persisted in a bucket. However, my problem lies in the image upload.
I've tried several approaches without success, but the closest I have come is using the Storage.Objects resource to upload a stream to the store. I currently use Spring to amalgamate the form contents into a "Tile" bean, which contains all the fields, including the image file (the file is currently stored as a com.google.appengine.api.datastore.Blob, which belongs to a different API, and could actually be the cause of the problem, but I can't seem to find a Storage alternative).
Upon submission, this tile object is passed to a DAO by my action, the Blob is extracted, and the Tile (without the image blob) is persisted to the Datastore. This part works fine. I then extract the bytes from the image Blob and construct an input stream around them and output this stream to Storage.
public void storeTileImageToStorage(Blob imageData, String fileName) throws FileNotFoundException, IOException, GeneralSecurityException {
ByteArrayInputStream bis = new ByteArrayInputStream(imageData.getBytes());
uploadStreamToStorage(fileName, "image/png", bis, bucketName);
}
public static void uploadStreamToStorage(
String name, String contentType, InputStream stream, String bucketName)
throws IOException, GeneralSecurityException
{
InputStreamContent contentStream = new InputStreamContent(contentType, stream);
StorageObject objectMetadata = new StorageObject()
// Set the destination object name
.setName(name).setContentType(contentType);
// Do the insert
Storage client = getStorageService();
Storage.Objects.Insert insertRequest = client.objects().insert(
bucketName, objectMetadata, contentStream);
insertRequest.execute();
}
This works in some respects, as a new Object with correct name (and file-size) is created in the bucket. However, when I try to open the image using the web client I am greeted with a small white box, rather than the actual image (see below). Any attempts to service the image programmatically also fail
EDIT: As requested, the code I use to retrieve the image. Although I do not believe this is relevant, as the "white box" occurs when I click on the file within the cloud storage web client itself, not when I try and service the image programatically.
EDIT 2: Looking at this code again, I realise this will not work, as the .get() and cast to Blob will not work as I intend to. But regardless the servicing code is not my problem at the moment, the format of the file itself in Storage is my problem as of current.
public Blob retrieveTileImageFromStorage(String tileName) throws IOException, GeneralSecurityException {
StorageObject object = getObjectFromStorageBucket(bucketName, tileName);
Blob image = (Blob)object.get(tileName);
return image;
}
public static StorageObject getObjectFromStorageBucket(String bucketName, String objectName)
throws IOException, GeneralSecurityException {
Storage client = getStorageService();
Storage.Objects.Get get = client.objects().get(bucketName, objectName);
StorageObject object = get.execute();
return object;
}
I assume there will be a solution to this, and I will have made a silly mistake, as the file size is correct, implying the upload did work. I'm just having a problem viewing the file as an image.
Could anyone shed any light on the situation?
Thanks in advance.

Amazon rest call via android

I would like to perform rest calls to Amazon API from Android.
Amazon demands that all ws calls will be authenticated using HMAC signatures (Hash-based Message Authentication Code).
I'm missing a similar object to Apache Base64 object to sign my request.
Is there a simple way to do that in Android, or even better is there an Android client for Amazon web service (Product Advertising API).
You should be able to just include the Apache Base64 package in your project.
See this: http://www.delaytolerant.com/android-http-managing-base64-with-apache-commons-codec/
Or if there are any Java based Amazon clients, have you tried including those jars in your Android project?
Apparently the link above is now dead. Here's the contents of the page from Google's cache:
This post continues on programming
HTTP within Android. In the following,
I’ll show how to manage Base64 coded
content in Android and how to render
an image on WebView from a String that
we encoded.
First, the tool to use is commons
codec package from Apache. The
documentation can be found here. The
source is available here. You can just
include the source of the package to
your project, it is all Android
compatible.
The commons codec package has also
convenient method for Base64 decoding,
String imageString = "";
try {
FileInputStream fin = openFileInput("camera.jpg");
int jpeg_size = fin.available();
byte[] imagedata = new byte[jpeg_size];
fin.read(imagedata);
byte[] encodedData = Base64.encodeBase64(imagedata);
imageString = new String(encodedData);
final String mimetype = "text/html";
final String encoding = "UTF-8";
// replace below [ with html "<" and ] similarly ] with ">"
String html = "[html][body][center][img height=\"200\" width=\"200\"
src=\"data:image/jpeg;base64,"+imageString+"\"/][/center][/body][/html]";
mWebView.loadData(html, mimetype, encoding);
} catch (Exception e) {
e.printStackTrace();
}
There is also convenient Base64
decoding functionality in the package,
which can be used for example, to
decode Base64 encoded content in MIME
messages, which were covered in
previous post.
Make sure to encode the result as a url (signature = URLEncoder.encode(signature);) or you any end up in some misfortunes

Categories

Resources