Skip to content

Commit

Permalink
Update predominant color (#247)
Browse files Browse the repository at this point in the history
* Update predominant color
  • Loading branch information
strausr authored Jan 29, 2020
1 parent c620adb commit d1a2b7f
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 89 deletions.
84 changes: 25 additions & 59 deletions src/cloudinary-image.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -770,10 +770,10 @@ describe('CloudinaryImage', () => {
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('image/upload/c_fit,w_30/e_pixelate,f_auto,q_1/bear'));
}));
});
describe('placeholder type solid', () => {
describe('placeholder type predominant-color with exact dimensions', () => {
@Component({
template: `<cl-image public-id="bear" width="300" crop="fit">
<cl-placeholder type="solid"></cl-placeholder>
template: `<cl-image public-id="bear" width="300" height="300" crop="fit">
<cl-placeholder type="predominant-color"></cl-placeholder>
</cl-image>`
})
class TestComponent {}
Expand All @@ -791,18 +791,18 @@ describe('CloudinaryImage', () => {
fixture.detectChanges(); // initial binding
des = fixture.debugElement.queryAll(By.directive(CloudinaryPlaceHolder));
});
it('creates an img element with placeholder', fakeAsync(() => {
it('creates an img element with placeholder size 1 pxl', fakeAsync(() => {
tick();
fixture.detectChanges();
const img = des[0].children[0].nativeElement as HTMLImageElement;
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('image/upload/c_fit,w_30/ar_1,b_auto,' +
'c_pad,w_iw_div_2/c_crop,g_north_east,h_10,w_10/c_fill,h_ih,w_iw/f_auto,q_auto/bear'));
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('image/upload/c_fit,h_30,w_30/ar_1,b_auto,' +
'c_pad,w_iw_div_2/c_crop,g_north_east,h_1,w_1/f_auto,q_auto/bear'));
}));
});
describe('placeholder type vectorize', () => {
describe('placeholder type predominant-color', () => {
@Component({
template: `<cl-image public-id="bear" width="300" crop="fit">
<cl-placeholder type="vectorize"></cl-placeholder>
<cl-placeholder type="predominant-color"></cl-placeholder>
</cl-image>`
})
class TestComponent {}
Expand All @@ -824,14 +824,14 @@ describe('CloudinaryImage', () => {
tick();
fixture.detectChanges();
const img = des[0].children[0].nativeElement as HTMLImageElement;
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('image/upload/c_fit,w_30/e_vectorize,q_1/bear'));
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('image/upload/c_fit,w_30/ar_1,b_auto,' +
'c_pad,w_iw_div_2/c_crop,g_north_east,h_10,w_10/c_fill,h_ih,w_iw/f_auto,q_auto/bear'));
}));
});
describe('placeholder with cl-transformation', () => {
describe('placeholder type vectorize', () => {
@Component({
template: `<cl-image public-id="bear" width="300" crop="fit">
<cl-transformation effect="sepia"></cl-transformation>
<cl-placeholder type="blur"></cl-placeholder>
<cl-placeholder type="vectorize"></cl-placeholder>
</cl-image>`
})
class TestComponent {}
Expand All @@ -845,58 +845,22 @@ describe('CloudinaryImage', () => {
declarations: [CloudinaryTransformationDirective, CloudinaryImage, TestComponent, CloudinaryPlaceHolder],
providers: [{ provide: Cloudinary, useValue: testLocalCloudinary }]
}).createComponent(TestComponent);

fixture.detectChanges(); // initial binding
des = fixture.debugElement.queryAll(By.directive(CloudinaryPlaceHolder));
});
it('creates an img element with placeholder and cl-transformations', fakeAsync(() => {
it('creates an img element with placeholder', fakeAsync(() => {
tick();
fixture.detectChanges();
const img = des[0].children[0].nativeElement as HTMLImageElement;
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('e_sepia/c_fit,w_30/e_blur:2000,f_auto,q_1/bear'));
}));
});
describe('cl-image with acessibility modes', () => {
@Component({
template: `<cl-image public-id="bear" accessibility="darkmode"></cl-image>
<cl-image public-id="bear" accessibility="monochrome"></cl-image>
<cl-image public-id="bear" accessibility="brightmode"></cl-image>
<cl-image public-id="bear" accessibility="colorblind"></cl-image>`
})
class TestComponent {}

let fixture: ComponentFixture<TestComponent>;
let des: DebugElement[]; // the elements w/ the directive
let testLocalCloudinary: Cloudinary = new Cloudinary(require('cloudinary-core'),
{ cloud_name: '@@fake_angular2_sdk@@', client_hints: true } as CloudinaryConfiguration);
beforeEach(() => {
fixture = TestBed.configureTestingModule({
declarations: [CloudinaryTransformationDirective, CloudinaryImage, TestComponent],
providers: [{ provide: Cloudinary, useValue: testLocalCloudinary }]
}).createComponent(TestComponent);
fixture.detectChanges(); // initial binding
des = fixture.debugElement.queryAll(By.directive(CloudinaryImage));
});
it('creates an img element with accessibility darkmode', fakeAsync(() => {
const img = des[0].children[0].nativeElement as HTMLImageElement;
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('e_tint:75:black/bear'));
}));
it('creates an img element with accessibility monochrome', fakeAsync(() => {
const img = des[1].children[0].nativeElement as HTMLImageElement;
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('e_grayscale/bear'));
}));
it('creates an img element with accessibility brightmode', fakeAsync(() => {
const img = des[2].children[0].nativeElement as HTMLImageElement;
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('e_tint:50:white/bear'));
}));
it('creates an img element with accessibility colorblind', fakeAsync(() => {
const img = des[3].children[0].nativeElement as HTMLImageElement;
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('e_assist_colorblind/bear'));
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('image/upload/c_fit,w_30/e_vectorize,q_1/bear'));
}));
});
describe('cl-image with acessibility modes and transformation', () => {
describe('placeholder with cl-transformation', () => {
@Component({
template: `<cl-image public-id="bear" accessibility="darkmode" effect="grayscale" overlay="sample">
<cl-transformation effect="sepia"></cl-transformation>
template: `<cl-image public-id="bear" width="300" crop="fit">
<cl-transformation effect="sepia"></cl-transformation>
<cl-placeholder type="blur"></cl-placeholder>
</cl-image>`
})
class TestComponent {}
Expand All @@ -907,15 +871,17 @@ describe('CloudinaryImage', () => {
{ cloud_name: '@@fake_angular2_sdk@@', client_hints: true } as CloudinaryConfiguration);
beforeEach(() => {
fixture = TestBed.configureTestingModule({
declarations: [CloudinaryTransformationDirective, CloudinaryImage, TestComponent],
declarations: [CloudinaryTransformationDirective, CloudinaryImage, TestComponent, CloudinaryPlaceHolder],
providers: [{ provide: Cloudinary, useValue: testLocalCloudinary }]
}).createComponent(TestComponent);
fixture.detectChanges(); // initial binding
des = fixture.debugElement.queryAll(By.directive(CloudinaryImage));
des = fixture.debugElement.queryAll(By.directive(CloudinaryPlaceHolder));
});
it('creates an img element with accessibility darkmode without overwriting effect', fakeAsync(() => {
it('creates an img element with placeholder and cl-transformations', fakeAsync(() => {
tick();
fixture.detectChanges();
const img = des[0].children[0].nativeElement as HTMLImageElement;
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('e_sepia/e_grayscale,l_sample/e_tint:75:black/bear'));
expect(img.attributes.getNamedItem('src').value).toEqual(jasmine.stringMatching('e_sepia/c_fit,w_30/e_blur:2000,f_auto,q_1/bear'));
}));
});
});
13 changes: 1 addition & 12 deletions src/cloudinary-image.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { Cloudinary } from './cloudinary.service';
import { CloudinaryTransformationDirective } from './cloudinary-transformation.directive';
import { CloudinaryPlaceHolder } from './cloudinary-placeholder.component';
import { isBrowser } from './cloudinary.service';
import { accessibilityEffect } from './constants';

@Component({
selector: 'cl-image',
Expand All @@ -34,7 +33,6 @@ export class CloudinaryImage
@Input('loading') loading: string;
@Input('width') width?: string;
@Input('height') height?: string;
@Input('accessibility') accessibility?: string;

@ContentChildren(CloudinaryTransformationDirective)
transformations: QueryList<CloudinaryTransformationDirective>;
Expand All @@ -45,7 +43,6 @@ export class CloudinaryImage

observer: MutationObserver;
shouldShowPlaceHolder: boolean = true;
options: object = {};

constructor(private el: ElementRef, private cloudinary: Cloudinary) {}

Expand Down Expand Up @@ -125,10 +122,6 @@ export class CloudinaryImage
if (this.placeholderComponent) {
this.placeholderHandler(options);
}
if (this.accessibility) {
this.options = options;
options.src = this.accessibilityModeHandler();
}
const imageTag = this.cloudinary.imageTag(this.publicId, options);

this.setElementAttributes(image, imageTag.attributes());
Expand All @@ -149,13 +142,9 @@ export class CloudinaryImage
const placeholderOptions = {};

Object.keys(options).forEach(name => {
placeholderOptions[name] = (name === 'width' && !options[name].startsWith('auto') || name === 'height') ? Math.floor(parseInt(options[name], 10) * 0.1) : options[name];
placeholderOptions[name] = (name === 'width' && !options[name].startsWith('auto') || name === 'height') ? Math.ceil(parseInt(options[name], 10) * 0.1) : options[name];
})
this.placeholderComponent.options = placeholderOptions;
}

accessibilityModeHandler() {
return this.cloudinary.url(this.publicId, {transformation: [this.options, accessibilityEffect[this.accessibility]]});
}
}

17 changes: 5 additions & 12 deletions src/cloudinary-placeholder.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Input,
} from '@angular/core';
import {Cloudinary} from './cloudinary.service';

import { placeholderImageOptions, predominantColorTransformPxl } from './constants';

@Component({
selector: 'cl-placeholder',
Expand Down Expand Up @@ -40,17 +40,10 @@ export class CloudinaryPlaceHolder implements AfterContentChecked {
}

getPlaceholderImage() {
const placeholderImageOptions = {
'vectorize': {effect: 'vectorize', quality: 1},
'pixelate': {effect: 'pixelate', quality: 1, fetch_format: 'auto'},
'blur': {effect: 'blur:2000', quality: 1, fetch_format: 'auto'},
'solid': [
{width: 'iw_div_2', aspect_ratio: 1, crop: 'pad', background: 'auto'},
{crop: 'crop', width: 10, height: 10, gravity: 'north_east'},
{width: 'iw', height: 'ih', crop: 'fill'},
{fetch_format: 'auto', quality: 'auto'}]
if (this.type === 'predominant-color' && this.itemHeight && this.itemWidth) {
return this.cloudinary.url(this.publicId, {transformation: [this.options, ...predominantColorTransformPxl]});
} else {
return this.cloudinary.url(this.publicId, {transformation: [this.options, ...placeholderImageOptions[this.type] || placeholderImageOptions['blur']]})
}
let transformation = [].concat.apply([], [this.options, placeholderImageOptions[this.type] || placeholderImageOptions['blur']]);
return this.cloudinary.url(this.publicId, {transformation: transformation});
}
}
23 changes: 17 additions & 6 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
export const accessibilityEffect = {
'darkmode': {effect: 'tint:75:black'},
'brightmode': {effect: 'tint:50:white'},
'monochrome': {effect: 'grayscale'},
'colorblind': {effect: 'assist_colorblind'}
}
export const predominantColorTransformPxl = [
{width: 'iw_div_2', aspect_ratio: 1, crop: 'pad', background: 'auto'},
{crop: 'crop', width: 1, height: 1, gravity: 'north_east'},
{fetch_format: 'auto', quality: 'auto'}];

export const predominantColorTransform = [
{width: 'iw_div_2', aspect_ratio: 1, crop: 'pad', background: 'auto'},
{crop: 'crop', width: 10, height: 10, gravity: 'north_east'},
{width: 'iw', height: 'ih', crop: 'fill'},
{fetch_format: 'auto', quality: 'auto'}];

export const placeholderImageOptions = {
'vectorize': {effect: 'vectorize', quality: 1},
'pixelate': {effect: 'pixelate', quality: 1, fetch_format: 'auto'},
'blur': {effect: 'blur:2000', quality: 1, fetch_format: 'auto'},
'predominant-color': predominantColorTransform
};

0 comments on commit d1a2b7f

Please sign in to comment.