1
2
3
4
5
6
7
8
9
10
11
12
13
14 package com.atlassian.core.util;
15
16 import java.io.DataInput;
17 import java.io.EOFException;
18 import java.io.FileInputStream;
19 import java.io.InputStream;
20 import java.io.IOException;
21 import java.net.URL;
22 import java.util.Vector;
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 public class ImageInfo
130 {
131
132
133
134
135
136 public static final int FORMAT_JPEG = 0;
137
138
139
140
141
142
143
144 public static final int FORMAT_GIF = 1;
145
146
147
148
149
150
151 public static final int FORMAT_PNG = 2;
152
153
154
155
156
157 public static final int FORMAT_BMP = 3;
158
159
160
161
162
163 public static final int FORMAT_PCX = 4;
164
165
166
167
168 public static final int FORMAT_IFF = 5;
169
170
171
172
173
174 public static final int FORMAT_RAS = 6;
175
176
177 public static final int FORMAT_PBM = 7;
178
179
180 public static final int FORMAT_PGM = 8;
181
182
183 public static final int FORMAT_PPM = 9;
184
185
186 public static final int FORMAT_PSD = 10;
187
188
189 public static final int FORMAT_SWF = 11;
190
191
192
193
194 private static final String[] FORMAT_NAMES = { "JPEG", "GIF", "PNG", "BMP", "PCX", "IFF", "RAS", "PBM", "PGM",
195 "PPM", "PSD", "SWF" };
196
197
198
199
200
201 private static final String[] MIME_TYPE_STRINGS = { "image/jpeg", "image/gif", "image/png", "image/bmp",
202 "image/pcx", "image/iff", "image/ras", "image/x-portable-bitmap", "image/x-portable-graymap",
203 "image/x-portable-pixmap", "image/psd", "application/x-shockwave-flash" };
204
205 private int width;
206 private int height;
207 private int bitsPerPixel;
208 private boolean progressive;
209 private int format;
210 private InputStream in;
211 private DataInput din;
212 private boolean collectComments = true;
213 private Vector comments;
214 private boolean determineNumberOfImages;
215 private int numberOfImages;
216 private int physicalHeightDpi;
217 private int physicalWidthDpi;
218 private int bitBuf;
219 private int bitPos;
220
221 private void addComment(String s)
222 {
223 if (comments == null)
224 {
225 comments = new Vector();
226 }
227 comments.addElement(s);
228 }
229
230
231
232
233
234
235
236
237 public boolean check()
238 {
239 format = -1;
240 width = -1;
241 height = -1;
242 bitsPerPixel = -1;
243 numberOfImages = 1;
244 physicalHeightDpi = -1;
245 physicalWidthDpi = -1;
246 comments = null;
247 try
248 {
249 int b1 = read() & 0xff;
250 int b2 = read() & 0xff;
251 if (b1 == 0x47 && b2 == 0x49)
252 {
253 return checkGif();
254 }
255 else if (b1 == 0x89 && b2 == 0x50)
256 {
257 return checkPng();
258 }
259 else if (b1 == 0xff && b2 == 0xd8)
260 {
261 return checkJpeg();
262 }
263 else if (b1 == 0x42 && b2 == 0x4d)
264 {
265 return checkBmp();
266 }
267 else if (b1 == 0x0a && b2 < 0x06)
268 {
269 return checkPcx();
270 }
271 else if (b1 == 0x46 && b2 == 0x4f)
272 {
273 return checkIff();
274 }
275 else if (b1 == 0x59 && b2 == 0xa6)
276 {
277 return checkRas();
278 }
279 else if (b1 == 0x50 && b2 >= 0x31 && b2 <= 0x36)
280 {
281 return checkPnm(b2 - '0');
282 }
283 else if (b1 == 0x38 && b2 == 0x42)
284 {
285 return checkPsd();
286 }
287 else if (b1 == 0x46 && b2 == 0x57)
288 {
289 return checkSwf();
290 }
291 else
292 {
293 return false;
294 }
295 }
296 catch (IOException ioe)
297 {
298 return false;
299 }
300 }
301
302 private boolean checkBmp() throws IOException
303 {
304 byte[] a = new byte[44];
305 if (read(a) != a.length)
306 {
307 return false;
308 }
309 width = getIntLittleEndian(a, 16);
310 height = getIntLittleEndian(a, 20);
311 if (width < 1 || height < 1)
312 {
313 return false;
314 }
315 bitsPerPixel = getShortLittleEndian(a, 26);
316 if (bitsPerPixel != 1 && bitsPerPixel != 4 && bitsPerPixel != 8 && bitsPerPixel != 16 && bitsPerPixel != 24
317 && bitsPerPixel != 32)
318 {
319 return false;
320 }
321 int x = (int) (getIntLittleEndian(a, 36) * 0.0254);
322 if (x > 0)
323 {
324 setPhysicalWidthDpi(x);
325 }
326 int y = (int) (getIntLittleEndian(a, 40) * 0.0254);
327 if (y > 0)
328 {
329 setPhysicalHeightDpi(y);
330 }
331 format = FORMAT_BMP;
332 return true;
333 }
334
335 private boolean checkGif() throws IOException
336 {
337 final byte[] GIF_MAGIC_87A = { 0x46, 0x38, 0x37, 0x61 };
338 final byte[] GIF_MAGIC_89A = { 0x46, 0x38, 0x39, 0x61 };
339 byte[] a = new byte[11];
340 if (read(a) != 11)
341 {
342 return false;
343 }
344 if ((!equals(a, 0, GIF_MAGIC_89A, 0, 4)) && (!equals(a, 0, GIF_MAGIC_87A, 0, 4)))
345 {
346 return false;
347 }
348 format = FORMAT_GIF;
349 width = getShortLittleEndian(a, 4);
350 height = getShortLittleEndian(a, 6);
351 int flags = a[8] & 0xff;
352 bitsPerPixel = ((flags >> 4) & 0x07) + 1;
353
354 if (!determineNumberOfImages)
355 {
356 return true;
357 }
358
359 if ((flags & 0x80) != 0)
360 {
361 int tableSize = (1 << ((flags & 7) + 1)) * 3;
362 skip(tableSize);
363 }
364 numberOfImages = 0;
365 int blockType;
366 do
367 {
368 blockType = read();
369 switch (blockType)
370 {
371 case (0x2c):
372 {
373 if (read(a, 0, 9) != 9)
374 {
375 return false;
376 }
377 flags = a[8] & 0xff;
378 progressive = (flags & 0x40) != 0;
379 int localBitsPerPixel = (flags & 0x07) + 1;
380 if (localBitsPerPixel > bitsPerPixel)
381 {
382 bitsPerPixel = localBitsPerPixel;
383 }
384 if ((flags & 0x80) != 0)
385 {
386 skip((1 << localBitsPerPixel) * 3);
387 }
388 skip(1);
389 int n;
390 do
391 {
392 n = read();
393 if (n > 0)
394 {
395 skip(n);
396 }
397 else if (n == -1)
398 {
399 return false;
400 }
401 }
402 while (n > 0);
403 numberOfImages++;
404 break;
405 }
406 case (0x21):
407 {
408 int extensionType = read();
409 if (collectComments && extensionType == 0xfe)
410 {
411 StringBuffer sb = new StringBuffer();
412 int n;
413 do
414 {
415 n = read();
416 if (n == -1)
417 {
418 return false;
419 }
420 if (n > 0)
421 {
422 for (int i = 0; i < n; i++)
423 {
424 int ch = read();
425 if (ch == -1)
426 {
427 return false;
428 }
429 sb.append((char) ch);
430 }
431 }
432 }
433 while (n > 0);
434 }
435 else
436 {
437 int n;
438 do
439 {
440 n = read();
441 if (n > 0)
442 {
443 skip(n);
444 }
445 else if (n == -1)
446 {
447 return false;
448 }
449 }
450 while (n > 0);
451 }
452 break;
453 }
454 case (0x3b):
455 {
456 break;
457 }
458 default:
459 {
460 return false;
461 }
462 }
463 }
464 while (blockType != 0x3b);
465 return true;
466 }
467
468 private boolean checkIff() throws IOException
469 {
470 byte[] a = new byte[10];
471
472
473 if (read(a, 0, 10) != 10)
474 {
475 return false;
476 }
477 final byte[] IFF_RM = { 0x52, 0x4d };
478 if (!equals(a, 0, IFF_RM, 0, 2))
479 {
480 return false;
481 }
482 int type = getIntBigEndian(a, 6);
483 if (type != 0x494c424d &&
484 type != 0x50424d20)
485 {
486 return false;
487 }
488
489 do
490 {
491 if (read(a, 0, 8) != 8)
492 {
493 return false;
494 }
495 int chunkId = getIntBigEndian(a, 0);
496 int size = getIntBigEndian(a, 4);
497 if ((size & 1) == 1)
498 {
499 size++;
500 }
501 if (chunkId == 0x424d4844)
502 {
503 if (read(a, 0, 9) != 9)
504 {
505 return false;
506 }
507 format = FORMAT_IFF;
508 width = getShortBigEndian(a, 0);
509 height = getShortBigEndian(a, 2);
510 bitsPerPixel = a[8] & 0xff;
511 return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel < 33);
512 }
513 else
514 {
515 skip(size);
516 }
517 }
518 while (true);
519 }
520
521 private boolean checkJpeg() throws IOException
522 {
523 byte[] data = new byte[12];
524 while (true)
525 {
526 if (read(data, 0, 4) != 4)
527 {
528 return false;
529 }
530 int marker = getShortBigEndian(data, 0);
531 int size = getShortBigEndian(data, 2);
532 if ((marker & 0xff00) != 0xff00)
533 {
534 return false;
535 }
536 if (marker == 0xffe0)
537 {
538 if (size < 14)
539 {
540 return false;
541 }
542 if (read(data, 0, 12) != 12)
543 {
544 return false;
545 }
546 final byte[] APP0_ID = { 0x4a, 0x46, 0x49, 0x46, 0x00 };
547 if (equals(APP0_ID, 0, data, 0, 5))
548 {
549 if (data[7] == 1)
550 {
551 setPhysicalWidthDpi(getShortBigEndian(data, 8));
552 setPhysicalHeightDpi(getShortBigEndian(data, 10));
553 }
554 else if (data[7] == 2)
555 {
556 int x = getShortBigEndian(data, 8);
557 int y = getShortBigEndian(data, 10);
558 setPhysicalWidthDpi((int) (x * 2.54f));
559 setPhysicalHeightDpi((int) (y * 2.54f));
560 }
561 }
562 skip(size - 14);
563 }
564 else if (collectComments && size > 2 && marker == 0xfffe)
565 {
566 size -= 2;
567 byte[] chars = new byte[size];
568 if (read(chars, 0, size) != size)
569 {
570 return false;
571 }
572 String comment = new String(chars, "iso-8859-1");
573 comment = comment.trim();
574 addComment(comment);
575 }
576 else if (marker >= 0xffc0 && marker <= 0xffcf && marker != 0xffc4 && marker != 0xffc8)
577 {
578 if (read(data, 0, 6) != 6)
579 {
580 return false;
581 }
582 format = FORMAT_JPEG;
583 bitsPerPixel = (data[0] & 0xff) * (data[5] & 0xff);
584 progressive = marker == 0xffc2 || marker == 0xffc6 || marker == 0xffca || marker == 0xffce;
585 width = getShortBigEndian(data, 3);
586 height = getShortBigEndian(data, 1);
587 return true;
588 }
589 else
590 {
591 skip(size - 2);
592 }
593 }
594 }
595
596 private boolean checkPcx() throws IOException
597 {
598 byte[] a = new byte[64];
599 if (read(a) != a.length)
600 {
601 return false;
602 }
603 if (a[0] != 1)
604 {
605 return false;
606 }
607
608 int x1 = getShortLittleEndian(a, 2);
609 int y1 = getShortLittleEndian(a, 4);
610 int x2 = getShortLittleEndian(a, 6);
611 int y2 = getShortLittleEndian(a, 8);
612 if (x1 < 0 || x2 < x1 || y1 < 0 || y2 < y1)
613 {
614 return false;
615 }
616 width = x2 - x1 + 1;
617 height = y2 - y1 + 1;
618
619 int bits = a[1];
620 int planes = a[63];
621 if (planes == 1 && (bits == 1 || bits == 2 || bits == 4 || bits == 8))
622 {
623
624 bitsPerPixel = bits;
625 }
626 else if (planes == 3 && bits == 8)
627 {
628
629 bitsPerPixel = 24;
630 }
631 else
632 {
633 return false;
634 }
635 setPhysicalWidthDpi(getShortLittleEndian(a, 10));
636 setPhysicalHeightDpi(getShortLittleEndian(a, 10));
637 format = FORMAT_PCX;
638 return true;
639 }
640
641 private boolean checkPng() throws IOException
642 {
643 final byte[] PNG_MAGIC = { 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
644 byte[] a = new byte[27];
645 if (read(a) != 27)
646 {
647 return false;
648 }
649 if (!equals(a, 0, PNG_MAGIC, 0, 6))
650 {
651 return false;
652 }
653 format = FORMAT_PNG;
654 width = getIntBigEndian(a, 14);
655 height = getIntBigEndian(a, 18);
656 bitsPerPixel = a[22] & 0xff;
657 int colorType = a[23] & 0xff;
658 if (colorType == 2 || colorType == 6)
659 {
660 bitsPerPixel *= 3;
661 }
662 progressive = (a[26] & 0xff) != 0;
663 return true;
664 }
665
666 private boolean checkPnm(int id) throws IOException
667 {
668 if (id < 1 || id > 6)
669 {
670 return false;
671 }
672 final int[] PNM_FORMATS = { FORMAT_PBM, FORMAT_PGM, FORMAT_PPM };
673 format = PNM_FORMATS[(id - 1) % 3];
674 boolean hasPixelResolution = false;
675 String s;
676 while (true)
677 {
678 s = readLine();
679 if (s != null)
680 {
681 s = s.trim();
682 }
683 if (s == null || s.length() < 1)
684 {
685 continue;
686 }
687 if (s.charAt(0) == '#')
688 {
689 if (collectComments && s.length() > 1)
690 {
691 addComment(s.substring(1));
692 }
693 continue;
694 }
695 if (!hasPixelResolution)
696 {
697 int spaceIndex = s.indexOf(' ');
698 if (spaceIndex == -1)
699 {
700 return false;
701 }
702 String widthString = s.substring(0, spaceIndex);
703 spaceIndex = s.lastIndexOf(' ');
704 if (spaceIndex == -1)
705 {
706 return false;
707 }
708 String heightString = s.substring(spaceIndex + 1);
709 try
710 {
711 width = Integer.parseInt(widthString);
712 height = Integer.parseInt(heightString);
713 }
714 catch (NumberFormatException nfe)
715 {
716 return false;
717 }
718 if (width < 1 || height < 1)
719 {
720 return false;
721 }
722 if (format == FORMAT_PBM)
723 {
724 bitsPerPixel = 1;
725 return true;
726 }
727 hasPixelResolution = true;
728 }
729 else
730 {
731 int maxSample;
732 try
733 {
734 maxSample = Integer.parseInt(s);
735 }
736 catch (NumberFormatException nfe)
737 {
738 return false;
739 }
740 if (maxSample < 0)
741 {
742 return false;
743 }
744 for (int i = 0; i < 25; i++)
745 {
746 if (maxSample < (1 << (i + 1)))
747 {
748 bitsPerPixel = i + 1;
749 if (format == FORMAT_PPM)
750 {
751 bitsPerPixel *= 3;
752 }
753 return true;
754 }
755 }
756 return false;
757 }
758 }
759 }
760
761 private boolean checkPsd() throws IOException
762 {
763 byte[] a = new byte[24];
764 if (read(a) != a.length)
765 {
766 return false;
767 }
768 final byte[] PSD_MAGIC = { 0x50, 0x53 };
769 if (!equals(a, 0, PSD_MAGIC, 0, 2))
770 {
771 return false;
772 }
773 format = FORMAT_PSD;
774 width = getIntBigEndian(a, 16);
775 height = getIntBigEndian(a, 12);
776 int channels = getShortBigEndian(a, 10);
777 int depth = getShortBigEndian(a, 20);
778 bitsPerPixel = channels * depth;
779 return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel <= 64);
780 }
781
782 private boolean checkRas() throws IOException
783 {
784 byte[] a = new byte[14];
785 if (read(a) != a.length)
786 {
787 return false;
788 }
789 final byte[] RAS_MAGIC = { 0x6a, (byte) 0x95 };
790 if (!equals(a, 0, RAS_MAGIC, 0, 2))
791 {
792 return false;
793 }
794 format = FORMAT_RAS;
795 width = getIntBigEndian(a, 2);
796 height = getIntBigEndian(a, 6);
797 bitsPerPixel = getIntBigEndian(a, 10);
798 return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel <= 24);
799 }
800
801
802 private boolean checkSwf() throws IOException
803 {
804
805 byte[] a = new byte[6];
806 if (read(a) != a.length)
807 {
808 return false;
809 }
810 format = FORMAT_SWF;
811 int bitSize = (int) readUBits(5);
812 int maxX = readSBits(bitSize);
813 int maxY = readSBits(bitSize);
814 width = maxX / 20;
815 height = maxY / 20;
816 setPhysicalWidthDpi(72);
817 setPhysicalHeightDpi(72);
818 return (width > 0 && height > 0);
819 }
820
821
822
823
824
825
826
827 private static boolean determineVerbosity(String[] args)
828 {
829 if (args != null && args.length > 0)
830 {
831 for (int i = 0; i < args.length; i++)
832 {
833 if ("-c".equals(args[i]))
834 {
835 return false;
836 }
837 }
838 }
839 return true;
840 }
841
842 private static boolean equals(byte[] a1, int offs1, byte[] a2, int offs2, int num)
843 {
844 while (num-- > 0)
845 {
846 if (a1[offs1++] != a2[offs2++])
847 {
848 return false;
849 }
850 }
851 return true;
852 }
853
854
855
856
857
858
859
860 public int getBitsPerPixel()
861 {
862 return bitsPerPixel;
863 }
864
865
866
867
868
869
870
871
872
873
874 public String getComment(int index)
875 {
876 if (comments == null || index < 0 || index >= comments.size())
877 {
878 throw new IllegalArgumentException("Not a valid comment index: " + index);
879 }
880 return (String) comments.elementAt(index);
881 }
882
883
884
885
886
887
888
889 public int getFormat()
890 {
891 return format;
892 }
893
894
895
896
897
898
899
900 public String getFormatName()
901 {
902 if (format >= 0 && format < FORMAT_NAMES.length)
903 {
904 return FORMAT_NAMES[format];
905 }
906 else
907 {
908 return "?";
909 }
910 }
911
912
913
914
915
916
917 public int getHeight()
918 {
919 return height;
920 }
921
922 private static int getIntBigEndian(byte[] a, int offs)
923 {
924 return (a[offs] & 0xff) << 24 | (a[offs + 1] & 0xff) << 16 | (a[offs + 2] & 0xff) << 8 | a[offs + 3] & 0xff;
925 }
926
927 private static int getIntLittleEndian(byte[] a, int offs)
928 {
929 return (a[offs + 3] & 0xff) << 24 | (a[offs + 2] & 0xff) << 16 | (a[offs + 1] & 0xff) << 8 | a[offs] & 0xff;
930 }
931
932
933
934
935
936
937 public String getMimeType()
938 {
939 if (format >= 0 && format < MIME_TYPE_STRINGS.length)
940 {
941 if (format == FORMAT_JPEG && progressive)
942 {
943 return "image/pjpeg";
944 }
945 return MIME_TYPE_STRINGS[format];
946 }
947 else
948 {
949 return null;
950 }
951 }
952
953
954
955
956
957
958
959
960 public int getNumberOfComments()
961 {
962 if (comments == null)
963 {
964 return 0;
965 }
966 else
967 {
968 return comments.size();
969 }
970 }
971
972
973
974
975
976
977
978
979 public int getNumberOfImages()
980 {
981 return numberOfImages;
982 }
983
984
985
986
987
988
989
990
991
992 public int getPhysicalHeightDpi()
993 {
994 return physicalHeightDpi;
995 }
996
997
998
999
1000
1001
1002
1003
1004
1005
1006 public float getPhysicalHeightInch()
1007 {
1008 int h = getHeight();
1009 int ph = getPhysicalHeightDpi();
1010 if (h > 0 && ph > 0)
1011 {
1012 return ((float) h) / ((float) ph);
1013 }
1014 else
1015 {
1016 return -1.0f;
1017 }
1018 }
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029 public int getPhysicalWidthDpi()
1030 {
1031 return physicalWidthDpi;
1032 }
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042 public float getPhysicalWidthInch()
1043 {
1044 int w = getWidth();
1045 int pw = getPhysicalWidthDpi();
1046 if (w > 0 && pw > 0)
1047 {
1048 return ((float) w) / ((float) pw);
1049 }
1050 else
1051 {
1052 return -1.0f;
1053 }
1054 }
1055
1056 private static int getShortBigEndian(byte[] a, int offs)
1057 {
1058 return (a[offs] & 0xff) << 8 | (a[offs + 1] & 0xff);
1059 }
1060
1061 private static int getShortLittleEndian(byte[] a, int offs)
1062 {
1063 return (a[offs] & 0xff) | (a[offs + 1] & 0xff) << 8;
1064 }
1065
1066
1067
1068
1069
1070
1071 public int getWidth()
1072 {
1073 return width;
1074 }
1075
1076
1077
1078
1079
1080
1081 public boolean isProgressive()
1082 {
1083 return progressive;
1084 }
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094 public static void main(String[] args)
1095 {
1096 ImageInfo imageInfo = new ImageInfo();
1097 imageInfo.setDetermineImageNumber(true);
1098 boolean verbose = determineVerbosity(args);
1099 if (args.length == 0)
1100 {
1101 run(null, System.in, imageInfo, verbose);
1102 }
1103 else
1104 {
1105 int index = 0;
1106 while (index < args.length)
1107 {
1108 InputStream in = null;
1109 try
1110 {
1111 String name = args[index++];
1112 System.out.print(name + ";");
1113 if (name.startsWith("http://"))
1114 {
1115 in = new URL(name).openConnection().getInputStream();
1116 }
1117 else
1118 {
1119 in = new FileInputStream(name);
1120 }
1121 run(name, in, imageInfo, verbose);
1122 in.close();
1123 }
1124 catch (IOException e)
1125 {
1126 try
1127 {
1128 in.close();
1129 }
1130 catch (IOException ee)
1131 {
1132 }
1133 }
1134 }
1135 }
1136 }
1137
1138 private static void print(String sourceName, ImageInfo ii, boolean verbose)
1139 {
1140 if (verbose)
1141 {
1142 printVerbose(sourceName, ii);
1143 }
1144 else
1145 {
1146 printCompact(sourceName, ii);
1147 }
1148 }
1149
1150 private static void printCompact(String sourceName, ImageInfo imageInfo)
1151 {
1152 final String SEP = "\t";
1153 System.out.println(sourceName + SEP + imageInfo.getFormatName() + SEP + imageInfo.getMimeType() + SEP
1154 + imageInfo.getWidth() + SEP + imageInfo.getHeight() + SEP + imageInfo.getBitsPerPixel() + SEP
1155 + imageInfo.getNumberOfImages() + SEP + imageInfo.getPhysicalWidthDpi() + SEP
1156 + imageInfo.getPhysicalHeightDpi() + SEP + imageInfo.getPhysicalWidthInch() + SEP
1157 + imageInfo.getPhysicalHeightInch() + SEP + imageInfo.isProgressive());
1158 }
1159
1160 private static void printLine(int indentLevels, String text, float value, float minValidValue)
1161 {
1162 if (value < minValidValue)
1163 {
1164 return;
1165 }
1166 printLine(indentLevels, text, Float.toString(value));
1167 }
1168
1169 private static void printLine(int indentLevels, String text, int value, int minValidValue)
1170 {
1171 if (value >= minValidValue)
1172 {
1173 printLine(indentLevels, text, Integer.toString(value));
1174 }
1175 }
1176
1177 private static void printLine(int indentLevels, String text, String value)
1178 {
1179 if (value == null || value.length() == 0)
1180 {
1181 return;
1182 }
1183 while (indentLevels-- > 0)
1184 {
1185 System.out.print("\t");
1186 }
1187 if (text != null && text.length() > 0)
1188 {
1189 System.out.print(text);
1190 System.out.print(" ");
1191 }
1192 System.out.println(value);
1193 }
1194
1195 private static void printVerbose(String sourceName, ImageInfo ii)
1196 {
1197 printLine(0, null, sourceName);
1198 printLine(1, "File format: ", ii.getFormatName());
1199 printLine(1, "MIME type: ", ii.getMimeType());
1200 printLine(1, "Width (pixels): ", ii.getWidth(), 1);
1201 printLine(1, "Height (pixels): ", ii.getHeight(), 1);
1202 printLine(1, "Bits per pixel: ", ii.getBitsPerPixel(), 1);
1203 printLine(1, "Progressive: ", ii.isProgressive() ? "yes" : "no");
1204 printLine(1, "Number of images: ", ii.getNumberOfImages(), 1);
1205 printLine(1, "Physical width (dpi): ", ii.getPhysicalWidthDpi(), 1);
1206 printLine(1, "Physical height (dpi): ", ii.getPhysicalHeightDpi(), 1);
1207 printLine(1, "Physical width (inches): ", ii.getPhysicalWidthInch(), 1.0f);
1208 printLine(1, "Physical height (inches): ", ii.getPhysicalHeightInch(), 1.0f);
1209 int numComments = ii.getNumberOfComments();
1210 printLine(1, "Number of textual comments: ", numComments, 1);
1211 if (numComments > 0)
1212 {
1213 for (int i = 0; i < numComments; i++)
1214 {
1215 printLine(2, null, ii.getComment(i));
1216 }
1217 }
1218 }
1219
1220 private int read() throws IOException
1221 {
1222 if (in != null)
1223 {
1224 return in.read();
1225 }
1226 else
1227 {
1228 return din.readByte();
1229 }
1230 }
1231
1232 private int read(byte[] a) throws IOException
1233 {
1234 if (in != null)
1235 {
1236 return in.read(a);
1237 }
1238 else
1239 {
1240 din.readFully(a);
1241 return a.length;
1242 }
1243 }
1244
1245 private int read(byte[] a, int offset, int num) throws IOException
1246 {
1247 if (in != null)
1248 {
1249 return in.read(a, offset, num);
1250 }
1251 else
1252 {
1253 din.readFully(a, offset, num);
1254 return num;
1255 }
1256 }
1257
1258 private String readLine() throws IOException
1259 {
1260 return readLine(new StringBuffer());
1261 }
1262
1263 private String readLine(StringBuffer sb) throws IOException
1264 {
1265 boolean finished;
1266 do
1267 {
1268 int value = read();
1269 finished = (value == -1 || value == 10);
1270 if (!finished)
1271 {
1272 sb.append((char) value);
1273 }
1274 }
1275 while (!finished);
1276 return sb.toString();
1277 }
1278
1279 private long readUBits(int numBits) throws IOException
1280 {
1281 if (numBits == 0)
1282 {
1283 return 0;
1284 }
1285 int bitsLeft = numBits;
1286 long result = 0;
1287 if (bitPos == 0)
1288 {
1289 if (in != null)
1290 {
1291 bitBuf = in.read();
1292 }
1293 else
1294 {
1295 bitBuf = din.readByte();
1296 }
1297 bitPos = 8;
1298 }
1299
1300 while (true)
1301 {
1302 int shift = bitsLeft - bitPos;
1303 if (shift > 0)
1304 {
1305
1306 result |= bitBuf << shift;
1307 bitsLeft -= bitPos;
1308
1309
1310 if (in != null)
1311 {
1312 bitBuf = in.read();
1313 }
1314 else
1315 {
1316 bitBuf = din.readByte();
1317 }
1318 bitPos = 8;
1319 }
1320 else
1321 {
1322
1323 result |= bitBuf >> -shift;
1324 bitPos -= bitsLeft;
1325 bitBuf &= 0xff >> (8 - bitPos);
1326
1327 return result;
1328 }
1329 }
1330 }
1331
1332
1333
1334
1335
1336
1337 private int readSBits(int numBits) throws IOException
1338 {
1339
1340 long uBits = readUBits(numBits);
1341
1342
1343 if ((uBits & (1L << (numBits - 1))) != 0)
1344 {
1345
1346 uBits |= -1L << numBits;
1347 }
1348
1349 return (int) uBits;
1350 }
1351
1352 private static void run(String sourceName, InputStream in, ImageInfo imageInfo, boolean verbose)
1353 {
1354 imageInfo.setInput(in);
1355 imageInfo.setDetermineImageNumber(true);
1356 imageInfo.setCollectComments(verbose);
1357 if (imageInfo.check())
1358 {
1359 print(sourceName, imageInfo, verbose);
1360 }
1361 }
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372 public void setCollectComments(boolean newValue)
1373 {
1374 collectComments = newValue;
1375 }
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388 public void setDetermineImageNumber(boolean newValue)
1389 {
1390 determineNumberOfImages = newValue;
1391 }
1392
1393
1394
1395
1396
1397
1398
1399
1400 public void setInput(DataInput dataInput)
1401 {
1402 din = dataInput;
1403 in = null;
1404 }
1405
1406
1407
1408
1409
1410
1411
1412 public void setInput(InputStream inputStream)
1413 {
1414 in = inputStream;
1415 din = null;
1416 }
1417
1418 private void setPhysicalHeightDpi(int newValue)
1419 {
1420 physicalWidthDpi = newValue;
1421 }
1422
1423 private void setPhysicalWidthDpi(int newValue)
1424 {
1425 physicalHeightDpi = newValue;
1426 }
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438 private void skip(int numBytesToSkip) throws IOException
1439 {
1440 for (int bytesSkipped = 0; bytesSkipped < numBytesToSkip; bytesSkipped++)
1441 {
1442 if (read() == -1)
1443 throw new EOFException("Reached end of stream before "
1444 + numBytesToSkip + " bytes could be skipped");
1445 }
1446 }
1447 }