dragon66 / icafe Goto Github PK
View Code? Open in Web Editor NEWJava library for reading, writing, converting and manipulating images and metadata
License: Eclipse Public License 1.0
Java library for reading, writing, converting and manipulating images and metadata
License: Eclipse Public License 1.0
most open source lib support is not good.
Context:
I wrote a program using icafe that splits one large multipage TIFF into several smaller multipage TIFFs. I wanted to do this without decompressing the TIFFs (they mostly use type 6 JPEG compression), so I used the copyPages function from the TIFFTweaker class.
The problem:
The program worked, but the files it created were exactly twice the size they were supposed to be. After much debugging I discovered that for each page in the TIFF, there were two sets of identical image data in the file. However, only one set of image data was actually referenced by an IFD, so the extra set did not show up in any TIFF viewer or analyzer.
The solution:
I tracked down the problem to the copyPageData function. I realized that if the TIFF file uses type 6 JPEG compression, the image data is copied twice. I solved this by adding two conditionals:
This problem was tricky to debug, so I figured I would post it here for reference. My solution is not the most elegant, but it works. If you have any questions or suggestions just let me know.
For ease of use, it would be better to use an EnumMap as the internal container for NativeMetadata. We can then create and populate the NativeMetadata inside an ImageReader and retrieve the EnumMap and query it by enum key specific for that kind of image. - may need to create enum type for GIF specific native metadata. For JPEG, use Marker as key and for PNG, use ChunkType instead. TIFF may not need NativeMetadata at all.
Original question from Prashant Bandewar
Jan 22 at 4:18 AM
I am using the icafe 1.1 version for one of my projects. The requirement is to split a multi-page tiff file and based on a criteria split it either into single or two page tif files. The splitimages method in TiffTweaker was not useful as it will split only into single pages so I modified the TiffTweaker and gave a custom implementation for it. I created the below method to call the TiffTweaker methods.
This works fine in case of smaller files but as the size of the source tiff file grows, the performance slows down considerably. Based on the analysis so far, it seems like the FileCacheRandomAccessInputStream takes most of the processing time and while reading it is always starting from the start of the source file and creating a cache file everytime from the start of source.
For e.g. if I have 10 page source file, and it needs to be split in 5 files of two page each, during iteration 1, cache file is created with first two pages(based on the list of IFD's which contains data only for the pages to be copied either one or two objects in list) but next time, the cache is created with 4 pages and next time with 6 pages. Because of this when the input file is large, the processing slows down considerably once the number of records cross a certain threshold based system configuration.
Any help from your side would be greatly appreciated.
java
public static void createCMoDTiff(FileInputStream fin,
FileOutputStream fout, List list) throws IOException {
long startTiffSplit=System.currentTimeMillis();
RandomAccessInputStream rin = new FileCacheRandomAccessInputStream(fin,102400);
RandomAccessOutputStream rout = new FileCacheRandomAccessOutputStream(fout,102400);
// Copy the header information as is
copyHeader(rin, rout);
// copy the pages described in IFDs from inputfile to output file
copyPages(list, TIFFWriter.FIRST_WRITE_OFFSET, rin, rout);
int firstIFDOffset = list.get(0).getStartOffset();
// correct the pointer to 1st page
writeToStream(rout, firstIFDOffset);
rin.close();
rout.close();
long endTiffSplit = System.currentTimeMillis();
LOGGER.info("Time taken in ViaTiffTweaker : "+(endTiffSplit-startTiffSplit));
}
The current implementation requires that a specific API be used if this library is included. It would be ideal to become a provider of the standard API like: https://github.com/jai-imageio/jai-imageio-core
Adobe XMP is considered a better metadata format and it support customized metadata entries. Currently "icafe" can extract, show, and insert XMP data as a whole in XML DOM format. It's better to have some API or else to manage the namespace, schema, etc. Adobe already has an API XMPCore. I am investigating more about the XMP format and may take a look at the XMPCore too.
At the time to get a page of a PDF and apply convertToImage ( BufferedImage.TYPE_INT_RGB , 300) did not save the color image in grayscale only
I'm currently using this library (1.1-SNAPSHOT) to:
I am running this in a spring-boot application and exposing the above functionality as a web service.
I've just encountered an issue, that I realise has been here all along - just unbeknown to me.
The issue occurs when concurrent requests (on separate threads) come through where both threads are writing out a tiff at the same time.
The scenario :
java.lang.ArrayIndexOutOfBoundsException: 10104
at com.icafe4j.image.compression.packbits.Packbits.packbits(Unknown Source)
at com.icafe4j.image.writer.TIFFWriter.compressSample(Unknown Source)
at com.icafe4j.image.writer.TIFFWriter.writeTrueColor(Unknown Source)
at com.icafe4j.image.writer.TIFFWriter.writePageData(Unknown Source)
at com.icafe4j.image.writer.TIFFWriter.writePage(Unknown Source)
at com.icafe4j.image.tiff.TIFFTweaker.writePage(Unknown Source)
at au.com.reecefenwick.imaging.rest.ImageController.manipulateImage(ImageController.java:147)
at au.com.reecefenwick.imaging.rest.ImageController.drawOnImage(ImageController.java:99)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:968)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:870)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:844)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:237)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
...
java.lang.ArrayIndexOutOfBoundsException
java.lang.ArrayIndexOutOfBoundsException
java.lang.ArrayIndexOutOfBoundsException
java.lang.ArrayIndexOutOfBoundsException
java.lang.ArrayIndexOutOfBoundsException
java.lang.ArrayIndexOutOfBoundsException
java.lang.ArrayIndexOutOfBoundsException
This is my code where I am reading an image from a HTTP stream, modifying the BufferedImage and writing out as a TIFF to the HTTP response.
Don't read too much into the "CustomTiffTweaker", I created that after I discovered this issue to override the behaviour of a particular method, more on that below.
private void manipulateImage(InputStream tiffInputStream,
HttpServletResponse response, String contentType) throws IOException {
ImageReader reader = splitMultiPageImage(tiffInputStream);
int totalPages = reader.getNumImages(true);
// Prepare tiff writer
TIFFWriter writer = new TIFFWriter();
writer.setImageParam(buildTiffOptions()[0]);
List<IFD> ifds = new ArrayList<IFD>();
RandomAccessOutputStream rout = new MemoryCacheRandomAccessOutputStream(response.getOutputStream());
int writeOffset = CustomTiffTweaker.prepareForWrite(rout);
String ext = ".tif";
response.setHeader("Content-Disposition", "attachment; filename=" + UUID.randomUUID() + ext);
response.setContentType(contentType);
for (int i = 0; i < totalPages; i++ ) {
BufferedImage bufferedImage = reader.read(i);
bufferedImage = imageManipulationService.drawOnImage(bufferedImage);
writeOffset = CustomTiffTweaker.writePage(bufferedImage, rout, ifds, writeOffset, writer);
bufferedImage = null;
}
CustomTiffTweaker.finishWrite(rout, ifds);
rout.close();
response.flushBuffer();
}
The exception is being thrown here in this class
My attempt to debug/workaround
I created CustomTiffTweaker.java
as referenced above, extending the TIFFTweaker - overriding the writePage() method and implementing a retry mechanism.
public class CustomTiffTweaker extends TIFFTweaker {
private final Logger log = LoggerFactory.getLogger(CustomTiffTweaker.class);
public static int writePage(BufferedImage image, RandomAccessOutputStream rout, List<IFD> ifds,
int writeOffset, TIFFWriter writer) throws IOException {
int count = 0;
int maxTries = 15;
while(true) {
try {
// break out of loop, or return, on success
writeOffset = writer.writePage(image, 0, 0, rout, writeOffset);
ifds.add(writer.getIFD());
return writeOffset;
} catch (Exception e) {
// handle exception
System.out.println("Retrying");
if (++count == maxTries) throw new RuntimeException("");
}
}
}
}
I managed to stop the issue from happening by doing the above, which is obviously very dodgy :)
What really sucks about this issue is that is being silently consumed, with a stacktrace going to stdout.
Has anyone had similar experiences when using this library in a multi-threaded environment?
Hi
What are the plans to push this to regular maven so that it can be used by not using the SNAPSHOT mentioned in the README.md.
I understand that you have the last call on this but we are making use of this library but can not use oss.sonatype.org/content/repositories/snapshots
. Just wondering what are the plans to push this to regular maven? I believe the library works fantastically
How to covert tif to jpeg use icafe? Thanks..
Hi,
i am unable to use icafe in my project because it runs on java 1.5 version and icafe jar file is compiled with version 1.7.
can i get icafe jar file compile in 1.5.
Hello, it's me again. Metadata.insertXMP()
produces an exception for certain images.
Problem images:
https://github.com/sinedsem/test/blob/master/1.jpg
https://github.com/sinedsem/test/blob/master/2.jpg
https://github.com/sinedsem/test/blob/master/3.jpg
https://github.com/sinedsem/test/blob/master/4.jpg
Code to reproduce issue:
File source = new File("1.jpg");
File destination = new File("result.jpg");
XMPMeta xmpMeta = new XMPMetaImpl();
ByteArrayOutputStream xmpOut = new ByteArrayOutputStream();
XMPMetaFactory.serialize(xmpMeta, xmpOut);
FileInputStream is = new FileInputStream(source);
FileOutputStream os = new FileOutputStream(destination);
Metadata.insertXMP(is, os, xmpOut.toString("utf-8"));
is.close();
os.close();
StackTrace (Sorry, no line numbers)
java.lang.NegativeArraySizeException: null
at com.icafe4j.image.jpeg.JPEGTweaker.insertXMP(Unknown Source)
at com.icafe4j.image.jpeg.JPEGTweaker.insertXMP(Unknown Source)
at com.icafe4j.image.meta.Metadata.insertXMP(Unknown Source)
Hi.. You know what happens, when about 400 users actively use your library? They find bugs...
Here I have an image: https://github.com/sinedsem/test/blob/master/5.jpg . Poor image, what happened with you? One evil user removed all metadata from you using XnView.
Now when I try to read metadata with icafe Metadata.readMetadata("5.jpg");
it throws IllegalArgumentException
java.lang.IllegalArgumentException: Copy range out of array bounds
at com.icafe4j.util.ArrayUtils.subArray(Unknown Source)
at com.icafe4j.image.meta.adobe.IRB.read(Unknown Source)
at com.icafe4j.image.meta.Metadata.ensureDataRead(Unknown Source)
at com.icafe4j.image.meta.adobe.IRB.get8BIM(Unknown Source)
at com.icafe4j.image.jpeg.JPEGTweaker.readMetadata(Unknown Source)
at com.icafe4j.image.meta.Metadata.readMetadata(Unknown Source)
at com.icafe4j.image.meta.Metadata.readMetadata(Unknown Source)
at com.icafe4j.image.meta.Metadata.readMetadata(Unknown Source)
Can this be related to #38 ? I still think that subArray
method should allow copying the full length.
In progress - coming to the final part of decoding Huffman code and reconstruct the YCbCr sample data. Currently, reading support for JPEG is still going through Java ImageIO.
I am getting this exception when call insertExif from JPEGTweaker
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableMap.put(Unknown Source)
at com.icafe4j.image.tiff.IFD.addChild(Unknown Source)
at com.icafe4j.image.jpeg.JPEGTweaker.insertExif(Unknown Source)
at arpm.image.ImageAdjuster.addMetadata(ImageAdjuster.java:215)
at arpm.image.ImageAdjuster.main(ImageAdjuster.java:363)
Hey,
I need to make a split of a Multi TIFF, but later move the Single TIFF image to other folder, even the Multi TIFF. But the problem is tha tthe lib doesnt release some of the Single TIFF and the Multi TIFF.
I check the source, but I cant find any reason.
Thanks.
Your project is very perfect. But it seems that it does not support the export of interlaced GIF, PNG and JPG images. Or maybe I didn't find it.
Finish TIFF reader
This issue appears not always. Basically, it depends on image file. Some files are ok, others procudes this issue. Example of a problem file: https://github.com/sinedsem/test/blob/master/6.jpg
ArrayList<IPTCDataSet> iptcDataSets = new ArrayList<>();
iptcDataSets.add(new IPTCDataSet(IPTCApplicationTag.OBJECT_NAME, "I have ©"));
FileInputStream is = new FileInputStream("6.jpg");
FileOutputStream os = new FileOutputStream("result.jpg");
Metadata.insertIPTC(is, os, iptcDataSets, true);
is.close();
os.close();
Result: I have В©
.
P. S. I really wish to prodive you more information when opening issues, but debugger goes crazy every time I try to step into icafe methods. No idea why.
Hi,
Any example of how to write info into XMP ?
Found this but going no where...
JpegXMP
Thanks
There have been questions and requirements regarding inserting more than one metadata types into the image in one operation (method call) to avoid creating intermediate temporay files. This is the attempt to accomplish that purpose. Initially, we are not going to support update to the metadata. The old metadata of the same type as the inserted one will be replaced by the new one.
I am attempting to convert a 10mb PDF (40 pages) to a multi-page TIFF
I have the following code:
I'm using org.apache.pdfbox to process the PDF.
public void savePdfAsTiff(PDDocument pdf, OutputStream outputStream) throws IOException {
BufferedImage[] images = new BufferedImage[pdf.getNumberOfPages()];
for (int i = 0; i < images.length; i++) {
PDPage page = (PDPage) pdf.getDocumentCatalog().getAllPages()
.get(i);
BufferedImage image;
try {
image = page.convertToImage(BufferedImage.TYPE_INT_RGB, 288); //works
images[i] = image;
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
RandomAccessOutputStream rout = new MemoryCacheRandomAccessOutputStream(outputStream);
ImageParam.ImageParamBuilder builder = ImageParam.getBuilder();
ImageParam[] param = new ImageParam[1];
TIFFOptions tiffOptions = new TIFFOptions();
tiffOptions.setTiffCompression(TiffFieldEnum.Compression.CCITTFAX4);
builder.imageOptions(tiffOptions);
builder.colorType(ImageColorType.FULL_COLOR).ditherMatrix(DitherMatrix.getBayer8x8Diag()).applyDither(true).ditherMethod(DitherMethod.BAYER);
param[0] = builder.build();
TIFFTweaker.writeMultipageTIFF(rout, param, images);
rout.close();
}
This works quite well on smaller images.
But obviously buffering everything in memory will only get you so far, in my case I run out of heap space.
Have you got any examples to create the multipage tiff more efficiently?
Hello
I want to add 2 new features to the TiffTweaker module:
I had some questions:
Hello @dragon66!
It's me again. I would like to thank you again for your library. I respect that you support it and keep it free and open source.
However, I can see that you are not so passionate about icafe. I don't see new features are being implemented or enhancement issues are being closed. As a developer I can fully understand you.
But I don't want this project to die, so I think I will fork it and will try to implement some features that I need and possibly add some improvements. And here I need your help:
Please say if you find this appropriate.
Thanks,
Denis,
StockHelper developer.
P. S. You icafe certainly deserve to be built with Maven. This will be the first improvement I am going to add.
Hi,
In your document, you have said, " To save memory, we can also write animated GIF frame by frame!"
Can you provide an example? I'm getting Java Heap Space error due to all the images are written out in a single shot.
GIFTweaker.writeAnimatedGIF(images, delays, fout);
Thanks
Kangs
This isn't about iCafe per se.
I would like to add some extra information to the bottom of issue #29 (which is closed) to help others who come across it, like I did.
If you can add this (or open it for a short amount of time, so I can include one more comment) I'll add the following at the very bottom:
I would like to leave a comment for anyone else who might find this while searching for a fix to their problems (like I did). The built in concurrency mechanism that dragon66 is talking about is the synchronize() block. Info about it can be found [here](https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html).
Current testing classes inside the cafe.test package do not provide any other ways then exception to indicate whether or not the tested unit is working. Migrating to JUnit test will solve the problem.
In order to reduce memory consumption, there should be a way to write animated GIF frames one at a time. Currently, "icafe" write them from an array of BufferedImages which could be a problem if lots of frames are involved or the frames are large.
Hi: The code used to work correctly, no changes made, but now I receive the below errors, can you please check:
[ERROR] [19,22] package cafe.image.gif does not exist
[ERROR] [20,17] package cafe.util does not exist
[49,32] cannot find symbol
symbol: variable FileUtils
location: class com.invitae.framework.utils.CommonUtil
[ERROR] cannot find symbol
symbol: variable GIFTweaker
location: class com.invitae.framework.utils.CommonUtil
In some occasions like we want to modify an existing animated GIF, it would be ideal if we could grab the frame as GIFFrame. Then we can modify the properties such as the delay of it and save the frames back as an animated GIF.
Add function to rotate JPEG lossslessly and lossily
Currently, the only quantization algorithm used is "popularity". It's quick and produces good result if combined with dither process. But sometimes, when better image quality is required, we need a better algorithm. We may not even need a dither process in this case.
Some people insert outlines in their JPEG images, which are named "Clipping path". There are a few articles about this, e. g. http://designus.sk/the-secret-path-of-jpg-images/
Here I have an example of image with clipping path: https://github.com/sinedsem/test/blob/master/clipping_path.jpg
In addition to clipping path, this image has one IPTC Keywords tag - keyword.
Let's say I want to remove this tag from image, but save clipping path info. Unfortunately, I can't do this.
When I call insertIPTC with update = true, clipping path is saved, but I can't delete tags, only add.
When I call with update = false, I see no way to preverve clipping path.
That's how I use it:
File source = new File("clipping_path.jpg");
File destination = new File("result.jpg");
FileInputStream is = new FileInputStream(source);
Map<MetadataType, Metadata> metadataMap = Metadata.readMetadata(is);
ArrayList<IPTCDataSet> iptcDataSets = new ArrayList<>();
// the following loop is needed to preserve all metadata but Keywords. Unfortunately, I can't retrieve clipping path from here.
if (metadataMap != null && metadataMap.get(MetadataType.IPTC) != null) {
IPTC iptc = (IPTC) metadataMap.get(MetadataType.IPTC);
for (Map.Entry<String, List<IPTCDataSet>> entry : iptc.getDataSets().entrySet()) {
if (!entry.getKey().equals(IPTCApplicationTag.KEY_WORDS.getName())) {
System.out.println(entry.getKey());
iptcDataSets.addAll(entry.getValue());
}
}
}
is = new FileInputStream(source);
FileOutputStream os = new FileOutputStream(destination);
Metadata.insertIPTC(is, os, iptcDataSets, true); // this can be true or false
is.close();
os.close();
Hi @dragon66! It's me again from stockhelper again =)
As usual, file : https://github.com/sinedsem/test/blob/master/7.jpg
Stack trace:
java.lang.RuntimeException: XMP data size exceededs JPEG segment size
at com.icafe4j.image.meta.jpeg.JpegXMP.write(Unknown Source)
at com.icafe4j.image.jpeg.JPEGTweaker.insertXMP(Unknown Source)
at com.icafe4j.image.jpeg.JPEGTweaker.insertXMP(Unknown Source)
at com.icafe4j.image.meta.Metadata.insertXMP(Unknown Source)
P. S. Please find another glass of beer in your PayPal wallet =)
Hi,
I want to read a jpeg from a servlet and can not find instructions on what jars to use. You have two main jars one 980kb and the other 2Mb so not sure why two and which to use and if there are more needed for compile and deploy.
Hi,
Will you support RAW images as well ? Nice if icafe can support LibRaw. LibRaw is a libraries for developer that support most of the RAW images out there and they do support Mac and Win. too bad, there's no JNI support for this library...
http://www.libraw.org/
Thanks
I spent a bit of time playing with demos but I have failed to produce 48bpp png.
Does icafe support it? Is there a plan to support writing deep color pngs?
Thanks.
Hi!
For easier consumption, it would be great if the Jar were hosted somewhere.
Maven central is the standard, but publishing to Bintray is much easier.
Anyway, some place where one could automatically retrieve the Jar via Maven, SBT, ... would be great!
Thanks
Martin
Hi,
I came across your icafe library yesterday, when I was looking for a library to handle animated gifs. I would like to use it in my project, but the scattered logging to System.out
is not too handy. I would expect a library to log via slf4j or logback, allowing it to seamlessly integrate with a bigger application. Do you have plans to change it? I am thinking about forking your project on github and making some changes.
On the other hand I am also writing this issue to get in touch with you and say big thanks for sharing this code!
Cheers,
Balazs
Currently, the MetadataType enum only supports common meta data types which could be found in more than one image/media formats - like EXIF, ICC_PROFILE, IPTC, PHOTOSHOP IRB, XMP etc. We need to add native metadata types as well.
How do you change the dpi of tif-file?
Currently TIFFReader has no support for CCITT Fax compression. This is a common format which we need to support.
Hi! I am getting an exception when loading a PNG that both OSX Preview, Photoshop and Chrome can load: https://cloud.githubusercontent.com/assets/4610874/11146632/46cbeaf4-8a10-11e5-8ead-696cab4fac82.png
My code:
InputStream stream = new URL("https://cloud.githubusercontent.com/assets/4610874/11146632/46cbeaf4-8a10-11e5-8ead-696cab4fac82.png").openStream();
new PNGReader().read(stream);
Stack trace:
Cause: java.io.EOFException:
at com.icafe4j.io.IOUtils.readFully(Unknown Source)
at com.icafe4j.io.IOUtils.readFully(Unknown Source)
at com.icafe4j.io.IOUtils.readIntMM(Unknown Source)
at com.icafe4j.io.IOUtils.readUnsignedIntMM(Unknown Source)
at com.icafe4j.image.reader.PNGReader.read(Unknown Source)
This was on version 1.1-SNAPSHOT.
Add scale (resize) Implementation following Chris Campbell's suggestions in "The Perils of Image.getScaledInstance() "
"
Hi,
this is the code.
JpegExif exif = new JpegExif();
exif.addImageField(TiffTag.WINDOWS_XP_TITLE, FieldType.BYTE, "".getBytes("UTF-16LE"));
it managed to modify Windows XP comments, subject but failed on Authors and Title.
Please note that, all this fields already contained info. Ijust wanted to modify the info.
Any ideas ?
Thanks
The Javadoc for class JPEGTweaker states for method insertXmp:
The standard part of the XMP must be a valid XMP with packet wrapper and, should already include the GUID for the ExtendedXMP in case of ExtendedXMP
Looking at the result and the source code, this seems to be incorrect. The tag xmpNote:HasExtendedXMP with the MD5 checksum is created by the function itself:
`
...
if(extendedXmp != null) { // We have ExtendedXMP
guid = StringUtils.generateMD5(extendedXmp);
NodeList descriptions = xmpDoc.getElementsByTagName("rdf:Description");
int length = descriptions.getLength();
if(length > 0) {
Element node = (Element)descriptions.item(length - 1);
node.setAttribute("xmlns:xmpNote", "http://ns.adobe.com/xmp/extension/");
node.setAttribute("xmpNote:HasExtendedXMP", guid);
}
}
`
It should be:
The standard part of the XMP must be a valid XMP with packet wrapper. In case of ExtendedXMP the required namespace and the tag xmpNote:HasExtendedXMP will be added.
By the way: Fantastic to have support for extended XMP in the library!
This tag is Adobe private TIFF tag with a structure similar to Photoshop Image Resource Block with building block 8BIM.
This library can compile the java 1.6?
I have a problem using classes as my contender this in java 1.6
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.