1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.gallery3d.filtershow.pipeline; 18 19 import android.graphics.Bitmap; 20 import android.graphics.Rect; 21 import android.support.v8.renderscript.Allocation; 22 import android.util.JsonReader; 23 import android.util.JsonWriter; 24 import android.util.Log; 25 26 import com.android.gallery3d.R; 27 import com.android.gallery3d.filtershow.cache.BitmapCache; 28 import com.android.gallery3d.filtershow.cache.ImageLoader; 29 import com.android.gallery3d.filtershow.filters.BaseFiltersManager; 30 import com.android.gallery3d.filtershow.filters.FilterCropRepresentation; 31 import com.android.gallery3d.filtershow.filters.FilterFxRepresentation; 32 import com.android.gallery3d.filtershow.filters.FilterImageBorderRepresentation; 33 import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation; 34 import com.android.gallery3d.filtershow.filters.FilterRepresentation; 35 import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation; 36 import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation; 37 import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; 38 import com.android.gallery3d.filtershow.filters.FiltersManager; 39 import com.android.gallery3d.filtershow.filters.ImageFilter; 40 import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils; 41 import com.android.gallery3d.filtershow.imageshow.MasterImage; 42 import com.android.gallery3d.filtershow.state.State; 43 import com.android.gallery3d.filtershow.state.StateAdapter; 44 45 import java.io.IOException; 46 import java.io.StringReader; 47 import java.io.StringWriter; 48 import java.util.ArrayList; 49 import java.util.Collection; 50 import java.util.Vector; 51 52 public class ImagePreset { 53 54 private static final String LOGTAG = "ImagePreset"; 55 public static final String JASON_SAVED = "Saved"; 56 57 private Vector<FilterRepresentation> mFilters = new Vector<FilterRepresentation>(); 58 59 private boolean mDoApplyGeometry = true; 60 private boolean mDoApplyFilters = true; 61 62 private boolean mPartialRendering = false; 63 private Rect mPartialRenderingBounds; 64 private static final boolean DEBUG = false; 65 66 public ImagePreset() { 67 } 68 69 public ImagePreset(ImagePreset source) { 70 for (int i = 0; i < source.mFilters.size(); i++) { 71 FilterRepresentation sourceRepresentation = source.mFilters.elementAt(i); 72 mFilters.add(sourceRepresentation.copy()); 73 } 74 } 75 76 public Vector<FilterRepresentation> getFilters() { 77 return mFilters; 78 } 79 80 public FilterRepresentation getFilterRepresentation(int position) { 81 FilterRepresentation representation = null; 82 83 representation = mFilters.elementAt(position).copy(); 84 85 return representation; 86 } 87 88 private static boolean sameSerializationName(String a, String b) { 89 if (a != null && b != null) { 90 return a.equals(b); 91 } else { 92 return a == null && b == null; 93 } 94 } 95 96 public static boolean sameSerializationName(FilterRepresentation a, FilterRepresentation b) { 97 if (a == null || b == null) { 98 return false; 99 } 100 return sameSerializationName(a.getSerializationName(), b.getSerializationName()); 101 } 102 103 public int getPositionForRepresentation(FilterRepresentation representation) { 104 for (int i = 0; i < mFilters.size(); i++) { 105 if (sameSerializationName(mFilters.elementAt(i), representation)) { 106 return i; 107 } 108 } 109 return -1; 110 } 111 112 private FilterRepresentation getFilterRepresentationForType(int type) { 113 for (int i = 0; i < mFilters.size(); i++) { 114 if (mFilters.elementAt(i).getFilterType() == type) { 115 return mFilters.elementAt(i); 116 } 117 } 118 return null; 119 } 120 121 public int getPositionForType(int type) { 122 for (int i = 0; i < mFilters.size(); i++) { 123 if (mFilters.elementAt(i).getFilterType() == type) { 124 return i; 125 } 126 } 127 return -1; 128 } 129 130 public FilterRepresentation getFilterRepresentationCopyFrom( 131 FilterRepresentation filterRepresentation) { 132 // TODO: add concept of position in the filters (to allow multiple instances) 133 if (filterRepresentation == null) { 134 return null; 135 } 136 int position = getPositionForRepresentation(filterRepresentation); 137 if (position == -1) { 138 return null; 139 } 140 FilterRepresentation representation = mFilters.elementAt(position); 141 if (representation != null) { 142 representation = representation.copy(); 143 } 144 return representation; 145 } 146 147 public void updateFilterRepresentations(Collection<FilterRepresentation> reps) { 148 for (FilterRepresentation r : reps) { 149 updateOrAddFilterRepresentation(r); 150 } 151 } 152 153 public void updateOrAddFilterRepresentation(FilterRepresentation rep) { 154 int pos = getPositionForRepresentation(rep); 155 if (pos != -1) { 156 mFilters.elementAt(pos).useParametersFrom(rep); 157 } else { 158 addFilter(rep.copy()); 159 } 160 } 161 162 public void setDoApplyGeometry(boolean value) { 163 mDoApplyGeometry = value; 164 } 165 166 public void setDoApplyFilters(boolean value) { 167 mDoApplyFilters = value; 168 } 169 170 public boolean getDoApplyFilters() { 171 return mDoApplyFilters; 172 } 173 174 public boolean hasModifications() { 175 for (int i = 0; i < mFilters.size(); i++) { 176 FilterRepresentation filter = mFilters.elementAt(i); 177 if (!filter.isNil()) { 178 return true; 179 } 180 } 181 return false; 182 } 183 184 public boolean contains(byte type) { 185 for (FilterRepresentation representation : mFilters) { 186 if (representation.getFilterType() == type 187 && !representation.isNil()) { 188 return true; 189 } 190 } 191 return false; 192 } 193 194 public boolean isPanoramaSafe() { 195 for (FilterRepresentation representation : mFilters) { 196 if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY 197 && !representation.isNil()) { 198 return false; 199 } 200 if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER 201 && !representation.isNil()) { 202 return false; 203 } 204 if (representation.getFilterType() == FilterRepresentation.TYPE_VIGNETTE 205 && !representation.isNil()) { 206 return false; 207 } 208 if (representation.getFilterType() == FilterRepresentation.TYPE_TINYPLANET 209 && !representation.isNil()) { 210 return false; 211 } 212 } 213 return true; 214 } 215 216 public boolean same(ImagePreset preset) { 217 if (preset == null) { 218 return false; 219 } 220 221 if (preset.mFilters.size() != mFilters.size()) { 222 return false; 223 } 224 225 if (mDoApplyGeometry != preset.mDoApplyGeometry) { 226 return false; 227 } 228 229 if (mDoApplyFilters != preset.mDoApplyFilters) { 230 if (mFilters.size() > 0 || preset.mFilters.size() > 0) { 231 return false; 232 } 233 } 234 235 if (mDoApplyFilters && preset.mDoApplyFilters) { 236 for (int i = 0; i < preset.mFilters.size(); i++) { 237 FilterRepresentation a = preset.mFilters.elementAt(i); 238 FilterRepresentation b = mFilters.elementAt(i); 239 240 if (!a.same(b)) { 241 return false; 242 } 243 } 244 } 245 246 return true; 247 } 248 249 public boolean equals(ImagePreset preset) { 250 if (preset == null) { 251 return false; 252 } 253 254 if (preset.mFilters.size() != mFilters.size()) { 255 return false; 256 } 257 258 if (mDoApplyGeometry != preset.mDoApplyGeometry) { 259 return false; 260 } 261 262 if (mDoApplyFilters != preset.mDoApplyFilters) { 263 if (mFilters.size() > 0 || preset.mFilters.size() > 0) { 264 return false; 265 } 266 } 267 268 for (int i = 0; i < preset.mFilters.size(); i++) { 269 FilterRepresentation a = preset.mFilters.elementAt(i); 270 FilterRepresentation b = mFilters.elementAt(i); 271 boolean isGeometry = false; 272 if (a instanceof FilterRotateRepresentation 273 || a instanceof FilterMirrorRepresentation 274 || a instanceof FilterCropRepresentation 275 || a instanceof FilterStraightenRepresentation) { 276 isGeometry = true; 277 } 278 boolean evaluate = true; 279 if (!isGeometry && mDoApplyGeometry && !mDoApplyFilters) { 280 evaluate = false; 281 } else if (isGeometry && !mDoApplyGeometry && mDoApplyFilters) { 282 evaluate = false; 283 } 284 if (evaluate && !a.equals(b)) { 285 return false; 286 } 287 } 288 289 return true; 290 } 291 292 public int similarUpTo(ImagePreset preset) { 293 for (int i = 0; i < preset.mFilters.size(); i++) { 294 FilterRepresentation a = preset.mFilters.elementAt(i); 295 if (i < mFilters.size()) { 296 FilterRepresentation b = mFilters.elementAt(i); 297 if (!a.same(b)) { 298 return i; 299 } 300 if (!a.equals(b)) { 301 return i; 302 } 303 } else { 304 return i; 305 } 306 } 307 return preset.mFilters.size(); 308 } 309 310 public void showFilters() { 311 Log.v(LOGTAG, "\\\\\\ showFilters -- " + mFilters.size() + " filters"); 312 int n = 0; 313 for (FilterRepresentation representation : mFilters) { 314 Log.v(LOGTAG, " filter " + n + " : " + representation.toString()); 315 n++; 316 } 317 Log.v(LOGTAG, "/// showFilters -- " + mFilters.size() + " filters"); 318 } 319 320 public FilterRepresentation getLastRepresentation() { 321 if (mFilters.size() > 0) { 322 return mFilters.lastElement(); 323 } 324 return null; 325 } 326 327 public void removeFilter(FilterRepresentation filterRepresentation) { 328 if (filterRepresentation.getFilterType() == FilterRepresentation.TYPE_BORDER) { 329 for (int i = 0; i < mFilters.size(); i++) { 330 if (mFilters.elementAt(i).getFilterType() 331 == filterRepresentation.getFilterType()) { 332 mFilters.remove(i); 333 break; 334 } 335 } 336 } else { 337 for (int i = 0; i < mFilters.size(); i++) { 338 if (sameSerializationName(mFilters.elementAt(i), filterRepresentation)) { 339 mFilters.remove(i); 340 break; 341 } 342 } 343 } 344 } 345 346 // If the filter is an "None" effect or border, then just don't add this filter. 347 public void addFilter(FilterRepresentation representation) { 348 if (representation instanceof FilterUserPresetRepresentation) { 349 ImagePreset preset = ((FilterUserPresetRepresentation) representation).getImagePreset(); 350 if (preset.nbFilters() == 1 351 && preset.contains(FilterRepresentation.TYPE_FX)) { 352 FilterRepresentation rep = preset.getFilterRepresentationForType( 353 FilterRepresentation.TYPE_FX); 354 addFilter(rep); 355 } else { 356 // user preset replaces everything 357 mFilters.clear(); 358 for (int i = 0; i < preset.nbFilters(); i++) { 359 addFilter(preset.getFilterRepresentation(i)); 360 } 361 } 362 } else if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { 363 // Add geometry filter, removing duplicates and do-nothing operations. 364 for (int i = 0; i < mFilters.size(); i++) { 365 if (sameSerializationName(representation, mFilters.elementAt(i))) { 366 mFilters.remove(i); 367 } 368 } 369 int index = 0; 370 for (; index < mFilters.size(); index++) { 371 FilterRepresentation rep = mFilters.elementAt(index); 372 if (rep.getFilterType() != FilterRepresentation.TYPE_GEOMETRY) { 373 break; 374 } 375 } 376 if (!representation.isNil()) { 377 mFilters.insertElementAt(representation, index); 378 } 379 } else if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) { 380 removeFilter(representation); 381 if (!isNoneBorderFilter(representation)) { 382 mFilters.add(representation); 383 } 384 } else if (representation.getFilterType() == FilterRepresentation.TYPE_FX) { 385 boolean replaced = false; 386 for (int i = 0; i < mFilters.size(); i++) { 387 FilterRepresentation current = mFilters.elementAt(i); 388 if (current.getFilterType() == FilterRepresentation.TYPE_FX) { 389 mFilters.remove(i); 390 replaced = true; 391 if (!isNoneFxFilter(representation)) { 392 mFilters.add(i, representation); 393 } 394 break; 395 } 396 } 397 if (!replaced) { 398 mFilters.add(0, representation); 399 } 400 } else { 401 mFilters.add(representation); 402 } 403 // Enforces Filter type ordering for borders 404 FilterRepresentation border = null; 405 for (int i = 0; i < mFilters.size();) { 406 FilterRepresentation rep = mFilters.elementAt(i); 407 if (rep.getFilterType() == FilterRepresentation.TYPE_BORDER) { 408 border = rep; 409 mFilters.remove(i); 410 continue; 411 } 412 i++; 413 } 414 if (border != null) { 415 mFilters.add(border); 416 } 417 } 418 419 private boolean isNoneBorderFilter(FilterRepresentation representation) { 420 return representation instanceof FilterImageBorderRepresentation && 421 ((FilterImageBorderRepresentation) representation).getDrawableResource() == 0; 422 } 423 424 private boolean isNoneFxFilter(FilterRepresentation representation) { 425 return representation instanceof FilterFxRepresentation && 426 ((FilterFxRepresentation) representation).getNameResource() == R.string.none; 427 } 428 429 public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) { 430 for (int i = 0; i < mFilters.size(); i++) { 431 FilterRepresentation representation = mFilters.elementAt(i); 432 if (sameSerializationName(representation, filterRepresentation)) { 433 return representation; 434 } 435 } 436 return null; 437 } 438 439 public Bitmap apply(Bitmap original, FilterEnvironment environment) { 440 Bitmap bitmap = original; 441 bitmap = applyFilters(bitmap, -1, -1, environment); 442 return applyBorder(bitmap, environment); 443 } 444 445 public Collection<FilterRepresentation> getGeometryFilters() { 446 ArrayList<FilterRepresentation> geometry = new ArrayList<FilterRepresentation>(); 447 for (FilterRepresentation r : mFilters) { 448 if (r.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { 449 geometry.add(r); 450 } 451 } 452 return geometry; 453 } 454 455 public FilterRepresentation getFilterWithSerializationName(String serializationName) { 456 for (FilterRepresentation r : mFilters) { 457 if (r != null) { 458 if (sameSerializationName(r.getSerializationName(), serializationName)) { 459 return r.copy(); 460 } 461 } 462 } 463 return null; 464 } 465 466 public Rect finalGeometryRect(int width, int height) { 467 return GeometryMathUtils.finalGeometryRect(width, height, getGeometryFilters()); 468 } 469 470 public Bitmap applyGeometry(Bitmap bitmap, FilterEnvironment environment) { 471 // Apply any transform -- 90 rotate, flip, straighten, crop 472 // Returns a new bitmap. 473 if (mDoApplyGeometry) { 474 Bitmap bmp = GeometryMathUtils.applyGeometryRepresentations( 475 getGeometryFilters(), bitmap); 476 if (bmp != bitmap) { 477 environment.cache(bitmap); 478 } 479 return bmp; 480 } 481 return bitmap; 482 } 483 484 public Bitmap applyBorder(Bitmap bitmap, FilterEnvironment environment) { 485 // get the border from the list of filters. 486 FilterRepresentation border = getFilterRepresentationForType( 487 FilterRepresentation.TYPE_BORDER); 488 if (border != null && mDoApplyGeometry) { 489 bitmap = environment.applyRepresentation(border, bitmap); 490 if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) { 491 } 492 } 493 return bitmap; 494 } 495 496 public int nbFilters() { 497 return mFilters.size(); 498 } 499 500 public Bitmap applyFilters(Bitmap bitmap, int from, int to, FilterEnvironment environment) { 501 if (mDoApplyFilters) { 502 if (from < 0) { 503 from = 0; 504 } 505 if (to == -1) { 506 to = mFilters.size(); 507 } 508 for (int i = from; i < to; i++) { 509 FilterRepresentation representation = mFilters.elementAt(i); 510 if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { 511 // skip the geometry as it's already applied. 512 continue; 513 } 514 if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) { 515 // for now, let's skip the border as it will be applied in 516 // applyBorder() 517 // TODO: might be worth getting rid of applyBorder. 518 continue; 519 } 520 Bitmap tmp = bitmap; 521 bitmap = environment.applyRepresentation(representation, bitmap); 522 if (tmp != bitmap) { 523 environment.cache(tmp); 524 } 525 if (environment.needsStop()) { 526 return bitmap; 527 } 528 } 529 } 530 531 return bitmap; 532 } 533 534 public void applyBorder(Allocation in, Allocation out, 535 boolean copyOut, FilterEnvironment environment) { 536 FilterRepresentation border = getFilterRepresentationForType( 537 FilterRepresentation.TYPE_BORDER); 538 if (border != null && mDoApplyGeometry) { 539 // TODO: should keep the bitmap around 540 Allocation bitmapIn = in; 541 if (copyOut) { 542 bitmapIn = Allocation.createTyped( 543 CachingPipeline.getRenderScriptContext(), in.getType()); 544 bitmapIn.copyFrom(out); 545 } 546 environment.applyRepresentation(border, bitmapIn, out); 547 } 548 } 549 550 public void applyFilters(int from, int to, Allocation in, Allocation out, 551 FilterEnvironment environment) { 552 if (mDoApplyFilters) { 553 if (from < 0) { 554 from = 0; 555 } 556 if (to == -1) { 557 to = mFilters.size(); 558 } 559 for (int i = from; i < to; i++) { 560 FilterRepresentation representation = mFilters.elementAt(i); 561 if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY 562 || representation.getFilterType() == FilterRepresentation.TYPE_BORDER) { 563 continue; 564 } 565 if (i > from) { 566 in.copyFrom(out); 567 } 568 environment.applyRepresentation(representation, in, out); 569 } 570 } 571 } 572 573 public boolean canDoPartialRendering() { 574 if (MasterImage.getImage().getZoomOrientation() != ImageLoader.ORI_NORMAL) { 575 return false; 576 } 577 for (int i = 0; i < mFilters.size(); i++) { 578 FilterRepresentation representation = mFilters.elementAt(i); 579 if (!representation.supportsPartialRendering()) { 580 return false; 581 } 582 } 583 return true; 584 } 585 586 public void fillImageStateAdapter(StateAdapter imageStateAdapter) { 587 if (imageStateAdapter == null) { 588 return; 589 } 590 Vector<State> states = new Vector<State>(); 591 for (FilterRepresentation filter : mFilters) { 592 if (filter instanceof FilterUserPresetRepresentation) { 593 // do not show the user preset itself in the state panel 594 continue; 595 } 596 State state = new State(filter.getName()); 597 state.setFilterRepresentation(filter); 598 states.add(state); 599 } 600 imageStateAdapter.fill(states); 601 } 602 603 public void setPartialRendering(boolean partialRendering, Rect bounds) { 604 mPartialRendering = partialRendering; 605 mPartialRenderingBounds = bounds; 606 } 607 608 public boolean isPartialRendering() { 609 return mPartialRendering; 610 } 611 612 public Rect getPartialRenderingBounds() { 613 return mPartialRenderingBounds; 614 } 615 616 public Vector<ImageFilter> getUsedFilters(BaseFiltersManager filtersManager) { 617 Vector<ImageFilter> usedFilters = new Vector<ImageFilter>(); 618 for (int i = 0; i < mFilters.size(); i++) { 619 FilterRepresentation representation = mFilters.elementAt(i); 620 ImageFilter filter = filtersManager.getFilterForRepresentation(representation); 621 usedFilters.add(filter); 622 } 623 return usedFilters; 624 } 625 626 public String getJsonString(String name) { 627 StringWriter swriter = new StringWriter(); 628 try { 629 JsonWriter writer = new JsonWriter(swriter); 630 writeJson(writer, name); 631 writer.close(); 632 } catch (IOException e) { 633 return null; 634 } 635 return swriter.toString(); 636 } 637 638 public void writeJson(JsonWriter writer, String name) { 639 int numFilters = mFilters.size(); 640 try { 641 writer.beginObject(); 642 for (int i = 0; i < numFilters; i++) { 643 FilterRepresentation filter = mFilters.get(i); 644 if (filter instanceof FilterUserPresetRepresentation) { 645 continue; 646 } 647 String sname = filter.getSerializationName(); 648 if (DEBUG) { 649 Log.v(LOGTAG, "Serialization: " + sname); 650 if (sname == null) { 651 Log.v(LOGTAG, "Serialization name null for filter: " + filter); 652 } 653 } 654 writer.name(sname); 655 filter.serializeRepresentation(writer); 656 } 657 writer.endObject(); 658 659 } catch (IOException e) { 660 Log.e(LOGTAG,"Error encoding JASON",e); 661 } 662 } 663 664 /** 665 * populates preset from JSON string 666 * 667 * @param filterString a JSON string 668 * @return true on success if false ImagePreset is undefined 669 */ 670 public boolean readJsonFromString(String filterString) { 671 if (DEBUG) { 672 Log.v(LOGTAG, "reading preset: \"" + filterString + "\""); 673 } 674 StringReader sreader = new StringReader(filterString); 675 try { 676 JsonReader reader = new JsonReader(sreader); 677 boolean ok = readJson(reader); 678 if (!ok) { 679 reader.close(); 680 return false; 681 } 682 reader.close(); 683 } catch (Exception e) { 684 Log.e(LOGTAG, "\""+filterString+"\""); 685 Log.e(LOGTAG, "parsing the filter parameters:", e); 686 return false; 687 } 688 return true; 689 } 690 691 /** 692 * populates preset from JSON stream 693 * 694 * @param sreader a JSON string 695 * @return true on success if false ImagePreset is undefined 696 */ 697 public boolean readJson(JsonReader sreader) throws IOException { 698 sreader.beginObject(); 699 700 while (sreader.hasNext()) { 701 String name = sreader.nextName(); 702 FilterRepresentation filter = creatFilterFromName(name); 703 if (filter == null) { 704 Log.w(LOGTAG, "UNKNOWN FILTER! " + name); 705 return false; 706 } 707 filter.deSerializeRepresentation(sreader); 708 addFilter(filter); 709 } 710 sreader.endObject(); 711 return true; 712 } 713 714 FilterRepresentation creatFilterFromName(String name) { 715 if (FilterRotateRepresentation.SERIALIZATION_NAME.equals(name)) { 716 return new FilterRotateRepresentation(); 717 } else if (FilterMirrorRepresentation.SERIALIZATION_NAME.equals(name)) { 718 return new FilterMirrorRepresentation(); 719 } else if (FilterStraightenRepresentation.SERIALIZATION_NAME.equals(name)) { 720 return new FilterStraightenRepresentation(); 721 } else if (FilterCropRepresentation.SERIALIZATION_NAME.equals(name)) { 722 return new FilterCropRepresentation(); 723 } 724 FiltersManager filtersManager = FiltersManager.getManager(); 725 return filtersManager.createFilterFromName(name); 726 } 727 728 public void updateWith(ImagePreset preset) { 729 if (preset.mFilters.size() != mFilters.size()) { 730 Log.e(LOGTAG, "Updating a preset with an incompatible one"); 731 return; 732 } 733 for (int i = 0; i < mFilters.size(); i++) { 734 FilterRepresentation destRepresentation = mFilters.elementAt(i); 735 FilterRepresentation sourceRepresentation = preset.mFilters.elementAt(i); 736 destRepresentation.useParametersFrom(sourceRepresentation); 737 } 738 } 739 } 740