Java variable issue with Tesseract OCR - java

I used this code in Spring Boot Java to create an OCR application.
#Controller
public class FileUploadController {
#RequestMapping("/")
public String index() {
return "upload";
}
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public RedirectView singleFileUpload(#RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes, Model model) throws IOException, TesseractException {
byte[] bytes = file.getBytes();
Path path = Paths.get("C:/Users/ashwi/Downloads/javaocr9/src/main/resources/static" + file.getOriginalFilename());
Files.write(path, bytes);
File convFile = convert(file);
Tesseract tesseract = new Tesseract();
tesseract.setDatapath("C:/Users/ashwi/Downloads/ocr-tess4j-example-master/ocr-tess4j-example-master/tessdata");
String text = tesseract.doOCR(file2);
redirectAttributes.addFlashAttribute("file", file);
redirectAttributes.addFlashAttribute("text", text);
return new RedirectView("result");
}
#RequestMapping("/result")
public String result() {
return "result";
}
public static File convert(MultipartFile file) throws IOException {
File convFile = new File(file.getOriginalFilename());
convFile.createNewFile();
FileOutputStream fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();
return convFile;
}
}
However, there appears to be an error at:
String text = tesseract.doOCR(file2);
In visual studio code, I got an error saying: "file2 cannot be resolved to a variable".
Any ideas? I am new to Java and am having trouble fixing it.
I got this version of code from: https://stackabuse.com/tesseract-simple-java-optical-character-recognition/

Related

How to solve ERROR java.nio.file.AccessDeniedException: D:\workspace_intellij_forKiri\Kiri\server\kiri\temp\28004d6bc31cfiles.png

I am going to convert MultipartFile to File and upload it to S3 bucket.
However, when running the test, an error occurs in the process of converting MultipartFile to File.
ERROR : java.nio.file.AccessDeniedException: D:\workspace_intellij_forKiri\Kiri\server\kiri\temp\8b28a2f2-7276-4036
multipartFile.transferTo(file);
Please advise if there is anything I am missing.
The spring boot version is 2.7.7 version.
Test code
#WithAccount("creamyyyy")
#DisplayName("image save test")
#Test
public void createImageTest() throws Exception {
//given
String filename = "files";
String contentType = "png";
MockMultipartFile image1 = new MockMultipartFile(
filename,
filename + "." + contentType,
"image/png",
filename.getBytes());
//when
//then
this.mockMvc.perform( //== ERROR!!!
MockMvcRequestBuilders
.multipart("/api/posts/image")
.file(image1)
.contentType(MediaType.MULTIPART_FORM_DATA)
.characterEncoding("UTF-8")
)
.andDo(print())
.andExpect(status().isOk());
}
ImageService Code
// FileSave
public List<ImageResDto> addFile(List<MultipartFile> multipartFiles) throws IOException {
List<ImageResDto> imageResDtoList = new ArrayList<>();
/**
* <ImageResDto>
* private Long image_id;
* private String imgUrl;
*/
String absolutePath = new File("").getAbsolutePath() + File.separator + "temp";
for (MultipartFile multipartFile : multipartFiles) {
String contentType = multipartFile.getContentType();
if(ObjectUtils.isEmpty(contentType)) {
throw new RuntimeException("FILE TYPE NOT FOUND");
} else if(!verifyContentType(contentType)){
throw new RuntimeException("FILE TYPE NOT FOUND");
}
}
for (MultipartFile multipartFile : multipartFiles) {
String filename = UUID.randomUUID() + multipartFile.getOriginalFilename();
// save in local
String fullFilePath = absolutePath + File.separator + filename;
System.out.println("fullFilePath = " + fullFilePath);
File file = new File(fullFilePath);
if(!file.exists()) { file.mkdirs(); }
multipartFile.transferTo(file); // ERROR ... OTL
file.createNewFile();
// S3 upload
amazonS3.putObject(
new PutObjectRequest(bucket, filename, file)
.withCannedAcl(CannedAccessControlList.PublicRead)
);
String imgUrl = amazonS3.getUrl(bucket, filename).toString();
Image newImage = Image.builder()
.filename(filename)
.filepath(filename)
.imgUrl(imgUrl)
.build();
imageRepository.save(newImage);
ImageResDto imageResDto = ImageResDto.of(newImage);
imageResDtoList.add(imageResDto);
file.delete(); // local file delete
}
return imageResDtoList;
}
ImageController Code
#PostMapping(value = "/api/posts/image", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity createImage(#RequestPart(value = "files") List<MultipartFile> multipartFiles) throws IOException {
System.out.println("ImageController Runnnn");
// get member
PrincipalDetails principalDetails = (PrincipalDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Member member = principalDetails.getMember();
List<ImageResDto> imageResDtoList = imageService.addFile(multipartFiles);
return new ResponseEntity(imageResDtoList, HttpStatus.CREATED);
}
I tried to specify a separate route using Path, but I failed.
// Error ..java.nio.file.AccessDeniedException => Path
// multipartFile -> File
Path path = Paths.get(fullFilePath).toAbsolutePath();
multipartFile.transferTo(path.toFile());
Files.createFile(path);
What is incomprehensible is that when tested using PostMan, the file is normally uploaded to the S3 bucket.
Please tell me if I applied anything wrong.

How to write JUnit Test for uploading Image in Amazon S3 in Spring Boot

I have a problem about writing a test to upload Image in Amazon s3 in Spring Boot.
I tried to write its test method but I got an error shown below.
How can I fix it?
Here is the method of Rest controller
#RestController
#RequestMapping("/api/v1/bookImage")
#RequiredArgsConstructor
public class ImageRestController {
#PostMapping
public ResponseEntity<String> uploadImage(#RequestParam("bookId") Long bookId, #RequestParam("file") MultipartFile file) {
final String uploadImg = imageStoreService.uploadImg(convert(file), bookId);
service.saveImage(bookId, uploadImg);
return ResponseEntity.ok(uploadImg);
}
private File convert(final MultipartFile multipartFile) {
// convert multipartFile to File
File file = new File(Objects.requireNonNull(multipartFile.getOriginalFilename()));
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(multipartFile.getBytes());
return file;
} catch (IOException e) {
throw new RuntimeException("Failed to convert multipartFile to File");
}
}
Here is the method of imageService.
public String uploadImg(File file, Long bookId) {
s3amazon.putObject(BUCKET_NAME, bookId.toString(), file);
return baseUrl + bookId;
}
Here is the test method shown below.
#Test
void itShouldGetImagePath_WhenValidBookIdAndFile() throws Exception{
// given - precondition or setup
String bookId = "1";
String imagePath = "amazon-imagepath";
String baseUrl = String.format(imagePath + "/%s", bookId);
Long bookIdValue = 1L;
MockMultipartFile uploadFile = new MockMultipartFile("file", new byte[1]);
// when - action or the behaviour that we are going test
when(imageStoreService.uploadImg(convert(uploadFile), bookIdValue)).thenReturn(baseUrl); -> HERE IS THE ERROR
// then - verify the output
mvc.perform(MockMvcRequestBuilders.multipart("/api/v1/bookImage")
.file(uploadFile)
.param("bookId", bookId))
.andExpect((ResultMatcher) content().string(baseUrl))
.andExpect(status().isOk());
}
private File convert(final MultipartFile multipartFile) {
// convert multipartFile to File
File file = new File(Objects.requireNonNull(multipartFile.getOriginalFilename()));
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(multipartFile.getBytes());
return file;
} catch (IOException e) {
throw new RuntimeException("Failed to convert multipartFile to File");
}
}
Here is the error : Failed to convert multipartFile to File (java.lang.RuntimeException: Failed to convert multipartFile to Filejava.io.FileNotFoundException: )
How can I fix it?
Here is the solution shown below.
#Test
void itShouldGetImagePath_WhenValidBookIdAndFile() throws Exception{
// given - precondition or setup
String bookId = "1";
String imagePath = "amazon-imagepath";
String baseUrl = String.format(imagePath + "/%s", bookId);
Long bookIdValue = 1L;
String fileName = "sample.png";
MockMultipartFile uploadFile =
new MockMultipartFile("file", fileName, "image/png", "Some bytes".getBytes());
// when - action or the behaviour that we are going test
when(imageStoreService.uploadImg(convert(uploadFile), bookIdValue)).thenReturn(baseUrl);
doNothing().when(bookSaveService).saveImage(bookIdValue,baseUrl);
// then - verify the output
mvc.perform(MockMvcRequestBuilders.multipart("/api/v1/bookImage")
.file(uploadFile)
.param("bookId", bookId))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$").value(baseUrl))
.andExpect(content().string(baseUrl));
}

how to get the path of project directory in spring?

i am trying to upload an image file with my jsp form. i am successfully being able to upload it but not in the directory that i want.
#Controller
public class ProductController {
private Path path;
#Autowired
private ProductService productService;
#RequestMapping(value="/admin/addProduct")
public String addProduct() {
return "addProduct";
}
#RequestMapping(value="/admin/addProduct", method= RequestMethod.POST)
public String addNewProduct(#ModelAttribute("product") Product products,
BindingResult result,HttpServletRequest request,#RequestParam("prodImage")
MultipartFile file) {
System.out.println("adding product");
System.out.println(path);
if(result.hasErrors()) {
return "addProduct";
}
productService.saveProduct(products);
MultipartFile productImage = file;
String rootDir = request.getSession().getServletContext().getRealPath("/");
System.out.println(rootDir);
path = Paths.get(rootDir+"//WEB-INF//resources//images//"+products.getId()+
".jpg");
System.out.println("path :"+path);
if(productImage != null && !productImage.isEmpty()) {
System.out.println("inside not null product image");
try {
productImage.transferTo(new File(path.toString()));
System.out.println("after saving image");
}catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException("product image saving failed",ex);
}
}
return "redirect:/admin/productInventory";
}
#RequestMapping("/admin/productInventory")
public String productInventory() {
return "productInventory";
}
}
this is the current dir location being printed:-
/mnt/7A46BE1454633621/eclipseworkspace/ecommerce/target/ecommerce/
path :/mnt/7A46BE1454633621/eclipseworkspace/ecommerce/target/ecommerce/
WEB-INF/resources/images/5.jpg
i want to upload my image inside WEB-INF/resources/images. how can i do that?
you need to check class path is set or not then you can use classpath:/WEB-INF/resources/images/ path to image upload and download.
You can use the below code to upload image to your images folder. Here multipartFile is the reference of MultipartFile interface
InputStream inputStream = multipartFile.getInputStream();
byte[] buf = new byte[1024];
String path = servletContext.getRealPath("WEB-INF/resources/images");
File file = new File(path);
String basePath = file.getCanonicalPath();
String fileName = multipartFile.getOriginalFilename();
FileOutputStream fileOutputStream = new FileOutputStream(basePath+"/"+fileName);
int numRead = 0;
while ((numRead = inputStream.read(buf)) >= 0) {
fileOutputStream.write(buf, 0, numRead);
}
inputStream.close();
fileOutputStream.close();
Also to get servletContext reference autowire ServeletContext interface like this:
#Autowired
ServletContext servletContext;

Unit testing an endpoint with #RequestBody

So I am getting a 400 for my HTTP response code when it should be 200. I am passing in a byte[] object to the endpoint but it doesn't seem to be adding the content-type correctly? Any suggestions?
#RequestMapping(value = "/test", method = RequestMethod.POST, consumes = "application/octet-stream")
public ResponseEntity<String> receiveCompressedBinary(#RequestHeader String site, #RequestHeader String customer,
#RequestHeader String table, #RequestBody byte[] binary, #RequestHeader String loadStatus) {
if(binary.length < maxFileSize) {
return new ResponseEntity<String>(HttpStatus.OK);
}
else{
return new ResponseEntity<String>(HttpStatus.PAYLOAD_TOO_LARGE);
}
}
My test:
#Test
public void testUploadCompressedBinaryInitialRunning() throws Exception{
File file = new File("src/test/resources/testFile.txt");
String site = "site";
String customer = "customer";
String table = "table";
String loadStatus = "INITIALRUNNING";
this.mockMvc.perform(post("/test").header("site",site).param("customer",customer).
param("table", table).content(compress(file)).param("loadStatus",loadStatus)
.with(user("user"))).andExpect(status().isOk());
this.mockMvc.perform(post("/uploadCompressedBinary")).andDo(print()).andExpect(status().isOk());
}
Compress method:
public static byte[] compress(File file) throws IOException {
if (file.length() == 0) {
return null;
}
FileInputStream fileInputStream = null;
byte[] fileInBytes = new byte[(int)file.length()];
try {
//convert file into array of bytes
fileInputStream = new FileInputStream(file);
fileInputStream.read(fileInBytes);
fileInputStream.close();
} catch (IOException e) {
System.out.println("Exception whilst compressing the file: " + e.getMessage());
}
ByteArrayOutputStream obj = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(obj);
gzip.write(fileInBytes);
gzip.close();
return obj.toByteArray();
}
UPDATE: Got past it, rather than .param, I should be using .header
It does not look like you are setting the content type when you are posting.
Try
this.mockMvc.perform(post("/test").header("site",site).param("customer",customer).
param("table", table).content(compress(file)).contentType("application/octet-stream").param("loadStatus",loadStatus)
.with(user("user"))).andExpect(status().isOk());

Is produces of #RequestMapping sensitive to order of values?

This question is based on this question.
With provided comments, i had written three different tests to validate properly set content-types.
#Test
public void testGetImageJpg_ShouldSucceed() throws Exception {
File testImage = new File(TestConstants.TEST_IMAGE_JPG);
byte[] expectedBytes = IOUtils.toByteArray(new FileInputStream(testImage));
when(service.getImage(anyString(), anyString())).thenReturn(testImage);
mockMvc.perform(get("/getImage/id/bla.jpg").sessionAttrs(session))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.IMAGE_JPEG))
.andExpect(content().bytes(expectedBytes));
}
#Test
public void testGetImagePng_ShouldSucceed() throws Exception {
File testImage = new File(TestConstants.TEST_IMAGE_PNG);
byte[] expectedBytes = IOUtils.toByteArray(new FileInputStream(testImage));
when(service.getImage(anyString(), anyString())).thenReturn(testImage);
mockMvc.perform(get("/getImage/id/bla.png").sessionAttrs(session))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.IMAGE_PNG))
.andExpect(content().bytes(expectedBytes));
}
#Test
public void testGetImageGif_ShouldSucceed() throws Exception {
File testImage = new File(TestConstants.TEST_IMAGE_GIF);
byte[] expectedBytes = IOUtils.toByteArray(new FileInputStream(testImage));
when(service.getImage(anyString(), anyString())).thenReturn(testImage);
mockMvc.perform(get("/getImage/id/bla.gif").sessionAttrs(session))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.IMAGE_GIF))
.andExpect(content().bytes(expectedBytes));
}
This is my controller, where all tests succeed:
#RequestMapping(value="/getImage/{id}/{path}", produces = {"image/png","image/jpeg","image/gif"})
#ResponseBody
byte[] getImage(#PathVariable("id") String id,
#PathVariable("path") String path) throws ImageNotFoundException {
File imageFile = service.getImage(id, path);
InputStream in;
try {
in = new FileInputStream(imageFile);
return IOUtils.toByteArray(in);
} catch (IOException e) {
throw new ImageNotFoundException();
}
}
But when I change the order of produces value to
produces = {"image/jpeg","image/png","image/gif"}
The test for png is failing:
java.lang.AssertionError: Content type expected:<image/png> but was:<image/jpeg>
Im little confused, that changing the order of produces values leads to different results.
Does anyone observed this, is it a bug or did I miss something ?

Categories