create mp4 from pictures and mp3 java using xuggler - java

Im trying to combine a list of pictures to an mp4 movie with adding an mp3 file.
The length of the movie the user can choose either the length of the mp3 file or choose it manual.
And if the user chooses manual (length!=mp3 file length) the mp3 file should be cut or looped.
No it works with the pictures but without sound :(
private void convertImageToVideo() {
IMediaWriter writer = ToolFactory.makeWriter(outputFilename);
long delay = videotime / PicPathList.size();
long milliseconds = 0;
//adds Pictures to the mp4 stream
for (int i = 0; i < PicPathList.size(); i++) {
BufferedImage bi;
try {
bi = ImageIO.read(new File(PicPathList.get(i)));
bi = Tools.prepareForEncoding(bi);
int width=bi.getWidth();
int height=bi.getHeight();
if(width%2==1){
width++;
}
if(height%2==1){
height++;
}
if (i == 0) {
writer.addVideoStream(0, 0, ID.CODEC_ID_H264, width, height);
}
//debug
// System.out.println(PicPathList.get(i) + ", bi:" + bi.getWidth() + "x"
// + bi.getHeight() + ", ms:" + milliseconds);
writer.encodeVideo(0, bi, milliseconds, TimeUnit.MILLISECONDS);
milliseconds += delay;
} catch (IOException e) {
e.printStackTrace();
System.out.println("Error");
}
}
writer.close();
//at this part Im trying to combine the further generated mp4 file with the mp3 file
String inputVideoFilePath = outputFilename;
String inputAudioFilePath = this.musicFile.getAbsolutePath();
String outputVideoFilePath = "outputFilename";
IMediaWriter mWriter = ToolFactory.makeWriter(outputVideoFilePath);
IContainer containerVideo = IContainer.make();
IContainer containerAudio = IContainer.make();
// check files are readable
containerVideo.open(inputVideoFilePath, IContainer.Type.READ, null);
containerAudio.open(inputAudioFilePath, IContainer.Type.READ, null);
// read video file and create stream
IStreamCoder coderVideo = containerVideo.getStream(0).getStreamCoder();
IPacket packetvideo = IPacket.make();
int width = coderVideo.getWidth();
int height = coderVideo.getHeight();
// read audio file and create stream
IStreamCoder coderAudio = containerAudio.getStream(0).getStreamCoder();
IPacket packetaudio = IPacket.make();
mWriter.addAudioStream(1, 0,coderAudio.getCodecID(), coderAudio.getChannels(), coderAudio.getSampleRate());
mWriter.addVideoStream(0, 0, width, height);
while (containerVideo.readNextPacket(packetvideo) >= 0) {
containerAudio.readNextPacket(packetaudio);
// video packet
IVideoPicture picture = IVideoPicture.make(coderVideo.getPixelType(), width, height);
coderVideo.decodeVideo(picture, packetvideo, 0);
if (picture.isComplete())
mWriter.encodeVideo(0, picture);
// audio packet
IAudioSamples samples = IAudioSamples.make(512, coderAudio.getChannels(), IAudioSamples.Format.FMT_S32);
coderAudio.decodeAudio(samples, packetaudio, 0);
if (samples.isComplete())
mWriter.encodeAudio(1, samples);
}
coderAudio.close();
coderVideo.close();
containerAudio.close();
containerVideo.close();
mWriter.close();
}

I answered this question here which it is a complete answer.
JAVA - Xuggler - Play video while combining an MP3 audio file and a MP4 movie

You may use another jar file to merge your video and audio. Please notice this is not the right way to do it, but I didn't have any choice and time to dig into Xuggler codes.
I hope it works for you, too.
package MP4;
/**
*
* #author Pasban
*/
import com.coremedia.iso.boxes.Container;
import com.googlecode.mp4parser.authoring.Movie;
import com.googlecode.mp4parser.authoring.Track;
import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder;
import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class MuxMp4 {
public static void merge(String audio, String video, String output) throws IOException {
Movie countVideo = MovieCreator.build(video);
Movie countAudioEnglish = MovieCreator.build(audio);
Track audioTrackEnglish = countAudioEnglish.getTracks().get(0);
audioTrackEnglish.getTrackMetaData().setLanguage("eng");
countVideo.addTrack(audioTrackEnglish);
Container out = new DefaultMp4Builder().build(countVideo);
FileOutputStream fos = new FileOutputStream(new File(output));
out.writeContainer(fos.getChannel());
fos.close();
}
}
Check the MP4Parser sample codes for more information.
It is nice to mention that both of your files should be mp4. So you need to convert your mp3 to mp4 as well. and your video should not contain any sound, which in your case it does not.
AS I mentioned earlier, this in not the right way to do the job done.

Related

Youtube doesn't accept the mp4 I generate with javacv from an mp3 and a jpeg

Youtube doesn't accept the mp4 I generatewith javacv from an mp3 and a jpeg
I am using the youtube java api to upload this and no exception is thrown while uploading. An error which I pasted below occurs when only when I go to the youtube site. Either to see the uploaded video or to upload the video by hand.
The mp4 file is 00:59 in length and 506 kb in size so I don't thing that should be an issue.
This is the code:
public static void MergeMp3Mp4JavaCv(String path2ImageFile,String path2AudioFile, String path2OutputFile) throws IOException
{
IplImage ipl = cvLoadImage(path2ImageFile);
int height = ipl.height();
int width = ipl.width();
if(height%2!=0) height = height+1;
if(width%2!=0) width = width+1;
OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(path2OutputFile,width,height);
FrameGrabber audioFileGrabber = new FFmpegFrameGrabber(path2AudioFile);
try
{
audioFileGrabber.start();
recorder.setFrameRate(1);
recorder.setVideoBitrate(audioFileGrabber.getAudioBitrate());
recorder.setFormat("mp4");
recorder.setAudioChannels(1);
recorder.start();
recorder.record(grabberConverter.convert(ipl));
Frame frame = null;
while ((frame = audioFileGrabber.grabFrame())!=null)
{
recorder.record(frame);
}
recorder.stop();
audioFileGrabber.stop();
}
catch (org.bytedeco.javacv.FrameRecorder.Exception e){
e.printStackTrace();
}
}
Youtube says:
The video has failed to process. Please make sure you are uploading a
supported file type.
Edit: the file plays flawlessly in windows media player
Edit 2:
I checked out
https://support.google.com/youtube/answer/1722171?hl=en
Audio codec: AAC-LC
Channels: Stereo or Stereo + 5.1
Sample rate 96khz or 48khz
Video codec: H.264
Progressive scan (no interlacing)
High Profile
2 consecutive B frames
Closed GOP. GOP of half the frame rate.
CABAC
Variable bitrate. No bitrate limit required, though we offer recommended bit rates below for reference
Chroma subsampling: 4:2:0
I tried
recorder.setAudioCodec(avcodec.AV_CODEC_ID_H264 );
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
Tried a lot of other video codecs as well, but nothing works.
Does anyone know what I am doing wrong?
I eventually managed to get it working like this
public static void MergeMp3AndJpegIntoMp4(String path2ImageFile,String path2AudioFile, String path2OutputFile) throws IOException
{
IplImage ipl = cvLoadImage(path2ImageFile);
int height = ipl.height();
int width = ipl.width();
if(height%2!=0) height = height+1;
if(width%2!=0) width = width+1;
OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(path2OutputFile,width,height);
FrameGrabber audioFileGrabber = new FFmpegFrameGrabber(path2AudioFile);
try
{
audioFileGrabber.start();
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264 );//AV_CODEC_ID_VORBIS
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);//AV_CODEC_ID_MP3 //AV_CODEC_ID_AAC
recorder.setFormat("mp4");
recorder.setAudioChannels(2);
recorder.start();
Frame frame = null;
while ((frame = audioFileGrabber.grabFrame())!=null)
{ recorder.record(grabberConverter.convert(ipl));
recorder.record(frame);
}
recorder.stop();
audioFileGrabber.stop();
}
catch (org.bytedeco.javacv.FrameRecorder.Exception e){
e.printStackTrace();
throw e;
}
}

How to add watermark on video using mp4parser in android?

I had successfully convert recorded video into "out.h264" format and also audio into ".AAC" format using mp4parser. Now I want to implement "watermark image" on my recorded video. Is this possible with mp4parser to add watermark on video? I have checked GPUimages too. But there is no way to add effect on video, Its' example shows effect for only Images. So my question is How can I add watermark on video?
Below is my code for audio video :
File sdCard = Environment.getExternalStorageDirectory();
IsoFile isoFile = new IsoFile(videosPath);
TrackBox trackBox = (TrackBox) Path.getPath(isoFile, "/moov/trak/mdia/minf/stbl/stsd/avc1/../../../../../");
SampleList sl = new SampleList(trackBox);
File out = new File(sdCard + "/out.h264");
if (out.exists()) {
out.delete();
}
FileChannel fc = new RandomAccessFile(out, "rw").getChannel();
ByteBuffer separator = ByteBuffer.wrap(new byte[] { 0, 0, 0, 1 });
fc.write((ByteBuffer) separator.rewind());
// Write SPS
fc.write(ByteBuffer.wrap(((AvcConfigurationBox) Path.getPath(trackBox, "mdia/minf/stbl/stsd/avc1/avcC")).getSequenceParameterSets().get(0)));
// Warning:
// There might be more than one SPS (I've never seen that but it is possible)
fc.write((ByteBuffer) separator.rewind());
// Write PPS
fc.write(ByteBuffer.wrap(((AvcConfigurationBox) Path.getPath(trackBox, "mdia/minf/stbl/stsd/avc1/avcC")).getPictureParameterSets().get(0)));
// Warning:
// There might be more than one PPS (I've never seen that but it is possible)
int lengthSize = ((AvcConfigurationBox) Path.getPath(trackBox, "mdia/minf/stbl/stsd/avc1/avcC")).getLengthSizeMinusOne() + 1;
for (Sample sample : sl) {
ByteBuffer bb = sample.asByteBuffer();
while (bb.remaining() > 0) {
int length = (int) IsoTypeReaderVariable.read(bb, lengthSize);
fc.write((ByteBuffer) separator.rewind());
fc.write((ByteBuffer) bb.slice().limit(length));
bb.position(bb.position() + length);
}
}
fc.close();
Log.e(TAG, "Converted Path: " + out.getAbsolutePath() + " Start Time Convert: " + new Date());
H264TrackImpl h264Track = new H264TrackImpl(new FileDataSourceImpl(out.getAbsoluteFile()));
AACTrackImpl aacTrack = new AACTrackImpl(new FileDataSourceImpl(audioPath));
CroppedTrack aacTrackShort = new CroppedTrack(aacTrack, 1, aacTrack.getSamples().size());
// MP3TrackImpl accTrackImpl = new MP3TrackImpl(new FileDataSourceImpl(audioPath));
Movie movie = new Movie();
movie.addTrack(h264Track);
movie.addTrack(aacTrackShort);
Container mp4file = new DefaultMp4Builder().build(movie);
File output = new File(sdCard + "/output_KanAK.mp4");
if (output.exists()) {
output.delete();
}
#SuppressWarnings("resource")
FileChannel fc1 = new RandomAccessFile(output, "rw").getChannel();
mp4file.writeContainer(fc1);
fc1.close();
Bitmap largeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.velfee);
gpuImage.saveToPictures(largeIcon, output, 100, new OnPictureSavedListener() {
#Override
public void onPictureSaved(Uri uri) {
// TODO Auto-generated method stub
Log.e(TAG, "Picture save Uri");
GPUImageDifferenceBlendFilter filter;
filter.setBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher));
}
});
Any help would be appreciated!! Thanks in advance.
You can use a String as a watermark using the subtitle example in the github page. Set the limits to your own but ofcourse you wont be able to use image.

How to get Audio for encoding using Xuggler

I'm writing an application that records the screen and audio. While the screen recording works perfectly, I'm having difficulty in getting the raw audio using the JDK libraries. Here's the code:
try {
// Now, we're going to loop
long startTime = System.nanoTime();
System.out.println("Encoding Image.....");
while (!Thread.currentThread().isInterrupted()) {
// take the screen shot
BufferedImage screen = robot.createScreenCapture(screenBounds);
// convert to the right image type
BufferedImage bgrScreen = convertToType(screen,
BufferedImage.TYPE_3BYTE_BGR);
// encode the image
writer.encodeVideo(0, bgrScreen, System.nanoTime()
- startTime, TimeUnit.NANOSECONDS);
/* Need to get audio here and then encode using xuggler. Something like
WaveData wd = new WaveData();
TargetDataLine line;
AudioInputStream aus = new AudioInputStream(line);
short[] samples = getSourceSamples();
writer.encodeAudio(0, samples); */
if (timeCreation < 10) {
timeCreation = getGMTTime();
}
// sleep for framerate milliseconds
try {
Thread.sleep((long) (1000 / FRAME_RATE.getDouble()));
} catch (Exception ex) {
System.err.println("stopping....");
break;
}
}
// Finally we tell the writer to close and write the trailer if
// needed
} finally {
writer.close();
}
This page has some pseudo code like
while(haveMoreAudio())
{
short[] samples = getSourceSamples();
writer.encodeAudio(0, samples);
}
but what exactly should I do for getSourceSamples()?
Also, a bonus question - is it possible to choose from multiple microphones in this approach?
See also:
Xuggler encoding and muxing
Try this:
// Pick a format. Need 16 bits, the rest can be set to anything
// It is better to enumerate the formats that the system supports, because getLine() can error out with any particular format
AudioFormat audioFormat = new AudioFormat(44100.0F, 16, 2, true, false);
// Get default TargetDataLine with that format
DataLine.Info dataLineInfo = new DataLine.Info( TargetDataLine.class, audioFormat );
TargetDataLine line = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
// Open and start capturing audio
line.open(audioFormat, line.getBufferSize());
line.start();
while (true) {
// read as raw bytes
byte[] audioBytes = new byte[ line.getBufferSize() / 2 ]; // best size?
int numBytesRead = 0;
numBytesRead = line.read(audioBytes, 0, audioBytes.length);
// convert to signed shorts representing samples
int numSamplesRead = numBytesRead / 2;
short[] audioSamples = new short[ numSamplesRead ];
if (format.isBigEndian()) {
for (int i = 0; i < numSamplesRead; i++) {
audioSamples[i] = (short)((audioBytes[2*i] << 8) | audioBytes[2*i + 1]);
}
}
else {
for (int i = 0; i < numSamplesRead; i++) {
audioSamples[i] = (short)((audioBytes[2*i + 1] << 8) | audioBytes[2*i]);
}
}
// use audioSamples in Xuggler etc
}
To pick a microphone, you'd probably have to do this:
Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
// Look through and select a mixer here, different mixers should be different inputs
int selectedMixerIndex = 0;
Mixer mixer = AudioSystem.getMixer(mixerInfo[ selectedMixerIndex ]);
TargetDataLine line = (TargetDataLine) mixer.getLine(dataLineInfo);
I think it's possible that multiple microphones will show up in one mixer as different source data lines. In that case you'd have to open them and call dataLine.getControl(FloatControl.Type.MASTER_GAIN).setValue( volume ); to turn them on and off.
See:
WaveData.java
Sound wave from TargetDataLine
How to set volume of a SourceDataLine in Java

Splitting a multipage TIFF image into individual images (Java)

Been tearing my hair on this one.
How do I split a multipage / multilayer TIFF image into several individual images?
Demo image available here.
(Would prefer a pure Java (i.e. non-native) solution. Doesn't matter if the solution relies on commercial libraries.)
You can use the Java Advanced Imaging library, JAI, to split a mutlipage TIFF, by using an ImageReader:
ImageInputStream is = ImageIO.createImageInputStream(new File(pathToImage));
if (is == null || is.length() == 0){
// handle error
}
Iterator<ImageReader> iterator = ImageIO.getImageReaders(is);
if (iterator == null || !iterator.hasNext()) {
throw new IOException("Image file format not supported by ImageIO: " + pathToImage);
}
// We are just looking for the first reader compatible:
ImageReader reader = (ImageReader) iterator.next();
iterator = null;
reader.setInput(is);
Then you can get the number of pages:
nbPages = reader.getNumImages(true);
and read pages separatly:
reader.read(numPage)
A fast but non JAVA solution is tiffsplit. It is part of the libtiff library.
An example command to split a tiff file in all it's layers would be:
tiffsplit image.tif
The manpage says it all:
NAME
tiffsplit - split a multi-image TIFF into single-image TIFF files
SYNOPSIS
tiffsplit src.tif [ prefix ]
DESCRIPTION
tiffsplit takes a multi-directory (page) TIFF file and creates one or more single-directory (page) TIFF files
from it. The output files are given names created by concatenating a prefix, a lexically ordered suffix in the
range [aaa-zzz], the suffix .tif (e.g. xaaa.tif, xaab.tif, xzzz.tif). If a prefix is not specified on the
command line, the default prefix of x is used.
OPTIONS
None.
BUGS
Only a select set of ‘‘known tags’’ is copied when splitting.
SEE ALSO
tiffcp(1), tiffinfo(1), libtiff(3TIFF)
Libtiff library home page: http://www.remotesensing.org/libtiff/
I used this sample above with a tiff plugin i found called imageio-tiff.
Maven dependency:
<dependency>
<groupId>com.tomgibara.imageio</groupId>
<artifactId>imageio-tiff</artifactId>
<version>1.0</version>
</dependency>
I was able to get the buffered images from a tiff resource:
Resource img3 = new ClassPathResource(TIFF4);
ImageInputStream is = ImageIO.createImageInputStream(img3.getInputStream());
Iterator<ImageReader> iterator = ImageIO.getImageReaders(is);
if (iterator == null || !iterator.hasNext()) {
throw new IOException("Image file format not supported by ImageIO: ");
}
// We are just looking for the first reader compatible:
ImageReader reader = (ImageReader) iterator.next();
iterator = null;
reader.setInput(is);
int nbPages = reader.getNumImages(true);
LOGGER.info("No. of pages for tiff file is {}", nbPages);
BufferedImage image1 = reader.read(0);
BufferedImage image2 = reader.read(1);
BufferedImage image3 = reader.read(2);
But then i found another project called apache commons imaging
Maven dependency:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-imaging</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
In one line you can get the buffered images:
List<BufferedImage> bufferedImages = Imaging.getAllBufferedImages(img3.getInputStream(), TIFF4);
LOGGER.info("No. of pages for tiff file is {} using apache commons imaging", bufferedImages.size());
Then write to file sample:
final Map<String, Object> params = new HashMap<String, Object>();
// set optional parameters if you like
params.put(ImagingConstants.PARAM_KEY_COMPRESSION, new Integer(TiffConstants.TIFF_COMPRESSION_CCITT_GROUP_4));
int i = 0;
for (Iterator<BufferedImage> iterator1 = bufferedImages.iterator(); iterator1.hasNext(); i++) {
BufferedImage bufferedImage = iterator1.next();
LOGGER.info("Image type {}", bufferedImage.getType());
File outFile = new File("C:\\tmp" + File.separator + "shane" + i + ".tiff");
Imaging.writeImage(bufferedImage, outFile, ImageFormats.TIFF, params);
}
Actually testing performance, apache is alot slower...
Or use an old version of iText, which is alot faster:
private ByteArrayOutputStream convertTiffToPdf(InputStream imageStream) throws IOException, DocumentException {
Image image;
ByteArrayOutputStream out = new ByteArrayOutputStream();
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, out);
writer.setStrictImageSequence(true);
document.open();
RandomAccessFileOrArray ra = new RandomAccessFileOrArray(imageStream);
int pages = TiffImage.getNumberOfPages(ra);
for (int i = 1; i <= pages; i++) {
image = TiffImage.getTiffImage(ra, i);
image.setAbsolutePosition(0, 0);
image.scaleToFit(PageSize.A4.getWidth(), PageSize.A4.getHeight());
document.setPageSize(PageSize.A4);
document.newPage();
document.add(image);
}
document.close();
out.flush();
return out;
}
This is how I did it with ImageIO:
public List<BufferedImage> extractImages(InputStream fileInput) throws Exception {
List<BufferedImage> extractedImages = new ArrayList<BufferedImage>();
try (ImageInputStream iis = ImageIO.createImageInputStream(fileInput)) {
ImageReader reader = getTiffImageReader();
reader.setInput(iis);
int pages = reader.getNumImages(true);
for (int imageIndex = 0; imageIndex < pages; imageIndex++) {
BufferedImage bufferedImage = reader.read(imageIndex);
extractedImages.add(bufferedImage);
}
}
return extractedImages;
}
private ImageReader getTiffImageReader() {
Iterator<ImageReader> imageReaders = ImageIO.getImageReadersByFormatName("TIFF");
if (!imageReaders.hasNext()) {
throw new UnsupportedOperationException("No TIFF Reader found!");
}
return imageReaders.next();
}
I took part of the code from this blog.
All the proposed solutions require reading the multipage image page by page and write the pages back to new TIFF images. Unless you want to save the individual pages to different image format, there is no point in decoding the image. Given the special structure of the TIFF image, you can split a multipage TIFF into single TIFF images without decoding.
The TIFF tweaking tool (part of a larger image related library - "icafe" I am using is written from scratch with pure Java. It can delete pages, insert pages, retain certain pages, split pages from a multiple page TIFF as well as merge multipage TIFF images into one TIFF image without decompressing them.
After trying with the TIFF tweaking tool, I am able to split the image into 3 pages: page#0, page#1, and page#2
NOTE1: The original demo image for some reason contains "incorrect" StripByteCounts value 1 which is not the actual bytes needed for the images strip. It turns out that the image data are not compressed, so the actual bytes for each image strip could be figured out through other TIFF field values such as RowsPerStrip, SamplesPerPixel, ImageWidth, etc.
NOTE2: Since in splitting the TIFF, the above mentioned library doesn't need to decode and re-encode the image. So it's fast and it also keeps the original encoding and additional metadata of each pages!
It works to set the compression to default param.setCompression(32946);.
public static void doitJAI(String mutitiff) throws IOException {
FileSeekableStream ss = new FileSeekableStream(mutitiff);
ImageDecoder dec = ImageCodec.createImageDecoder("tiff", ss, null);
int count = dec.getNumPages();
TIFFEncodeParam param = new TIFFEncodeParam();
param.setCompression(32946);
param.setLittleEndian(false); // Intel
System.out.println("This TIF has " + count + " image(s)");
for (int i = 0; i < count; i++) {
RenderedImage page = dec.decodeAsRenderedImage(i);
File f = new File("D:/PSN/SCB/SCAN/bin/Debug/Temps/test/single_" + i + ".tif");
System.out.println("Saving " + f.getCanonicalPath());
ParameterBlock pb = new ParameterBlock();
pb.addSource(page);
pb.add(f.toString());
pb.add("tiff");
pb.add(param);
RenderedOp r = JAI.create("filestore",pb);
r.dispose();
}
}
The below code will convert the multiple tiff into individual's and produces an Excel sheet with list of tiff images.
You need to create a folder in the C drive and place your TIFF images into it then run this code.
Need to import the below jars.
1.sun-as-jsr88-dm-4.0-sources
2./sun-jai_codec
3.sun-jai_core
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import java.io.IOException;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import com.sun.media.jai.codec.FileSeekableStream;
import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageDecoder;
import com.sun.media.jai.codec.TIFFEncodeParam;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import javax.swing.JOptionPane;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
public class TIFF_Sepreator {
File folder = new File("C:/FAX/");
public static void infoBox(String infoMessage, String titleBar)
{
JOptionPane.showMessageDialog(null, infoMessage, "InfoBox: " + titleBar, JOptionPane.INFORMATION_MESSAGE);
}
public void splitting() throws IOException, AWTException
{
boolean FinalFAXFolder = (new File("C:/Final_FAX")).mkdirs();
File[] listOfFiles = folder.listFiles();
String dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime());
try{
if (listOfFiles.length > 0)
{
for(int file=0; file<listOfFiles.length; file++)
{
System.out.println(listOfFiles[file]);
FileSeekableStream ss = new FileSeekableStream(listOfFiles[file]);
ImageDecoder dec = ImageCodec.createImageDecoder("tiff", ss, null);
int count = dec.getNumPages();
TIFFEncodeParam param = new TIFFEncodeParam();
param.setCompression(TIFFEncodeParam.COMPRESSION_GROUP4);
param.setLittleEndian(false); // Intel
System.out.println("This TIF has " + count + " image(s)");
for (int i = 0; i < count; i++)
{
RenderedImage page = dec.decodeAsRenderedImage(i);
File f = new File("C:\\Final_FAX\\"+dateFormat+ file +i + ".tif");
System.out.println("Saving " + f.getCanonicalPath());
ParameterBlock pb = new ParameterBlock();
pb.addSource(page);
pb.add(f.toString());
pb.add("tiff");
pb.add(param);
RenderedOp r = JAI.create("filestore",pb);
r.dispose();
}
}
TIFF_Sepreator.infoBox("Find your splitted TIFF images in location 'C:/Final_FAX/' " , "Done :)");
WriteListOFFilesIntoExcel();
}
else
{
TIFF_Sepreator.infoBox("No files was found in location 'C:/FAX/' " , "Empty folder");
System.out.println("No files found");
}
}
catch(Exception e)
{
TIFF_Sepreator.infoBox("Unabe to run due to this error: " +e , "Error");
System.out.println("Error: "+e);
}
}
public void WriteListOFFilesIntoExcel(){
File[] listOfFiles = folder.listFiles();
ArrayList<File> files = new ArrayList<File>(Arrays.asList(folder.listFiles()));
try {
String filename = "C:/Final_FAX/List_Of_Fax_Files.xls" ;
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("FirstSheet");
for (int file=0; file<listOfFiles.length; file++) {
System.out.println(listOfFiles[file]);
Row r = sheet.createRow(file);
r.createCell(0).setCellValue(files.get(file).toString());
}
FileOutputStream fileOut = new FileOutputStream(filename);
workbook.write(fileOut);
fileOut.close();
System.out.println("Your excel file has been generated!");
}
catch(Exception ex){
TIFF_Sepreator.infoBox("Unabe to run due to this error: " +ex , "Error");
System.out.println("Error: "+ex);
}
}
public static void main(String[] args) throws IOException, AWTException {
new TIFF_Sepreator().splitting();
}
}

How do I convert images between CMYK and RGB in ColdFusion (Java)?

I have a need to convert images from CMYK to RGB - not necessarily back again, but hey, if it can be done...
With the release of ColdFusion 8, we got the CFImage tag, but it doesn't support this conversion; and nor does Image.cfc, or Alagad's Image Component.
However, it should be possible in Java; which we can leverage through CF. For example, here's how you might create a Java thread to sleep a process:
<cfset jthread = createObject("java", "java.lang.Thread")/>
<cfset jthread.sleep(5000)/>
I would guess a similar method could be used to leverage java to do this image conversion, but not being a Java developer, I don't have a clue where to start. Can anyone lend a hand here?
A very simple formula for converting from CMYK to RGB ignoring all color profiles is:
R = ( (255-C)*(255-K) ) / 255;
G = ( (255-M)*(255-K) ) / 255;
B = ( (255-Y)*(255-K) ) / 255;
This code requires CMYK values to be in rage of 0-255. If you have 0 to 100 or 0.0 to 1.0 you'll have to convert the values.
Hope this will get you started.
As for the java and ColdFusion interfacing, I'm sorry, but I have no idea how to do that.
I use the Java ImageIO libraries (https://jai-imageio.dev.java.net). They aren't perfect, but can be simple and get the job done. As far as converting from CMYK to RGB, here is the best I have been able to come up with.
Download and install the ImageIO JARs and native libraries for your platform. The native libraries are essential. Without them the ImageIO JAR files will not be able to detect the CMYK images. Originally, I was under the impression that the native libraries would improve performance but was not required for any functionality. I was wrong.
The only other thing that I noticed is that the converted RGB images are sometimes much lighter than the CMYK images. If anyone knows how to solve that problem, I would be appreciative.
Below is some code to convert a CMYK image into an RGB image of any supported format.
Thank you,
Randy Stegbauer
package cmyk;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.apache.commons.lang.StringUtils;
public class Main
{
/**
* Creates new RGB images from all the CMYK images passed
* in on the command line.
* The new filename generated is, for example "GIF_original_filename.gif".
*
*/
public static void main(String[] args)
{
for (int ii = 0; ii < args.length; ii++)
{
String filename = args[ii];
boolean cmyk = isCMYK(filename);
System.out.println(cmyk + ": " + filename);
if (cmyk)
{
try
{
String rgbFile = cmyk2rgb(filename);
System.out.println(isCMYK(rgbFile) + ": " + rgbFile);
}
catch (IOException e)
{
System.out.println(e.getMessage());
}
}
}
}
/**
* If 'filename' is a CMYK file, then convert the image into RGB,
* store it into a JPEG file, and return the new filename.
*
* #param filename
*/
private static String cmyk2rgb(String filename) throws IOException
{
// Change this format into any ImageIO supported format.
String format = "gif";
File imageFile = new File(filename);
String rgbFilename = filename;
BufferedImage image = ImageIO.read(imageFile);
if (image != null)
{
int colorSpaceType = image.getColorModel().getColorSpace().getType();
if (colorSpaceType == ColorSpace.TYPE_CMYK)
{
BufferedImage rgbImage =
new BufferedImage(
image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
ColorConvertOp op = new ColorConvertOp(null);
op.filter(image, rgbImage);
rgbFilename = changeExtension(imageFile.getName(), format);
rgbFilename = new File(imageFile.getParent(), format + "_" + rgbFilename).getPath();
ImageIO.write(rgbImage, format, new File(rgbFilename));
}
}
return rgbFilename;
}
/**
* Change the extension of 'filename' to 'newExtension'.
*
* #param filename
* #param newExtension
* #return filename with new extension
*/
private static String changeExtension(String filename, String newExtension)
{
String result = filename;
if (filename != null && newExtension != null && newExtension.length() != 0);
{
int dot = filename.lastIndexOf('.');
if (dot != -1)
{
result = filename.substring(0, dot) + '.' + newExtension;
}
}
return result;
}
private static boolean isCMYK(String filename)
{
boolean result = false;
BufferedImage img = null;
try
{
img = ImageIO.read(new File(filename));
}
catch (IOException e)
{
System.out.println(e.getMessage() + ": " + filename);
}
if (img != null)
{
int colorSpaceType = img.getColorModel().getColorSpace().getType();
result = colorSpaceType == ColorSpace.TYPE_CMYK;
}
return result;
}
}
The tag cfx_image may be of use to you. I haven't used it in a while but I remember it had a ton of features.
Alternatively, you might be able to script a windows app such as Irfanview (via commandline using cfexecute) to process images.
Hope that helps
I know that this question is old, but I still encounter problems with CMYK images & ColdFusion. However, I just read a CMYK JPEG image using ColdFusion 10 and resaved it. The saved image was able to to be read using ColdFusion 9 (which is only capable of reading RGB JPEGs.) I'm not sure if this conversion is intentional or not and I don't currently have any way of identifying whether the source image's color profile is CMYK or not as the saved color profile still appears to be the same.
<cfset imgData = ImageRead(expandPath("./CMYK_image.jpg"))>
<cfset ImageWrite(imgData, expandPath("./Saved_image.jpg"))>

Categories