1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.modeshape.sequencer.image;
15
16 import java.io.DataInput;
17 import java.io.FileInputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.net.URL;
21 import java.util.Vector;
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 public class ImageMetadata {
133
134
135
136
137
138
139 public static final int FORMAT_JPEG = 0;
140
141
142
143
144
145
146 public static final int FORMAT_GIF = 1;
147
148
149
150
151
152
153 public static final int FORMAT_PNG = 2;
154
155
156
157
158
159 public static final int FORMAT_BMP = 3;
160
161
162
163
164
165 public static final int FORMAT_PCX = 4;
166
167
168
169
170 public static final int FORMAT_IFF = 5;
171
172
173
174
175
176 public static final int FORMAT_RAS = 6;
177
178
179 public static final int FORMAT_PBM = 7;
180
181
182 public static final int FORMAT_PGM = 8;
183
184
185 public static final int FORMAT_PPM = 9;
186
187
188 public static final int FORMAT_PSD = 10;
189
190
191
192
193
194
195
196
197
198
199 private static final String[] FORMAT_NAMES = {"JPEG", "GIF", "PNG", "BMP", "PCX", "IFF", "RAS", "PBM", "PGM", "PPM", "PSD"};
200
201
202
203
204
205 private static final String[] MIME_TYPE_STRINGS = {"image/jpeg", "image/gif", "image/png", "image/bmp", "image/pcx",
206 "image/iff", "image/ras", "image/x-portable-bitmap", "image/x-portable-graymap", "image/x-portable-pixmap", "image/psd"};
207
208 private int width;
209 private int height;
210 private int bitsPerPixel;
211
212 private boolean progressive;
213 private int format;
214 private InputStream in;
215 private DataInput din;
216 private boolean collectComments = true;
217 private Vector<String> comments;
218 private boolean determineNumberOfImages;
219 private int numberOfImages;
220 private int physicalHeightDpi;
221 private int physicalWidthDpi;
222
223 private void addComment( String s ) {
224 if (comments == null) {
225 comments = new Vector<String>();
226 }
227 comments.addElement(s);
228 }
229
230
231
232
233
234
235
236
237 public boolean check() {
238 format = -1;
239 width = -1;
240 height = -1;
241 bitsPerPixel = -1;
242 numberOfImages = 1;
243 physicalHeightDpi = -1;
244 physicalWidthDpi = -1;
245 comments = null;
246 try {
247 int b1 = read() & 0xff;
248 int b2 = read() & 0xff;
249 if (b1 == 0x47 && b2 == 0x49) {
250 return checkGif();
251 } else if (b1 == 0x89 && b2 == 0x50) {
252 return checkPng();
253 } else if (b1 == 0xff && b2 == 0xd8) {
254 return checkJpeg();
255 } else if (b1 == 0x42 && b2 == 0x4d) {
256 return checkBmp();
257 } else if (b1 == 0x0a && b2 < 0x06) {
258 return checkPcx();
259 } else if (b1 == 0x46 && b2 == 0x4f) {
260 return checkIff();
261 } else if (b1 == 0x59 && b2 == 0xa6) {
262 return checkRas();
263 } else if (b1 == 0x50 && b2 >= 0x31 && b2 <= 0x36) {
264 return checkPnm(b2 - '0');
265 } else if (b1 == 0x38 && b2 == 0x42) {
266 return checkPsd();
267 } else {
268 return false;
269 }
270 } catch (IOException ioe) {
271 return false;
272 }
273 }
274
275 private boolean checkBmp() throws IOException {
276 byte[] a = new byte[44];
277 if (read(a) != a.length) {
278 return false;
279 }
280 width = getIntLittleEndian(a, 16);
281 height = getIntLittleEndian(a, 20);
282 if (width < 1 || height < 1) {
283 return false;
284 }
285 bitsPerPixel = getShortLittleEndian(a, 26);
286 if (bitsPerPixel != 1 && bitsPerPixel != 4 && bitsPerPixel != 8 && bitsPerPixel != 16 && bitsPerPixel != 24
287 && bitsPerPixel != 32) {
288 return false;
289 }
290 int x = (int)(getIntLittleEndian(a, 36) * 0.0254);
291 if (x > 0) {
292 setPhysicalWidthDpi(x);
293 }
294 int y = (int)(getIntLittleEndian(a, 40) * 0.0254);
295 if (y > 0) {
296 setPhysicalHeightDpi(y);
297 }
298 format = FORMAT_BMP;
299 return true;
300 }
301
302 private boolean checkGif() throws IOException {
303 final byte[] GIF_MAGIC_87A = {0x46, 0x38, 0x37, 0x61};
304 final byte[] GIF_MAGIC_89A = {0x46, 0x38, 0x39, 0x61};
305 byte[] a = new byte[11];
306 if (read(a) != 11) {
307 return false;
308 }
309 if ((!equals(a, 0, GIF_MAGIC_89A, 0, 4)) && (!equals(a, 0, GIF_MAGIC_87A, 0, 4))) {
310 return false;
311 }
312 format = FORMAT_GIF;
313 width = getShortLittleEndian(a, 4);
314 height = getShortLittleEndian(a, 6);
315 int flags = a[8] & 0xff;
316 bitsPerPixel = ((flags >> 4) & 0x07) + 1;
317
318 if (!determineNumberOfImages) {
319 return true;
320 }
321
322 if ((flags & 0x80) != 0) {
323 int tableSize = (1 << ((flags & 7) + 1)) * 3;
324 skip(tableSize);
325 }
326 numberOfImages = 0;
327 int blockType;
328 do {
329 blockType = read();
330 switch (blockType) {
331 case (0x2c):
332 {
333 if (read(a, 0, 9) != 9) {
334 return false;
335 }
336 flags = a[8] & 0xff;
337 progressive = (flags & 0x40) != 0;
338
339
340
341
342 int localBitsPerPixel = (flags & 0x07) + 1;
343 if (localBitsPerPixel > bitsPerPixel) {
344 bitsPerPixel = localBitsPerPixel;
345 }
346 if ((flags & 0x80) != 0) {
347 skip((1 << localBitsPerPixel) * 3);
348 }
349 skip(1);
350 int n;
351 do {
352 n = read();
353 if (n > 0) {
354 skip(n);
355 } else if (n == -1) {
356 return false;
357 }
358 } while (n > 0);
359 numberOfImages++;
360 break;
361 }
362 case (0x21):
363 {
364 int extensionType = read();
365 if (collectComments && extensionType == 0xfe) {
366 StringBuffer sb = new StringBuffer();
367 int n;
368 do {
369 n = read();
370 if (n == -1) {
371 return false;
372 }
373 if (n > 0) {
374 for (int i = 0; i < n; i++) {
375 int ch = read();
376 if (ch == -1) {
377 return false;
378 }
379 sb.append((char)ch);
380 }
381 }
382 } while (n > 0);
383 } else {
384 int n;
385 do {
386 n = read();
387 if (n > 0) {
388 skip(n);
389 } else if (n == -1) {
390 return false;
391 }
392 } while (n > 0);
393 }
394 break;
395 }
396 case (0x3b):
397 {
398 break;
399 }
400 default: {
401 return false;
402 }
403 }
404 } while (blockType != 0x3b);
405 return true;
406 }
407
408 private boolean checkIff() throws IOException {
409 byte[] a = new byte[10];
410
411
412 if (read(a, 0, 10) != 10) {
413 return false;
414 }
415 final byte[] IFF_RM = {0x52, 0x4d};
416 if (!equals(a, 0, IFF_RM, 0, 2)) {
417 return false;
418 }
419 int type = getIntBigEndian(a, 6);
420 if (type != 0x494c424d &&
421 type != 0x50424d20) {
422 return false;
423 }
424
425 do {
426 if (read(a, 0, 8) != 8) {
427 return false;
428 }
429 int chunkId = getIntBigEndian(a, 0);
430 int size = getIntBigEndian(a, 4);
431 if ((size & 1) == 1) {
432 size++;
433 }
434 if (chunkId == 0x424d4844) {
435 if (read(a, 0, 9) != 9) {
436 return false;
437 }
438 format = FORMAT_IFF;
439 width = getShortBigEndian(a, 0);
440 height = getShortBigEndian(a, 2);
441 bitsPerPixel = a[8] & 0xff;
442 return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel < 33);
443 }
444 skip(size);
445 } while (true);
446 }
447
448 private boolean checkJpeg() throws IOException {
449 byte[] data = new byte[12];
450 while (true) {
451 if (read(data, 0, 4) != 4) {
452 return false;
453 }
454 int marker = getShortBigEndian(data, 0);
455 int size = getShortBigEndian(data, 2);
456 if ((marker & 0xff00) != 0xff00) {
457 return false;
458 }
459 if (marker == 0xffe0) {
460 if (size < 14) {
461
462 skip(size - 2);
463 continue;
464 }
465 if (read(data, 0, 12) != 12) {
466 return false;
467 }
468 final byte[] APP0_ID = {0x4a, 0x46, 0x49, 0x46, 0x00};
469 if (equals(APP0_ID, 0, data, 0, 5)) {
470
471 if (data[7] == 1) {
472 setPhysicalWidthDpi(getShortBigEndian(data, 8));
473 setPhysicalHeightDpi(getShortBigEndian(data, 10));
474 } else if (data[7] == 2) {
475 int x = getShortBigEndian(data, 8);
476 int y = getShortBigEndian(data, 10);
477 setPhysicalWidthDpi((int)(x * 2.54f));
478 setPhysicalHeightDpi((int)(y * 2.54f));
479 }
480 }
481 skip(size - 14);
482 } else if (collectComments && size > 2 && marker == 0xfffe) {
483 size -= 2;
484 byte[] chars = new byte[size];
485 if (read(chars, 0, size) != size) {
486 return false;
487 }
488 String comment = new String(chars, "iso-8859-1");
489 comment = comment.trim();
490 addComment(comment);
491 } else if (marker >= 0xffc0 && marker <= 0xffcf && marker != 0xffc4 && marker != 0xffc8) {
492 if (read(data, 0, 6) != 6) {
493 return false;
494 }
495 format = FORMAT_JPEG;
496 bitsPerPixel = (data[0] & 0xff) * (data[5] & 0xff);
497 progressive = marker == 0xffc2 || marker == 0xffc6 || marker == 0xffca || marker == 0xffce;
498 width = getShortBigEndian(data, 3);
499 height = getShortBigEndian(data, 1);
500 return true;
501 } else {
502 skip(size - 2);
503 }
504 }
505 }
506
507 private boolean checkPcx() throws IOException {
508 byte[] a = new byte[64];
509 if (read(a) != a.length) {
510 return false;
511 }
512 if (a[0] != 1) {
513 return false;
514 }
515
516 int x1 = getShortLittleEndian(a, 2);
517 int y1 = getShortLittleEndian(a, 4);
518 int x2 = getShortLittleEndian(a, 6);
519 int y2 = getShortLittleEndian(a, 8);
520 if (x1 < 0 || x2 < x1 || y1 < 0 || y2 < y1) {
521 return false;
522 }
523 width = x2 - x1 + 1;
524 height = y2 - y1 + 1;
525
526 int bits = a[1];
527 int planes = a[63];
528 if (planes == 1 && (bits == 1 || bits == 2 || bits == 4 || bits == 8)) {
529
530 bitsPerPixel = bits;
531 } else if (planes == 3 && bits == 8) {
532
533 bitsPerPixel = 24;
534 } else {
535 return false;
536 }
537 setPhysicalWidthDpi(getShortLittleEndian(a, 10));
538 setPhysicalHeightDpi(getShortLittleEndian(a, 10));
539 format = FORMAT_PCX;
540 return true;
541 }
542
543 private boolean checkPng() throws IOException {
544 final byte[] PNG_MAGIC = {0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
545 byte[] a = new byte[27];
546 if (read(a) != 27) {
547 return false;
548 }
549 if (!equals(a, 0, PNG_MAGIC, 0, 6)) {
550 return false;
551 }
552 format = FORMAT_PNG;
553 width = getIntBigEndian(a, 14);
554 height = getIntBigEndian(a, 18);
555 bitsPerPixel = a[22] & 0xff;
556 int colorType = a[23] & 0xff;
557 if (colorType == 2 || colorType == 6) {
558 bitsPerPixel *= 3;
559 }
560 progressive = (a[26] & 0xff) != 0;
561 return true;
562 }
563
564 private boolean checkPnm( int id ) throws IOException {
565 if (id < 1 || id > 6) {
566 return false;
567 }
568 final int[] PNM_FORMATS = {FORMAT_PBM, FORMAT_PGM, FORMAT_PPM};
569 format = PNM_FORMATS[(id - 1) % 3];
570 boolean hasPixelResolution = false;
571 String s;
572 while (true) {
573 s = readLine();
574 if (s != null) {
575 s = s.trim();
576 }
577 if (s == null || s.length() < 1) {
578 continue;
579 }
580 if (s.charAt(0) == '#') {
581 if (collectComments && s.length() > 1) {
582 addComment(s.substring(1));
583 }
584 continue;
585 }
586 if (!hasPixelResolution) {
587 int spaceIndex = s.indexOf(' ');
588 if (spaceIndex == -1) {
589 return false;
590 }
591 String widthString = s.substring(0, spaceIndex);
592 spaceIndex = s.lastIndexOf(' ');
593 if (spaceIndex == -1) {
594 return false;
595 }
596 String heightString = s.substring(spaceIndex + 1);
597 try {
598 width = Integer.parseInt(widthString);
599 height = Integer.parseInt(heightString);
600 } catch (NumberFormatException nfe) {
601 return false;
602 }
603 if (width < 1 || height < 1) {
604 return false;
605 }
606 if (format == FORMAT_PBM) {
607 bitsPerPixel = 1;
608 return true;
609 }
610 hasPixelResolution = true;
611 } else {
612 int maxSample;
613 try {
614 maxSample = Integer.parseInt(s);
615 } catch (NumberFormatException nfe) {
616 return false;
617 }
618 if (maxSample < 0) {
619 return false;
620 }
621 for (int i = 0; i < 25; i++) {
622 if (maxSample < (1 << (i + 1))) {
623 bitsPerPixel = i + 1;
624 if (format == FORMAT_PPM) {
625 bitsPerPixel *= 3;
626 }
627 return true;
628 }
629 }
630 return false;
631 }
632 }
633 }
634
635 private boolean checkPsd() throws IOException {
636 byte[] a = new byte[24];
637 if (read(a) != a.length) {
638 return false;
639 }
640 final byte[] PSD_MAGIC = {0x50, 0x53};
641 if (!equals(a, 0, PSD_MAGIC, 0, 2)) {
642 return false;
643 }
644 format = FORMAT_PSD;
645 width = getIntBigEndian(a, 16);
646 height = getIntBigEndian(a, 12);
647 int channels = getShortBigEndian(a, 10);
648 int depth = getShortBigEndian(a, 20);
649 bitsPerPixel = channels * depth;
650 return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel <= 64);
651 }
652
653 private boolean checkRas() throws IOException {
654 byte[] a = new byte[14];
655 if (read(a) != a.length) {
656 return false;
657 }
658 final byte[] RAS_MAGIC = {0x6a, (byte)0x95};
659 if (!equals(a, 0, RAS_MAGIC, 0, 2)) {
660 return false;
661 }
662 format = FORMAT_RAS;
663 width = getIntBigEndian(a, 2);
664 height = getIntBigEndian(a, 6);
665 bitsPerPixel = getIntBigEndian(a, 10);
666 return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel <= 24);
667 }
668
669
670
671
672
673
674
675 private static boolean determineVerbosity( String[] args ) {
676 if (args != null && args.length > 0) {
677 for (int i = 0; i < args.length; i++) {
678 if ("-c".equals(args[i])) {
679 return false;
680 }
681 }
682 }
683 return true;
684 }
685
686 private static boolean equals( byte[] a1,
687 int offs1,
688 byte[] a2,
689 int offs2,
690 int num ) {
691 while (num-- > 0) {
692 if (a1[offs1++] != a2[offs2++]) {
693 return false;
694 }
695 }
696 return true;
697 }
698
699
700
701
702
703
704
705 public int getBitsPerPixel() {
706 return bitsPerPixel;
707 }
708
709
710
711
712
713
714
715
716
717 public String getComment( int index ) {
718 if (comments == null || index < 0 || index >= comments.size()) {
719 throw new IllegalArgumentException("Not a valid comment index: " + index);
720 }
721 return comments.elementAt(index);
722 }
723
724
725
726
727
728
729
730 public int getFormat() {
731 return format;
732 }
733
734
735
736
737
738
739 public String getFormatName() {
740 if (format >= 0 && format < FORMAT_NAMES.length) {
741 return FORMAT_NAMES[format];
742 }
743 return "?";
744 }
745
746
747
748
749
750
751 public int getHeight() {
752 return height;
753 }
754
755 private static int getIntBigEndian( byte[] a,
756 int offs ) {
757 return (a[offs] & 0xff) << 24 | (a[offs + 1] & 0xff) << 16 | (a[offs + 2] & 0xff) << 8 | a[offs + 3] & 0xff;
758 }
759
760 private static int getIntLittleEndian( byte[] a,
761 int offs ) {
762 return (a[offs + 3] & 0xff) << 24 | (a[offs + 2] & 0xff) << 16 | (a[offs + 1] & 0xff) << 8 | a[offs] & 0xff;
763 }
764
765
766
767
768
769
770 public String getMimeType() {
771 if (format >= 0 && format < MIME_TYPE_STRINGS.length) {
772 if (format == FORMAT_JPEG && progressive) {
773 return "image/pjpeg";
774 }
775 return MIME_TYPE_STRINGS[format];
776 }
777 return null;
778 }
779
780
781
782
783
784
785
786
787 public int getNumberOfComments() {
788 if (comments == null) {
789 return 0;
790 }
791 return comments.size();
792 }
793
794
795
796
797
798
799
800
801 public int getNumberOfImages() {
802 return numberOfImages;
803 }
804
805
806
807
808
809
810
811
812
813 public int getPhysicalHeightDpi() {
814 return physicalHeightDpi;
815 }
816
817
818
819
820
821
822
823
824
825
826 public float getPhysicalHeightInch() {
827 int h = getHeight();
828 int ph = getPhysicalHeightDpi();
829 if (h > 0 && ph > 0) {
830 return ((float)h) / ((float)ph);
831 }
832 return -1.0f;
833 }
834
835
836
837
838
839
840
841
842
843
844 public int getPhysicalWidthDpi() {
845 return physicalWidthDpi;
846 }
847
848
849
850
851
852
853
854
855
856 public float getPhysicalWidthInch() {
857 int w = getWidth();
858 int pw = getPhysicalWidthDpi();
859 if (w > 0 && pw > 0) {
860 return ((float)w) / ((float)pw);
861 }
862 return -1.0f;
863 }
864
865 private static int getShortBigEndian( byte[] a,
866 int offs ) {
867 return (a[offs] & 0xff) << 8 | (a[offs + 1] & 0xff);
868 }
869
870 private static int getShortLittleEndian( byte[] a,
871 int offs ) {
872 return (a[offs] & 0xff) | (a[offs + 1] & 0xff) << 8;
873 }
874
875
876
877
878
879
880 public int getWidth() {
881 return width;
882 }
883
884
885
886
887
888
889 public boolean isProgressive() {
890 return progressive;
891 }
892
893
894
895
896
897
898
899
900 public static void main( String[] args ) {
901 ImageMetadata imageMetadata = new ImageMetadata();
902 imageMetadata.setDetermineImageNumber(true);
903 boolean verbose = determineVerbosity(args);
904 if (args.length == 0) {
905 run(null, System.in, imageMetadata, verbose);
906 } else {
907 int index = 0;
908 while (index < args.length) {
909 InputStream in = null;
910 try {
911 String name = args[index++];
912 System.out.print(name + ";");
913 if (name.startsWith("http://")) {
914 in = new URL(name).openConnection().getInputStream();
915 } else {
916 in = new FileInputStream(name);
917 }
918 run(name, in, imageMetadata, verbose);
919 in.close();
920 } catch (IOException e) {
921 System.out.println(e);
922 try {
923 if (in != null) {
924 in.close();
925 }
926 } catch (IOException ee) {
927 }
928 }
929 }
930 }
931 }
932
933 private static void print( String sourceName,
934 ImageMetadata ii,
935 boolean verbose ) {
936 if (verbose) {
937 printVerbose(sourceName, ii);
938 } else {
939 printCompact(sourceName, ii);
940 }
941 }
942
943 private static void printCompact( String sourceName,
944 ImageMetadata imageMetadata ) {
945 final String SEP = "\t";
946 System.out.println(sourceName + SEP + imageMetadata.getFormatName() + SEP + imageMetadata.getMimeType() + SEP
947 + imageMetadata.getWidth() + SEP + imageMetadata.getHeight() + SEP + imageMetadata.getBitsPerPixel()
948 + SEP + imageMetadata.getNumberOfImages() + SEP + imageMetadata.getPhysicalWidthDpi() + SEP
949 + imageMetadata.getPhysicalHeightDpi() + SEP + imageMetadata.getPhysicalWidthInch() + SEP
950 + imageMetadata.getPhysicalHeightInch() + SEP + imageMetadata.isProgressive());
951 }
952
953 private static void printLine( int indentLevels,
954 String text,
955 float value,
956 float minValidValue ) {
957 if (value < minValidValue) {
958 return;
959 }
960 printLine(indentLevels, text, Float.toString(value));
961 }
962
963 private static void printLine( int indentLevels,
964 String text,
965 int value,
966 int minValidValue ) {
967 if (value >= minValidValue) {
968 printLine(indentLevels, text, Integer.toString(value));
969 }
970 }
971
972 private static void printLine( int indentLevels,
973 String text,
974 String value ) {
975 if (value == null || value.length() == 0) {
976 return;
977 }
978 while (indentLevels-- > 0) {
979 System.out.print("\t");
980 }
981 if (text != null && text.length() > 0) {
982 System.out.print(text);
983 System.out.print(" ");
984 }
985 System.out.println(value);
986 }
987
988 private static void printVerbose( String sourceName,
989 ImageMetadata ii ) {
990 printLine(0, null, sourceName);
991 printLine(1, "File format: ", ii.getFormatName());
992 printLine(1, "MIME type: ", ii.getMimeType());
993 printLine(1, "Width (pixels): ", ii.getWidth(), 1);
994 printLine(1, "Height (pixels): ", ii.getHeight(), 1);
995 printLine(1, "Bits per pixel: ", ii.getBitsPerPixel(), 1);
996 printLine(1, "Progressive: ", ii.isProgressive() ? "yes" : "no");
997 printLine(1, "Number of images: ", ii.getNumberOfImages(), 1);
998 printLine(1, "Physical width (dpi): ", ii.getPhysicalWidthDpi(), 1);
999 printLine(1, "Physical height (dpi): ", ii.getPhysicalHeightDpi(), 1);
1000 printLine(1, "Physical width (inches): ", ii.getPhysicalWidthInch(), 1.0f);
1001 printLine(1, "Physical height (inches): ", ii.getPhysicalHeightInch(), 1.0f);
1002 int numComments = ii.getNumberOfComments();
1003 printLine(1, "Number of textual comments: ", numComments, 1);
1004 if (numComments > 0) {
1005 for (int i = 0; i < numComments; i++) {
1006 printLine(2, null, ii.getComment(i));
1007 }
1008 }
1009 }
1010
1011 private int read() throws IOException {
1012 if (in != null) {
1013 return in.read();
1014 }
1015 return din.readByte();
1016 }
1017
1018 private int read( byte[] a ) throws IOException {
1019 if (in != null) {
1020 return in.read(a);
1021 }
1022 din.readFully(a);
1023 return a.length;
1024 }
1025
1026 private int read( byte[] a,
1027 int offset,
1028 int num ) throws IOException {
1029 if (in != null) {
1030 return in.read(a, offset, num);
1031 }
1032 din.readFully(a, offset, num);
1033 return num;
1034 }
1035
1036 private String readLine() throws IOException {
1037 return readLine(new StringBuffer());
1038 }
1039
1040 private String readLine( StringBuffer sb ) throws IOException {
1041 boolean finished;
1042 do {
1043 int value = read();
1044 finished = (value == -1 || value == 10);
1045 if (!finished) {
1046 sb.append((char)value);
1047 }
1048 } while (!finished);
1049 return sb.toString();
1050 }
1051
1052 private static void run( String sourceName,
1053 InputStream in,
1054 ImageMetadata imageMetadata,
1055 boolean verbose ) {
1056 imageMetadata.setInput(in);
1057 imageMetadata.setDetermineImageNumber(true);
1058 imageMetadata.setCollectComments(verbose);
1059 if (imageMetadata.check()) {
1060 print(sourceName, imageMetadata, verbose);
1061 }
1062 }
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072 public void setCollectComments( boolean newValue ) {
1073 collectComments = newValue;
1074 }
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086 public void setDetermineImageNumber( boolean newValue ) {
1087 determineNumberOfImages = newValue;
1088 }
1089
1090
1091
1092
1093
1094
1095
1096 public void setInput( DataInput dataInput ) {
1097 din = dataInput;
1098 in = null;
1099 }
1100
1101
1102
1103
1104
1105
1106 public void setInput( InputStream inputStream ) {
1107 in = inputStream;
1108 din = null;
1109 }
1110
1111 private void setPhysicalHeightDpi( int newValue ) {
1112 physicalWidthDpi = newValue;
1113 }
1114
1115 private void setPhysicalWidthDpi( int newValue ) {
1116 physicalHeightDpi = newValue;
1117 }
1118
1119 private void skip( int num ) throws IOException {
1120 while (num > 0) {
1121 long result;
1122 if (in != null) {
1123 result = in.skip(num);
1124 } else {
1125 result = din.skipBytes(num);
1126 }
1127 if (result > 0) {
1128 num -= result;
1129 } else {
1130 if (in != null) {
1131 result = in.read();
1132 } else {
1133 result = din.readByte();
1134 }
1135 if (result == -1) {
1136 throw new IOException("Premature end of input.");
1137 }
1138 num--;
1139 }
1140 }
1141 }
1142 }