1 31 32 package org.opencms.loader; 33 34 import com.alkacon.simapi.RenderSettings; 35 import com.alkacon.simapi.Simapi; 36 import com.alkacon.simapi.filter.GrayscaleFilter; 37 import com.alkacon.simapi.filter.ShadowFilter; 38 39 import org.opencms.file.CmsFile; 40 import org.opencms.file.CmsObject; 41 import org.opencms.file.CmsProperty; 42 import org.opencms.file.CmsPropertyDefinition; 43 import org.opencms.file.CmsResource; 44 import org.opencms.main.CmsLog; 45 import org.opencms.main.OpenCms; 46 import org.opencms.util.CmsStringUtil; 47 48 import java.awt.Color ; 49 import java.awt.Rectangle ; 50 import java.awt.image.BufferedImage ; 51 import java.util.ArrayList ; 52 import java.util.Arrays ; 53 import java.util.Iterator ; 54 import java.util.List ; 55 56 import javax.servlet.http.HttpServletRequest ; 57 58 import org.apache.commons.logging.Log; 59 60 69 public class CmsImageScaler { 70 71 72 public static final String COLOR_TRANSPARENT = "transparent"; 73 74 75 public static final String FILTER_GRAYSCALE = "grayscale"; 76 77 78 public static final String FILTER_SHADOW = "shadow"; 79 80 81 public static final List FILTERS = Arrays.asList(new String [] {FILTER_GRAYSCALE, FILTER_SHADOW}); 82 83 84 public static final String PARAM_SCALE = "__scale"; 85 86 87 public static final int SCALE_DEFAULT_MAX_BLUR_SIZE = 2500 * 2500; 88 89 90 public static final int SCALE_DEFAULT_MAX_SIZE = 1500; 91 92 93 public static final String SCALE_PARAM_COLOR = "c"; 94 95 96 public static final String SCALE_PARAM_FILTER = "f"; 97 98 99 public static final String SCALE_PARAM_HEIGHT = "h"; 100 101 102 public static final String SCALE_PARAM_POS = "p"; 103 104 105 public static final String SCALE_PARAM_QUALITY = "q"; 106 107 108 public static final String SCALE_PARAM_RENDERMODE = "r"; 109 110 111 public static final String SCALE_PARAM_TYPE = "t"; 112 113 114 public static final String SCALE_PARAM_WIDTH = "w"; 115 116 117 protected static final Log LOG = CmsLog.getLog(CmsImageScaler.class); 118 119 120 private Color m_color; 121 122 123 private List m_filters; 124 125 126 private int m_height; 127 128 129 private int m_maxBlurSize; 130 131 132 private int m_position; 133 134 135 private int m_quality; 136 137 138 private int m_renderMode; 139 140 141 private String m_scaleParameters; 142 143 144 private int m_type; 145 146 147 private int m_width; 148 149 152 public CmsImageScaler() { 153 154 init(); 155 } 156 157 172 public CmsImageScaler(byte[] content, String rootPath) { 173 174 init(); 175 try { 176 BufferedImage image = Simapi.read(content); 178 m_height = image.getHeight(); 179 m_width = image.getWidth(); 180 } catch (Exception e) { 181 if (LOG.isDebugEnabled()) { 183 LOG.debug(Messages.get().getBundle().key(Messages.ERR_UNABLE_TO_EXTRACT_IMAGE_SIZE_1, rootPath), e); 184 } 185 init(); 187 } 188 } 189 190 198 public CmsImageScaler(CmsImageScaler original, CmsImageScaler target) { 199 200 CmsImageScaler scaler = original.getReScaler(target); 201 initValuesFrom(scaler); 202 } 203 204 214 public CmsImageScaler(CmsObject cms, CmsResource res) { 215 216 init(); 217 String sizeValue = null; 218 if ((cms != null) && (res != null)) { 219 try { 220 CmsProperty sizeProp = cms.readPropertyObject(res, CmsPropertyDefinition.PROPERTY_IMAGE_SIZE, false); 221 if (!sizeProp.isNullProperty()) { 222 sizeValue = sizeProp.getValue(); 224 } 225 } catch (Exception e) { 226 } 228 } 229 if (CmsStringUtil.isNotEmpty(sizeValue)) { 230 parseParameters(sizeValue); 231 } 232 } 233 234 241 public CmsImageScaler(HttpServletRequest request, int maxScaleSize, int maxBlurSize) { 242 243 init(); 244 m_maxBlurSize = maxBlurSize; 245 String parameters = request.getParameter(CmsImageScaler.PARAM_SCALE); 246 if (CmsStringUtil.isNotEmpty(parameters)) { 247 parseParameters(parameters); 248 if (isValid()) { 249 if ((getWidth() > maxScaleSize) || (getHeight() > maxScaleSize)) { 251 init(); 253 } 254 } 255 } 256 } 257 258 263 public CmsImageScaler(String parameters) { 264 265 init(); 266 if (CmsStringUtil.isNotEmpty(parameters)) { 267 parseParameters(parameters); 268 } 269 } 270 271 278 protected CmsImageScaler(CmsImageScaler base, int width, int height) { 279 280 initValuesFrom(base); 281 setWidth(width); 282 setHeight(height); 283 } 284 285 290 public void addFilter(String filter) { 291 292 if (CmsStringUtil.isNotEmpty(filter)) { 293 filter = filter.trim().toLowerCase(); 294 if (FILTERS.contains(filter)) { 295 m_filters.add(filter); 296 } 297 } 298 } 299 300 303 public Object clone() { 304 305 CmsImageScaler clone = new CmsImageScaler(); 306 clone.initValuesFrom(this); 307 return clone; 308 } 309 310 315 public Color getColor() { 316 317 return m_color; 318 } 319 320 325 public String getColorString() { 326 327 StringBuffer result = new StringBuffer (); 328 if (m_color == Simapi.COLOR_TRANSPARENT) { 329 result.append(COLOR_TRANSPARENT); 330 } else { 331 if (m_color.getRed() < 16) { 332 result.append('0'); 333 } 334 result.append(Integer.toString(m_color.getRed(), 16)); 335 if (m_color.getGreen() < 16) { 336 result.append('0'); 337 } 338 result.append(Integer.toString(m_color.getGreen(), 16)); 339 if (m_color.getBlue() < 16) { 340 result.append('0'); 341 } 342 result.append(Integer.toString(m_color.getBlue(), 16)); 343 } 344 return result.toString(); 345 } 346 347 359 public CmsImageScaler getDownScaler(CmsImageScaler downScaler) { 360 361 if (!isDownScaleRequired(downScaler)) { 362 return null; 364 } 365 366 int downHeight = downScaler.getHeight(); 367 int downWidth = downScaler.getWidth(); 368 369 int height = getHeight(); 370 int width = getWidth(); 371 372 if (((height > width) && (downHeight < downWidth)) || ((width > height) && (downWidth < downHeight))) { 373 downHeight = downWidth; 375 downWidth = downScaler.getHeight(); 376 } 377 378 if (width > downWidth) { 379 float scale = (float)downWidth / (float)width; 381 downHeight = Math.round(height * scale); 382 } else if (height > downHeight) { 383 float scale = (float)downHeight / (float)height; 385 downWidth = Math.round(width * scale); 386 } else { 387 return null; 389 } 390 391 return new CmsImageScaler(downScaler, downWidth, downHeight); 393 } 394 395 400 public List getFilters() { 401 402 return m_filters; 403 } 404 405 410 public String getFiltersString() { 411 412 StringBuffer result = new StringBuffer (); 413 Iterator i = m_filters.iterator(); 414 while (i.hasNext()) { 415 String filter = (String )i.next(); 416 result.append(filter); 417 if (i.hasNext()) { 418 result.append(':'); 419 } 420 } 421 return result.toString(); 422 } 423 424 429 public int getHeight() { 430 431 return m_height; 432 } 433 434 451 public String getImageType(String filename) { 452 453 return Simapi.getImageType(filename); 454 } 455 456 467 public int getMaxBlurSize() { 468 469 return m_maxBlurSize; 470 } 471 472 479 public int getPixelCount() { 480 481 return m_width * m_height; 482 } 483 484 489 public int getPosition() { 490 491 return m_position; 492 } 493 494 501 public int getQuality() { 502 503 return m_quality; 504 } 505 506 521 public int getRenderMode() { 522 523 return m_renderMode; 524 } 525 526 539 public CmsImageScaler getReScaler(CmsImageScaler target) { 540 541 int height = target.getHeight(); 542 int width = target.getWidth(); 543 544 if ((width > 0) && (getWidth() > 0)) { 545 float scale = (float)width / (float)getWidth(); 547 height = Math.round(getHeight() * scale); 548 } else if ((height > 0) && (getHeight() > 0)) { 549 float scale = (float)height / (float)getHeight(); 551 width = Math.round(getWidth() * scale); 552 } else if (isValid() && !target.isValid()) { 553 width = getWidth(); 555 height = getHeight(); 556 } 557 558 if ((target.getType() == 1) && (!target.isValid())) { 559 if ((target.getWidth() > 0) && (getWidth() < width)) { 561 height = getHeight(); 563 } else if ((target.getHeight() > 0) && (getHeight() < height)) { 564 width = getWidth(); 566 } 567 } 568 569 return new CmsImageScaler(target, width, height); 571 } 572 573 613 public int getType() { 614 615 return m_type; 616 } 617 618 623 public int getWidth() { 624 625 return m_width; 626 } 627 628 641 public CmsImageScaler getWidthScaler(CmsImageScaler downScaler) { 642 643 int width = downScaler.getWidth(); 644 int height; 645 646 if (getWidth() > width) { 647 float scale = (float)width / (float)getWidth(); 649 height = Math.round(getHeight() * scale); 650 } else { 651 width = getWidth(); 653 height = getHeight(); 654 } 655 656 return new CmsImageScaler(downScaler, width, height); 658 } 659 660 663 public int hashCode() { 664 665 return toString().hashCode(); 666 } 667 668 686 public boolean isDownScaleRequired(CmsImageScaler downScaler) { 687 688 if ((downScaler == null) || !isValid() || !downScaler.isValid()) { 689 return false; 691 } 692 693 if (getPixelCount() < (downScaler.getPixelCount() / 2)) { 694 return false; 696 } 697 698 int downWidth = downScaler.getWidth(); 699 int downHeight = downScaler.getHeight(); 700 if (downHeight > downWidth) { 701 downWidth = downHeight; 703 downHeight = downScaler.getWidth(); 704 } 705 int height = getHeight(); 706 int width = getWidth(); 707 if (height > width) { 708 width = height; 710 height = getWidth(); 711 } 712 713 return (width > downWidth) || (height > downHeight); 714 } 715 716 723 public boolean isValid() { 724 725 return (m_width > 0) && (m_height > 0); 726 } 727 728 736 public byte[] scaleImage(byte[] content, String rootPath) { 737 738 byte[] result = content; 739 740 RenderSettings renderSettings; 741 if ((m_renderMode == 0) && (m_quality == 0)) { 742 renderSettings = new RenderSettings(Simapi.RENDER_QUALITY); 744 } else { 745 renderSettings = new RenderSettings(m_renderMode); 747 if (m_quality != 0) { 748 renderSettings.setCompressionQuality(m_quality / 100f); 749 } 750 } 751 renderSettings.setMaximumBlurSize(m_maxBlurSize); 753 Simapi scaler = new Simapi(renderSettings); 755 String imageType = Simapi.getImageType(rootPath); 757 if (imageType == null) { 758 String mimeType = OpenCms.getResourceManager().getMimeType(rootPath, null, null); 760 if (mimeType == null) { 762 imageType = Simapi.TYPE_JPEG; 764 } 765 } 766 if (imageType == null) { 767 if (LOG.isDebugEnabled()) { 769 LOG.debug(Messages.get().getBundle().key(Messages.ERR_UNABLE_TO_SCALE_IMAGE_2, rootPath, toString())); 770 } 771 return result; 772 } 773 try { 774 BufferedImage image = Simapi.read(content); 775 776 Color color = getColor(); 777 778 if (!m_filters.isEmpty()) { 779 Iterator i = m_filters.iterator(); 780 while (i.hasNext()) { 781 String filter = (String )i.next(); 782 if (FILTER_GRAYSCALE.equals(filter)) { 783 GrayscaleFilter grayscaleFilter = new GrayscaleFilter(); 785 renderSettings.addImageFilter(grayscaleFilter); 786 } else if (FILTER_SHADOW.equals(filter)) { 787 ShadowFilter shadowFilter = new ShadowFilter(); 789 shadowFilter.setXOffset(5); 790 shadowFilter.setYOffset(5); 791 shadowFilter.setOpacity(192); 792 shadowFilter.setBackgroundColor(color.getRGB()); 793 color = Simapi.COLOR_TRANSPARENT; 794 renderSettings.setTransparentReplaceColor(Simapi.COLOR_TRANSPARENT); 795 renderSettings.addImageFilter(shadowFilter); 796 } 797 } 798 } 799 800 switch (getType()) { 801 case 1: 803 image = scaler.resize(image, getWidth(), getHeight(), color, getPosition(), false); 805 break; 806 case 2: 807 image = scaler.resize(image, getWidth(), getHeight(), getPosition()); 809 break; 810 case 3: 811 image = scaler.resize(image, getWidth(), getHeight(), true); 813 break; 814 case 4: 815 image = scaler.resize(image, getWidth(), getHeight(), false); 817 break; 818 default: 819 image = scaler.resize(image, getWidth(), getHeight(), color, getPosition(), true); 821 } 822 823 if (!m_filters.isEmpty()) { 824 Rectangle targetSize = scaler.applyFilterDimensions(getWidth(), getHeight()); 825 image = scaler.resize( 826 image, 827 (int)targetSize.getWidth(), 828 (int)targetSize.getHeight(), 829 Simapi.COLOR_TRANSPARENT, 830 Simapi.POS_CENTER); 831 image = scaler.applyFilters(image); 832 } 833 834 result = scaler.getBytes(image, imageType); 836 } catch (Exception e) { 837 if (LOG.isDebugEnabled()) { 838 LOG.debug(Messages.get().getBundle().key(Messages.ERR_UNABLE_TO_SCALE_IMAGE_2, rootPath, toString()), e); 839 } 840 } 841 return result; 842 } 843 844 851 public byte[] scaleImage(CmsFile file) { 852 853 return scaleImage(file.getContents(), file.getRootPath()); 854 } 855 856 861 public void setColor(Color color) { 862 863 m_color = color; 864 } 865 866 871 public void setColor(String value) { 872 873 if (COLOR_TRANSPARENT.indexOf(value) == 0) { 874 setColor(Simapi.COLOR_TRANSPARENT); 875 } else { 876 setColor(CmsStringUtil.getColorValue(value, Color.WHITE, SCALE_PARAM_COLOR)); 877 } 878 } 879 880 885 public void setFilters(String value) { 886 887 m_filters = new ArrayList (); 888 List filters = CmsStringUtil.splitAsList(value, ':'); 889 Iterator i = filters.iterator(); 890 while (i.hasNext()) { 891 String filter = (String )i.next(); 892 filter = filter.trim().toLowerCase(); 893 Iterator j = FILTERS.iterator(); 894 while (j.hasNext()) { 895 String candidate = (String )j.next(); 896 if (candidate.startsWith(filter)) { 897 addFilter(candidate); 899 break; 900 } 901 } 902 } 903 } 904 905 910 public void setHeight(int height) { 911 912 m_height = height; 913 } 914 915 922 public void setMaxBlurSize(int maxBlurSize) { 923 924 m_maxBlurSize = maxBlurSize; 925 } 926 927 932 public void setPosition(int position) { 933 934 switch (position) { 935 case Simapi.POS_DOWN_LEFT: 936 case Simapi.POS_DOWN_RIGHT: 937 case Simapi.POS_STRAIGHT_DOWN: 938 case Simapi.POS_STRAIGHT_LEFT: 939 case Simapi.POS_STRAIGHT_RIGHT: 940 case Simapi.POS_STRAIGHT_UP: 941 case Simapi.POS_UP_LEFT: 942 case Simapi.POS_UP_RIGHT: 943 m_position = position; 945 break; 946 default: 947 m_position = Simapi.POS_CENTER; 948 } 949 } 950 951 956 public void setQuality(int quality) { 957 958 if (quality < 0) { 959 m_quality = 0; 960 } else if (quality > 100) { 961 m_quality = 100; 962 } else { 963 m_quality = quality; 964 } 965 } 966 967 974 public void setRenderMode(int renderMode) { 975 976 if ((renderMode < Simapi.RENDER_QUALITY) || (renderMode > Simapi.RENDER_SPEED)) { 977 renderMode = Simapi.RENDER_QUALITY; 978 } 979 m_renderMode = renderMode; 980 } 981 982 989 public void setType(int type) { 990 991 if ((type < 0) || (type > 4)) { 992 m_type = 0; 994 } else { 995 m_type = type; 996 } 997 } 998 999 1004 public void setWidth(int width) { 1005 1006 m_width = width; 1007 } 1008 1009 1017 public String toRequestParam() { 1018 1019 StringBuffer result = new StringBuffer (128); 1020 result.append('?'); 1021 result.append(PARAM_SCALE); 1022 result.append('='); 1023 result.append(toString()); 1024 1025 return result.toString(); 1026 } 1027 1028 1031 public String toString() { 1032 1033 if (m_scaleParameters != null) { 1034 return m_scaleParameters; 1035 } 1036 1037 StringBuffer result = new StringBuffer (64); 1038 result.append(CmsImageScaler.SCALE_PARAM_WIDTH); 1039 result.append(':'); 1040 result.append(m_width); 1041 result.append(','); 1042 result.append(CmsImageScaler.SCALE_PARAM_HEIGHT); 1043 result.append(':'); 1044 result.append(m_height); 1045 if (m_type > 0) { 1046 result.append(','); 1047 result.append(CmsImageScaler.SCALE_PARAM_TYPE); 1048 result.append(':'); 1049 result.append(m_type); 1050 } 1051 if (m_position > 0) { 1052 result.append(','); 1053 result.append(CmsImageScaler.SCALE_PARAM_POS); 1054 result.append(':'); 1055 result.append(m_position); 1056 } 1057 if (m_color != Color.WHITE) { 1058 result.append(','); 1059 result.append(CmsImageScaler.SCALE_PARAM_COLOR); 1060 result.append(':'); 1061 result.append(getColorString()); 1062 } 1063 if (m_quality > 0) { 1064 result.append(','); 1065 result.append(CmsImageScaler.SCALE_PARAM_QUALITY); 1066 result.append(':'); 1067 result.append(m_quality); 1068 } 1069 if (m_renderMode > 0) { 1070 result.append(','); 1071 result.append(CmsImageScaler.SCALE_PARAM_RENDERMODE); 1072 result.append(':'); 1073 result.append(m_renderMode); 1074 } 1075 if (!m_filters.isEmpty()) { 1076 result.append(','); 1077 result.append(CmsImageScaler.SCALE_PARAM_FILTER); 1078 result.append(':'); 1079 result.append(getFiltersString()); 1080 } 1081 m_scaleParameters = result.toString(); 1082 return m_scaleParameters; 1083 } 1084 1085 1088 private void init() { 1089 1090 m_height = -1; 1091 m_width = -1; 1092 m_type = 0; 1093 m_position = 0; 1094 m_renderMode = 0; 1095 m_quality = 0; 1096 m_color = Color.WHITE; 1097 m_filters = new ArrayList (); 1098 m_maxBlurSize = CmsImageLoader.getMaxBlurSize(); 1099 } 1100 1101 1106 private void initValuesFrom(CmsImageScaler source) { 1107 1108 m_width = source.m_width; 1109 m_height = source.m_height; 1110 m_type = source.m_type; 1111 m_position = source.m_position; 1112 m_renderMode = source.m_renderMode; 1113 m_quality = source.m_quality; 1114 m_color = source.m_color; 1115 m_filters = new ArrayList (source.m_filters); 1116 m_maxBlurSize = source.m_maxBlurSize; 1117 } 1118 1119 1124 private void parseParameters(String parameters) { 1125 1126 m_width = -1; 1127 m_height = -1; 1128 m_position = 0; 1129 m_type = 0; 1130 m_color = Color.WHITE; 1131 1132 List tokens = CmsStringUtil.splitAsList(parameters, ','); 1133 Iterator it = tokens.iterator(); 1134 String k; 1135 String v; 1136 while (it.hasNext()) { 1137 String t = (String )it.next(); 1138 k = null; 1140 v = null; 1141 int idx = t.indexOf(':'); 1142 if (idx >= 0) { 1143 k = t.substring(0, idx).trim(); 1144 if (t.length() > idx) { 1145 v = t.substring(idx + 1).trim(); 1146 } 1147 } 1148 if (CmsStringUtil.isNotEmpty(k) && CmsStringUtil.isNotEmpty(v)) { 1149 if (SCALE_PARAM_HEIGHT.equals(k)) { 1151 m_height = CmsStringUtil.getIntValue(v, Integer.MIN_VALUE, k); 1153 } else if (SCALE_PARAM_WIDTH.equals(k)) { 1154 m_width = CmsStringUtil.getIntValue(v, Integer.MIN_VALUE, k); 1156 } else if (SCALE_PARAM_TYPE.equals(k)) { 1157 setType(CmsStringUtil.getIntValue(v, -1, CmsImageScaler.SCALE_PARAM_TYPE)); 1159 } else if (SCALE_PARAM_COLOR.equals(k)) { 1160 setColor(v); 1162 } else if (SCALE_PARAM_POS.equals(k)) { 1163 setPosition(CmsStringUtil.getIntValue(v, -1, CmsImageScaler.SCALE_PARAM_POS)); 1165 } else if (SCALE_PARAM_QUALITY.equals(k)) { 1166 setQuality(CmsStringUtil.getIntValue(v, 0, k)); 1168 } else if (SCALE_PARAM_RENDERMODE.equals(k)) { 1169 setRenderMode(CmsStringUtil.getIntValue(v, 0, k)); 1171 } else if (SCALE_PARAM_FILTER.equals(k)) { 1172 setFilters(v); 1174 } else { 1175 if (LOG.isDebugEnabled()) { 1176 LOG.debug(Messages.get().getBundle().key(Messages.ERR_INVALID_IMAGE_SCALE_PARAMS_2, k, v)); 1177 } 1178 } 1179 } else { 1180 if (LOG.isDebugEnabled()) { 1181 LOG.debug(Messages.get().getBundle().key(Messages.ERR_INVALID_IMAGE_SCALE_PARAMS_2, k, v)); 1182 } 1183 } 1184 } 1185 } 1186} | Popular Tags |