Corrupt Olympus Makernote Exif Directory - java
I'm trying to extract information from my photos via Java.
My camera, an Olympus E-510 saves all the pictures with a corrupt makernote directory. When I try to get the tags from the OlympusMakernoteDirectory, there are none. Each directory has one error which turns out to be an "Illegally sized directory" error.
Do I have any chance of somehow accessing the data in the directory? I wouldn't mind juggling bytes but I have no idea where to start :(
Currently working on a javascript only solution.
Will contribute it here in the next days:
https://github.com/redaktor/exiftool.js (it is just a fork for now)
Some Olympus Cameras seem to store their makernotes only in subIFDs.
I wouldn't mind juggling bytes but I have no idea where to start :(
start here :
this has a special meaning ::
0x3000: 'RawInfo',
0x4000: 'MainInfo',
they can be either pointers to SubIFDs or arrays
some cameras store the "root tags" in 0x4000 ...
{
0x2010: '_IFDpointer_Equipment', // (misleading name returns many things, e.g. serial)
0x2020: '_IFDpointer_CameraSettings',
0x2030: '_IFDpointer_RawDevelopment',
0x2031: '_IFDpointer_RawDevelopment2',
0x2040: '_IFDpointer_ImageProcessing',
0x2050: '_IFDpointer_FocusInfo',
0x0000: 'MakerNoteVersion',
0x0001: 'CameraSettings',
0x0003: 'CameraSettings',
0x0040: 'CompressedImageSize',
0x0081: 'PreviewImageData',
0x0088: 'PreviewImageStart',
0x0089: 'PreviewImageLength',
0x0100: 'ThumbnailImage',
0x0104: 'BodyFirmwareVersion',
0x0200: 'SpecialMode',
0x0201: 'Quality',
0x0202: 'Macro',
0x0203: 'BWMode',
0x0204: 'DigitalZoom',
0x0205: 'FocalPlaneDiagonal',
0x0206: 'LensDistortionParams',
0x0207: 'Olympus CameraType Values',
0x0208: 'Olympus TextInfo',
0x020b: 'EpsonImageWidth',
0x020c: 'EpsonImageHeight',
0x020d: 'EpsonSoftware',
0x0280: 'PreviewImage',
0x0300: 'PreCaptureFrames',
0x0301: 'WhiteBoard',
0x0302: 'OneTouchWB',
0x0303: 'WhiteBalanceBracket',
0x0304: 'WhiteBalanceBias',
0x0404: 'SerialNumber',
0x0405: 'Firmware',
0x0e00: 'PrintIM',
0x0f00: 'DataDump',
0x0f01: 'DataDump2',
0x0f04: 'ZoomedPreviewStart',
0x0f05: 'ZoomedPreviewLength',
0x0f06: 'ZoomedPreviewSize',
0x1000: 'ShutterSpeedValue',
0x1001: 'ISOValue',
0x1002: 'ApertureValue',
0x1003: 'BrightnessValue',
0x1004: 'FlashMode',
0x1006: 'ExposureCompensation',
0x1007: 'SensorTemperature',
0x1008: 'LensTemperature',
0x1009: 'LightCondition',
0x100a: 'FocusRange',
0x100b: 'FocusMode',
0x100c: 'ManualFocusDistance',
0x100d: 'ZoomStepCount',
0x100e: 'FocusStepCount',
0x100f: 'Sharpness',
0x1010: 'FlashChargeLevel',
0x1011: 'ColorMatrix',
0x1012: 'BlackLevel',
0x1013: 'ColorTemperatureBG?',
0x1014: 'ColorTemperatureRG?',
0x1017: 'RedBalance',
0x1018: 'BlueBalance',
0x1019: 'ColorMatrixNumber',
0x101a: 'SerialNumber',
0x101b: 'ExternalFlashAE1_0?',
0x101c: 'ExternalFlashAE2_0?',
0x101d: 'InternalFlashAE1_0?',
0x101e: 'InternalFlashAE2_0?',
0x101f: 'ExternalFlashAE1?',
0x1020: 'ExternalFlashAE2?',
0x1021: 'InternalFlashAE1?',
0x1022: 'InternalFlashAE2?',
0x1023: 'FlashExposureComp',
0x1024: 'InternalFlashTable',
0x1025: 'ExternalFlashGValue',
0x1026: 'ExternalFlashBounce',
0x1027: 'ExternalFlashZoom',
0x1028: 'ExternalFlashMode',
0x1029: 'Contrast',
0x102a: 'SharpnessFactor',
0x102b: 'ColorControl',
0x102c: 'ValidBits',
0x102d: 'CoringFilter',
0x102e: 'OlympusImageWidth',
0x102f: 'OlympusImageHeight',
0x1030: 'SceneDetect',
0x1031: 'SceneArea?',
0x1033: 'SceneDetectData?',
0x1034: 'CompressionRatio',
0x1035: 'PreviewImageValid',
0x1036: 'PreviewImageStart',
0x1037: 'PreviewImageLength',
0x1038: 'AFResult',
0x1039: 'CCDScanMode',
0x103a: 'NoiseReduction',
0x103b: 'FocusStepInfinity',
0x103c: 'FocusStepNear',
0x103d: 'LightValueCenter',
0x103e: 'LightValuePeriphery',
0x103f: 'FieldCount?'
}
_IFDpointer_Equipment: {
0x0000: 'EquipmentVersion',
// 0x0100: { ref: ' Olympus CameraType Values' }, // TODO
0x0101: 'SerialNumber',
0x0102: 'InternalSerialNumber',
0x0103: 'FocalPlaneDiagonal',
0x0104: 'BodyFirmwareVersion',
// 0x0201: { ref: ' Olympus LensType Values' }, // TODO
0x0202: 'LensSerialNumber',
0x0203: 'LensModel',
0x0204: 'LensFirmwareVersion',
0x0205: 'MaxApertureAtMinFocal',
0x0206: 'MaxApertureAtMaxFocal',
0x0207: 'MinFocalLength',
0x0208: 'MaxFocalLength',
0x020a: 'MaxAperture',
0x020b: 'LensProperties',
0x0301: 'Extender',
0x0302: 'ExtenderSerialNumber',
0x0303: 'ExtenderModel',
0x0304: 'ExtenderFirmwareVersion',
0x0403: 'ConversionLens',
0x1000: 'FlashType',
0x1002: 'FlashFirmwareVersion',
0x1003: 'FlashSerialNumber'
},
_IFDpointer_CameraSettings: {
0x0000: 'CameraSettingsVersion',
0x0100: 'PreviewImageValid',
0x0101: 'PreviewImageStart',
0x0102: 'PreviewImageLength',
0x0200: 'ExposureMode',
0x0201: 'AELock',
0x0203: 'ExposureShift',
0x0204: 'NDFilter',
0x0300: 'MacroMode',
0x0302: 'FocusProcess',
0x0303: 'AFSearch',
0x0304: 'AFAreas',
0x0305: 'AFPointSelected',
0x0306: 'AFFineTune',
0x0307: 'AFFineTuneAdj',
0x0401: 'FlashExposureComp',
0x0404: 'FlashControlMode',
0x0405: 'FlashIntensity',
0x0406: 'ManualFlashStrength',
0x0501: 'WhiteBalanceTemperature',
0x0502: 'WhiteBalanceBracket',
0x0503: 'CustomSaturation',
0x0504: 'ModifiedSaturation',
0x0505: 'ContrastSetting',
0x0506: 'SharpnessSetting',
0x0507: 'ColorSpace',
0x050a: 'NoiseReduction',
0x050b: 'DistortionCorrection',
0x050c: 'ShadingCompensation',
0x050d: 'CompressionFactor',
0x050f: 'Gradation',
0x0521: 'PictureModeSaturation',
0x0522: 'PictureModeHue?',
0x0523: 'PictureModeContrast',
0x0524: 'PictureModeSharpness',
0x0527: 'NoiseFilter',
0x052d: 'PictureModeEffect',
0x052e: 'ToneLevel',
0x0600: 'DriveMode',
0x0601: 'PanoramaMode',
0x0603: 'ImageQuality2',
0x0604: 'ImageStabilization',
0x0900: 'ManometerPressure',
0x0901: 'ManometerReading',
0x0902: 'ExtendedWBDetect',
0x0903: 'LevelGaugeRoll',
0x0904: 'LevelGaugePitch',
0x0908: 'DateTimeUTC'
},
_IFDpointer_RawDevelopment: {
0x0000: 'RawDevVersion',
0x0100: 'RawDevExposureBiasValue',
0x0101: 'RawDevWhiteBalanceValue',
0x0102: 'RawDevWBFineAdjustment',
0x0103: 'RawDevGrayPoint',
0x0104: 'RawDevSaturationEmphasis',
0x0105: 'RawDevMemoryColorEmphasis',
0x0106: 'RawDevContrastValue',
0x0107: 'RawDevSharpnessValue',
0x0108: 'RawDevColorSpace',
0x0109: 'RawDevEngine',
0x010a: 'RawDevNoiseReduction',
0x010b: 'RawDevEditStatus'
},
Related
How to fix "GetStatus Write RFID_API_UNKNOWN_ERROR data(x)- Field can Only Take Word values" Android RFID 8500 Zebra
I am trying to develop and application to read and write to RF tags. Reading is flawless, but I'm having issues with writing. Specifically the error "GetStatus Write RFID_API_UNKNOWN_ERROR data(x)- Field can Only Take Word values" I have tried reverse-engineering the Zebra RFID API Mobile by obtaining the .apk and decoding it, but the code is obfuscated and I am not able to decypher why that application's Write works and mine doesn't. I see the error in the https://www.ptsmobile.com/rfd8500/rfd8500-rfid-developer-guide.pdf at page 185, but I have no idea what's causing it. I've tried forcefully changing the writeData to Hex, before I realized that the API does that on its own, I've tried changing the Length of the writeData as well, but it just gets a null value. I'm so lost. public boolean WriteTag(String sourceEPC, long Password, MEMORY_BANK memory_bank, String targetData, int offset) { Log.d(TAG, "WriteTag " + targetData); try { TagData tagData = null; String tagId = sourceEPC; TagAccess tagAccess = new TagAccess(); tagAccess.getClass(); TagAccess.WriteAccessParams writeAccessParams = tagAccess.new WriteAccessParams(); String writeData = targetData; //write data in string writeAccessParams.setAccessPassword(Password); writeAccessParams.setMemoryBank(MEMORY_BANK.MEMORY_BANK_USER); writeAccessParams.setOffset(offset); // start writing from word offset 0 writeAccessParams.setWriteData(writeData); // set retries in case of partial write happens writeAccessParams.setWriteRetries(3); // data length in words System.out.println("length: " + writeData.length()/4); System.out.println("length: " + writeData.length()); writeAccessParams.setWriteDataLength(writeData.length()/4); // 5th parameter bPrefilter flag is true which means API will apply pre filter internally // 6th parameter should be true in case of changing EPC ID it self i.e. source and target both is EPC boolean useTIDfilter = memory_bank == MEMORY_BANK.MEMORY_BANK_EPC; reader.Actions.TagAccess.writeWait(tagId, writeAccessParams, null, tagData, true, useTIDfilter); } catch (InvalidUsageException e) { System.out.println("INVALID USAGE EXCEPTION: " + e.getInfo()); e.printStackTrace(); return false; } catch (OperationFailureException e) { //System.out.println("OPERATION FAILURE EXCEPTION"); System.out.println("OPERATION FAILURE EXCEPTION: " + e.getResults().toString()); e.printStackTrace(); return false; } return true; } With Password being 00 sourceEPC being the Tag ID obtained after reading Memory Bank being MEMORY_BANK.MEMORY_BANK_USER target data being "8426017056458" offset being 0 It just keeps giving me "GetStatus Write RFID_API_UNKNOWN_ERROR data(x)- Field can Only Take Word values" and I have no idea why this is the case, nor I know what a "Word value" is, and i've searched for it. This is all under the "OperationFailureException", as well. Any help would be appreciated, as there's almost no resources online for this kind of thing.
Even this question is a bit older, I had the same problem so as far as I know this should be the answer. Your target data "8426017056458" length is 13 and at writeAccessParams.setWriteDataLength(writeData.length()/4) you are devide it with four. Now if you are trying to write the target data it is longer than the determined WriteDataLength. And this throws the Error. One 'word' is 4 Hex => 16 Bits long. So your Data have to be filled up first and convert it to Hex.
adb shell command from android app
When I try to run the following process = Runtime.getRuntime().exec("input touchscreen swipe 100 1000 300 1000 1000"); //Normal swipe it works. However, when I am using it as following, it is not working. String[] inputs = {"adb", "shell", "input touchscreen swipe 500 1000 600 1000 1000"}; Process p = Runtime.getRuntime().exec(inputs); p.waitFor(); I've another command which I want to run, and for it to run, I have to use the second approach. Can someone tell me what is the reason or how can I make the second one run?
Process p = Runtime.getRuntime().exec(inputs); throws a couple of exceptions, including but not limited to IO, Null Pointer, Index Out of Bound. Try surrounding that line with a try catch Process p; try { p = Runtime.getRuntime().exec(ch); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
You should paste what the error is, if it exists. (For example, in logcat.) adb is the client, which may not exist in your Android device (since Android 5.0+). You are not expected to use it in your Android App command. For your sample, you can directly use input command without adb. Also, process = Runtime.getRuntime().exec("input touchscreen swipe 100 1000 300 1000 1000"); is equivalent to String[] inputs = {"input", "touchscreen", "swipe", "100", "1000", "300", "1000", "1000"}; process = Runtime.getRuntime().exec(inputs);. Note the dropped first two element in inputs from your question.
As #Geno Chen mentioned, the parameters, need to go with double quotes. String[] inputs = {"input", "touchscreen", "swipe", "100", "1000", "300", "1000", "1000"}; p.waitFor(); must be removed to get this working.
How to understand MTA's real-time gtfs data feeds
So far I've filled out the MTA online registration form for a Developer's API Key. Then in my android project, I implemented the gtfs realtime bindings dependecy from one of Google's github repositories, compile group: 'com.google.transit', name: 'gtfs-realtime-bindings', version: '0.0.4' Using their Java class, I tried this following code to print out all the gtfs data from the link given by MTA, try { String urlString = "http://datamine.mta.info/mta_esi.php?key=insertmykeyhere"; URL url = new URL(urlString.toString()); GtfsRealtime.FeedMessage feed = GtfsRealtime.FeedMessage.parseFrom(url.openStream()); for (GtfsRealtime.FeedEntity entity : feed.getEntityList()) { if (entity.hasTripUpdate()) { Log.d("stuff", entity.getTripUpdate().toString()); } } } catch (IOException e) { e.printStackTrace(); } However, I'm now having trouble interpreting the data printed out. I understand that there are static data feeds from http://web.mta.info/developers/developer-data-terms.html, which I used to interpret some of the data. Here is one of the trip updates printed out, stuff: trip { trip_id: "036000_GS.N01R" start_date: "20170218" route_id: "GS" 1001: "\n\0200S 0600 GCS/TSS\020\001\030\001" } stop_time_update { departure { time: 1487415600 } stop_id: "901N" 1001: "\n\0011\022\0011" } stop_time_update { arrival { time: 1487415690 } stop_id: "902N" 1001: "\n\0011" } I understand some parts such as trip_id, start_date, and stop_id. But parts such as trip_id, time, and 1001 I'm still unsure about it and the text files from the static feed don't do the best job of explaining them.
The MTA Subway GTFS-RT feeds are a little different than most others. Typically, GTFS-RT refers directly back to a static GTFS' via trip_id/stop_id/etc. Since in NYC there is usually a deviation from normal service ("2 Train via the 5 Line"), the RT feed retains the option to create new trips that do not exist in the static feed. To answer your immediate questions, you need to add the realtime extensions. That should solve the empty 1001: field. To do so, either compile the proto file, or just import the onebusaway-gtfs-realtime-api library, which has the extensions pre-compiled in: ExtensionRegistry registry = ExtensionRegistry.newInstance(); registry.add(GtfsRealtimeNYCT.nyctFeedHeader); registry.add(GtfsRealtimeNYCT.nyctStopTimeUpdate); registry.add(GtfsRealtimeNYCT.nyctTripDescriptor); GtfsRealtime.FeedMessage feed = GtfsRealtime.FeedMessage.parseFrom(url.openStream(), registry); This gives a result like: trip { trip_id: "B20170217WKD_132800B..S" start_date: "2017-02-17 22:08:00" route_id: "B" [transit_realtime.nyct_trip_descriptor] { train_id: "1B 2208 145/BBC" is_assigned: true direction: SOUTH } } stop_time_update { arrival { time: 1487390920 } departure { time: 1487390920 } stop_id: "D39" schedule_relationship: SCHEDULED [transit_realtime.nyct_stop_time_update] { scheduled_track: "A3" actual_track: "A3" } } stop_time_update { arrival { time: 1487391130 } departure { time: 1487391130 } stop_id: "D40" schedule_relationship: SCHEDULED [transit_realtime.nyct_stop_time_update] { scheduled_track: "A3" actual_track: "A3" } }
Cannot start Neo4j Server after Spatial data load
I've been trying to use the Neo4j Spatial plugin with data loaded via Java. I have added the plugin, and when I start an empty database this is confirmed by the following GET request to the server. { "extensions": { "SpatialPlugin": { "addSimplePointLayer": "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/addSimplePointLayer", "findClosestGeometries": "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/findClosestGeometries", "addNodesToLayer": "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/addNodesToLayer", "addGeometryWKTToLayer": "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/addGeometryWKTToLayer", "findGeometriesWithinDistance": "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/findGeometriesWithinDistance", "addEditableLayer": "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/addEditableLayer", "addCQLDynamicLayer": "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/addCQLDynamicLayer", "addNodeToLayer": "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/addNodeToLayer", "getLayer": "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/getLayer", "findGeometriesInBBox": "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/findGeometriesInBBox", "updateGeometryFromWKT": "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/updateGeometryFromWKT" } }, "node": "http://localhost:7474/db/data/node", "node_index": "http://localhost:7474/db/data/index/node", "relationship_index": "http://localhost:7474/db/data/index/relationship", "extensions_info": "http://localhost:7474/db/data/ext", "relationship_types": "http://localhost:7474/db/data/relationship/types", "batch": "http://localhost:7474/db/data/batch", "cypher": "http://localhost:7474/db/data/cypher", "indexes": "http://localhost:7474/db/data/schema/index", "constraints": "http://localhost:7474/db/data/schema/constraint", "transaction": "http://localhost:7474/db/data/transaction", "node_labels": "http://localhost:7474/db/data/labels", "neo4j_version": "2.3.2" } However, when I stop the server, load my spatial data via Java with a SpatialIndexProvider.SIMPLE_WKT_CONFIG index, then adding it with: try (Transaction tx = db.beginTx()) { Index<Node> index = db.index().forNodes("location", SpatialIndexProvider.SIMPLE_WKT_CONFIG); for (String line : lines) { String[] columns = line.split(","); Node node = db.createNode(); node.setProperty("wkt", String.format("POINT(%s %s)", columns[4], columns[3])); node.setProperty("name", columns[0]); index.add(node, "dummy", "value"); } tx.success(); } After a restart, I get the error: 2016-02-23 13:44:36.747+0000 ERROR [o.n.k.KernelHealth] setting TM not OK. Kernel has encountered some problem, please perform necessary action (tx recovery/restart) No index provider 'spatial' found. Maybe the intended provider (or one more of its dependencies) aren't on the classpath or it failed to load. in Messages.log inside the graph.db. Is there anything obvious that I'm doing wrong? I'm on windows 8, Neo4j 2.3.2, Java 8 and neo4j-spatial-0.15-neo4j-2.3.0.jar
Did you unzip the full spatial zip into the plugins directory? Otherwise some classes that spatial needs can't be found.
Printing with Attributes(Tray Control, Duplex, etc...) using javax.print library
I've been trying for some time to determine a way to use the standard Java Print library to print files - specifically, PDF documents - with certain attributes - specifically, to certain trays or using duplex. There exists plenty of documentation on how this should be done, and indeed, I've researched and tried these methods. The typical way is something like this: public static void main (String [] args) { try { PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null, null); //Acquire Printer PrintService printer = null; for (PrintService serv: pservices) { System.out.println(serv.toString()); if (serv.getName().equals("PRINTER_NAME_BLAH")) { printer = serv; } } if (printer != null) { System.out.println("Found!"); //Open File FileInputStream fis = new FileInputStream("FILENAME_BLAH_BLAH.pdf"); //Create Doc out of file, autosense filetype Doc pdfDoc = new SimpleDoc(fis, DocFlavor.INPUT_STREAM.AUTOSENSE, null); //Create job for printer DocPrintJob printJob = printer.createPrintJob(); //Create AttributeSet PrintRequestAttributeSet pset = new HashPrintRequestAttributeSet(); //Add MediaTray to AttributeSet pset.add(MediaTray.TOP); //Add Duplex Option to AttributeSet pset.add(Sides.DUPLEX); //Print using Doc and Attributes printJob.print(pdfDoc, pset); //Close File fis.close(); } } catch (Throwable t) { t.printStackTrace(); } } In short, you do the following Find the Printer Create a PrinterJob Create an AttributeSet Add Attributes to the AttributeSet, such as Tray and Duplex Call print on the printer job using the AttributeSet The problem here is that, despite being the documented way of doing this, as well as what I've found from several tutorials, this method... doesn't work. Now keep in mind, I know that doesn't sound very descript, but hear me out. I don't say that lightly... The official documentation for PrinterJob actually mentions that the AttributeSet is ignored in the default implementation. Source code seen here shows this to be true - the attributes are passed in and ignored entirely. So apparently, you need some sort of extended version of the class, which is possibly based on the specific printers and their capabilities? I attempted to write some test code that would tell me such capabilities - we have a large variety of printers set up at the office, large or small, simple or full of bells and whistles - not to mention several drivers on my computer just for pseudo-printer drivers that just create documents and simulate printers without going to any sort of hardware. The test code is as follows: public static void main (String [] args) { PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null, null); for (PrintService serv: pservices) { System.out.println(serv.toString()); printFunctionality(serv, "Trays", MediaTray.class); printFunctionality(serv, "Copies", Copies.class); printFunctionality(serv, "Print Quality", PrintQuality.class); printFunctionality(serv, "Color", ColorSupported.class); printFunctionality(serv, "Media Size", MediaSize.class); printFunctionality(serv, "Accepting Jobs", PrinterIsAcceptingJobs.class); } } private static void printFunctionality(PrintService serv, String attrName, Class<? extends Attribute> attr) { boolean isSupported = serv.isAttributeCategorySupported(attr); System.out.println(" " + attrName + ": " + (isSupported ? "Y" : "N")); } The results I found were that every printer, without exception, returned that "copies" were supported, and all other attributes were not. Furthermore, every printer's capabilities were identical, regardless of how implausible that would seem. The inevitable question is multi-layered: How does one send in attributes in a way that they are registered? Additionally, how does one properly detect the capabilities of a printer? Indeed, is the PrinterJob class actually extended in a usable way at all, or are the Attributes always ignored? Examples I've found throughout The Internet seem to suggest to me that the answer to the latter question is "No, they are always ignored", which seems ridiculous to me (but increasingly more believable as I sift through hundreds of pages). Is this code that Sun simply set up but never got working to a completed state? If so, are there any alternatives?
The problem is that the the Java print API is a bridge between worlds. Printer manufacturers don't release drivers for the JVM. They release drivers for Windows, Macintosh, and maybe someone has a a driver for a given printer that works on one or more *nix platforms. Along you come with some Java code running inside a JVM on some host system. When you start querying the printer features, you aren't talking to the printers -- you are talking to a bridge class in java.awt.print that hook into the JVM, which hooks to the host operating system, which hooks into whatever particular driver was installed for a given printer. So there are several places where this can fall apart... The particular JVM you are on may or may not fully implement the API for querying printer features, let alone passing those parameters along for a given job. A few suggestions: look into the javax.print classes as an alternative to java.awt.print -- I've had more luck printing from there. try using alternative print drivers for your printers -- you can define multiple named connections to a given printer, each with a different driver. If you've got a manufacturer provided driver, try a more generic driver, if you've got a generic driver, try to install a more specific one. run your code under alternate JVM implementations for your platform
So, we inevitably found a way to print to different trays and with different settings, but not directly. We found it impossible to send attributes via the printJob.print method, and that much hasn't changed. However, we were able to set the name of the print job, then intercept the print job with a low-level Perl script, parse the name, and set the tray and duplex settings there. It's an extreme hack, but it works. It still remains true that Java Printer Attributes do not work, and you will need to find another way if you want to set them.
We had similar requirement to print PDF's and wanted to send some pages to Specific tray and also wanted the document to be stapled. We used Java code + ghost script combination First convert PDF to ghost script and then add PJL (Print job language) commands to ghost script file to select trays and staple the documents. Then send that edited ghost script file to printer. Here is complete example written in Java http://reddymails.blogspot.com/2014/07/how-to-print-documents-using-java-how.html -Ram
Here's what it looks like in javafx Tray's may vary and it will also print out all trays that are available just change the tray name private void printImage(Node node) { PrinterJob job = PrinterJob.createPrinterJob(); if (job != null) { JobSettings js = job.getJobSettings(); PaperSource papersource = js.getPaperSource(); System.out.println("PaperSource=" + papersource); PrinterAttributes pa = printer.getPrinterAttributes(); Set<PaperSource> s = pa.getSupportedPaperSources(); System.out.println("# of papersources=" + s.size()); if (s != null) { for (PaperSource newPaperSource : s) { System.out.println("newpapersource= " + newPaperSource); //Here is where you would put the tray name that is appropriate //in the contains section if(newPaperSource.toString().contains("Tray 2")) js.setPaperSource(newPaperSource); } } job.getJobSettings().setJobName("Whatever"); ObjectProperty<PaperSource> sources = job.getJobSettings().paperSourceProperty(); System.out.println(sources.toString()); boolean success = job.printPage(node); if (success) { System.out.println("PRINTING FINISHED"); job.endJob(); //Stage mainStage = (Stage) root.getScene().getWindow(); //mainStage.close(); } } } Here's My output: PaperSource=Paper source : Automatic # of papersources=6 newpapersource= Paper source : newpapersource= Paper source : Manual Feed in Tray 1 newpapersource= Paper source : Printer auto select newpapersource= Paper source : Tray 1 newpapersource= Paper source : Tray 2 newpapersource= Paper source : Form-Source ObjectProperty [bean: Collation = UNCOLLATED Copies = 1 Sides = ONE_SIDED JobName = Whatever Page ranges = null Print color = COLOR Print quality = NORMAL Print resolution = Feed res=600dpi. Cross Feed res=600dpi. Paper source = Paper source : Tray 2 Page layout = Paper=Paper: Letter size=8.5x11.0 INCH Orient=PORTRAIT leftMargin=54.0 rightMargin=54.0 topMargin=54.0 bottomMargin=54.0, name: paperSource, value: Paper source : Tray 2] PRINTING FINISHED
I've found the trick for the printer trays is to iterate over the Media.class using getSupportedAttributeValues(...), match the human-readable name, and select that particular value. Tested on Windows, MacOS with several tray configurations. String tray = "1"; // Handle human-readable names, see PRINTER_TRAY_ALIASES usage below for context. Adjust as needed. List<String> PRINTER_TRAY_ALIASES = Arrays.asList("", "Tray ", "Paper Cassette "); // Get default printer PrintService printService = PrintServiceLookup.lookupDefaultPrintService(); // Attributes to be provided at print time PrintRequestAttributeSet pset = new HashPrintRequestAttributeSet(); Media[] supported = printService.getSupportedAttributeValues(Media.class, null, null); for(Media m : supported) { for(String pta : PRINTER_TRAY_ALIASES) { // Matches "1", "Tray 1", or "Paper Cassette 1" if (m.toString().trim().equalsIgnoreCase(pta + tray)) { attributes.add(m); break; } } } // Print, etc // printJob.print(pdfDoc, pset);